diff --git a/Frontend/implementations/EpicGames/src/assets/css/showcase.css b/Frontend/implementations/EpicGames/src/assets/css/showcase.css new file mode 100644 index 00000000..cc7d5119 --- /dev/null +++ b/Frontend/implementations/EpicGames/src/assets/css/showcase.css @@ -0,0 +1,201 @@ + +:root { + --democolor0: rgba(15, 15, 15, 1); + --democolor1: #000000; + --democolor2: #FFFFFF; + --democolor3: #0585fe; + --democolor4: rgba(26, 26, 26, 1); + --democolor5: rgba(36, 36, 36, 1); + --democolor6: rgba(53, 53, 53, 1); + --democolor7: rgba(180, 180, 180, 1); +} + +body { + margin: 0px; + padding: 0px; + height: 100vh; + width: 100vw; + background-color: var(--democolor5); + font-family: verdana,sans-serif; + color: var(--democolor7); +} + +code { + background-color: var(--democolor6); +} + +.wrapper { + display: flex; + align-items: stretch; + height: 100%; + width: 100%; +} + +.spaced-row { + display: flex; + flex-direction: row; + justify-content: space-evenly; +} + +#infocontainer { + padding: 0.5em; + font-size: large; + min-height: 15vh; + max-height: 15vh; + display: flex; + flex-direction: column; + justify-content: flex-start; +} + +#infoinstructions { + background-color: var(--democolor4); + padding: 0.5em; + font-size: medium; + flex-grow: 1; + overflow-y: auto; +} + +#content { + width: 100%; + flex-direction: column; + display: flex; + align-items: initial; + justify-content: center; +} + +#exampletitle { + padding: 1em; + display: flex; + flex-direction: column; + justify-content: center; + align-items: baseline; +} + +#sidebar { + min-width: 250px; + max-width: 250px; + background-color: var(--democolor4); + transition: all 0.3s; + font-size: small; + border-color: var(--democolor4); + border-style: solid; + border-width: 0.33em 0.33em 0em 0em; + align-content: flex-start; + display: flex; + flex-direction: column; +} + +#sidebar-tab-header { + width: 100%; +} + +#sidebar-header { + padding: 0.25rem 2rem 0.25rem 0.5rem; + background-color: var(--democolor5); + border-top: 1px solid var(--democolor3); + border-radius: 5px 5px 0px 0px; + margin-left: 1em; + width: -moz-fit-content; + width: fit-content; +} + +#sidebarContent { + max-height:100%; + overflow-y:auto; + background-color: var(--democolor5); + flex-grow: 1; + padding-left: 1em; + padding-right: 1em; +} + +#sidebar-example-selector { + background-color: var(--democolor5); + padding-top: 1em; + padding-bottom: 1em; + padding-left: 1em; +} + +#psdemotext { + font-size: large; +} + +#playercontainer { + background-color: var(--democolor0); + flex-grow: 1; + font-family: 'Montserrat', sans-serif; +} + +select { + font-size: large; + padding: 0.5em; + color: var(--democolor7); + background-color: var(--democolor0); + border: 2px solid var(--democolor6); + outline: none !important; + border-radius: 5px; +} + +select:hover { + color: var(--democolor2); +} + +a, a:hover, a:focus { + color: inherit; + text-decoration: none; + transition: all 0.3s; +} + +#sidebar ul.components { + padding: 20px 0; +} + +#sidebar ul p { + color: #fff; + padding: 10px; +} + +#sidebar ul li a { + padding: 10px; + font-size: 1.1em; + display: block; +} +#sidebar ul li a:hover { + color: #7386D5; + background: #fff; +} + +#sidebar ul li.active > a, a[aria-expanded="true"] { + color: #fff; + background: #212f44; + /*#f90;*/ +} +ul ul a { + font-size: 0.9em !important; + padding-left: 30px !important; + background: #354b6d; +} + +a[data-toggle="collapse"] { + position: relative; +} + +.dropdown-toggle::after { + display: block; + position: absolute; + top: 50%; + right: 20px; + transform: translateY(-50%); +} + +.characterBtn { + width: 100%; + cursor: pointer; +} + +.characterBtn:hover { + box-shadow: var(--democolor3) 0px 0px 0px 3px; +} + +.characterBtn:active { + box-shadow: var(--democolor5) 0px 0px 0px 3px; +} \ No newline at end of file diff --git a/Frontend/implementations/EpicGames/src/assets/images/Aurora.jpg b/Frontend/implementations/EpicGames/src/assets/images/Aurora.jpg new file mode 100644 index 00000000..3c7fe700 Binary files /dev/null and b/Frontend/implementations/EpicGames/src/assets/images/Aurora.jpg differ diff --git a/Frontend/implementations/EpicGames/src/assets/images/Crunch.jpg b/Frontend/implementations/EpicGames/src/assets/images/Crunch.jpg new file mode 100644 index 00000000..6984314a Binary files /dev/null and b/Frontend/implementations/EpicGames/src/assets/images/Crunch.jpg differ diff --git a/Frontend/implementations/EpicGames/src/player.ts b/Frontend/implementations/EpicGames/src/player.ts index 08823767..310907f1 100644 --- a/Frontend/implementations/EpicGames/src/player.ts +++ b/Frontend/implementations/EpicGames/src/player.ts @@ -1,24 +1,24 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -import { Config, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2'; -import { Application, PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2'; -const PixelStreamingApplicationStyles = - new PixelStreamingApplicationStyle(); -PixelStreamingApplicationStyles.applyStyleSheet(); - -document.body.onload = function() { - // Example of how to set the logger level - // Logger.SetLoggerVerbosity(10); - - // Create a config object - const config = new Config({ useUrlParams: true }); - - // Create a Native DOM delegate instance that implements the Delegate interface class - const stream = new PixelStreaming(config); - const application = new Application({ - stream, - onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode) - }); - // document.getElementById("centrebox").appendChild(application.rootElement); - document.body.appendChild(application.rootElement); -} +// Copyright Epic Games, Inc. All Rights Reserved. + +import { Config, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2'; +import { Application, PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2'; +const PixelStreamingApplicationStyles = + new PixelStreamingApplicationStyle(); +PixelStreamingApplicationStyles.applyStyleSheet(); + +document.body.onload = function() { + // Example of how to set the logger level + // Logger.SetLoggerVerbosity(10); + + // Create a config object + const config = new Config({ useUrlParams: true }); + + // Create a Native DOM delegate instance that implements the Delegate interface class + const stream = new PixelStreaming(config); + const application = new Application({ + stream, + onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode) + }); + // document.getElementById("centrebox").appendChild(application.rootElement); + document.body.appendChild(application.rootElement); +} diff --git a/Frontend/implementations/EpicGames/src/showcase.html b/Frontend/implementations/EpicGames/src/showcase.html new file mode 100644 index 00000000..ed6142d4 --- /dev/null +++ b/Frontend/implementations/EpicGames/src/showcase.html @@ -0,0 +1,61 @@ + + + +
+Welcome to the Pixel Streaming demo showcase!
+Getting Started
+Example: Sending data to Unreal Engine
+Under the hood these interactions use the WebRTC data channel to send a data payload that we interpret on the UE side and respond to appropriately.
+In particular the function called to send custom data to Unreal Engine from the frontend is:
+pixelstreaming.emitUIInteraction(data: object | string)
+ `;
+
+ const characterSelectElem = document.createElement("div");
+ this._exampleSettingsElem.appendChild(characterSelectElem);
+
+ const sendDataTitle = document.createElement("h2");
+ sendDataTitle.innerText = "Send data: ";
+ characterSelectElem.appendChild(sendDataTitle);
+
+ const characterSelectTitle = document.createElement("p");
+ characterSelectTitle.innerText = "Select a character: ";
+ characterSelectElem.appendChild(characterSelectTitle);
+
+ // Make Aurora character
+ const auroraElem = document.createElement("div");
+ characterSelectElem.appendChild(auroraElem);
+ const auroraImg = document.createElement("img");
+ auroraImg.classList.add("characterBtn");
+ auroraImg.src = "./images/Aurora.jpg";
+ auroraImg.onclick = () => { this._onCharacterClicked("Aurora"); }
+ auroraElem.appendChild(auroraImg);
+
+ // Make Crunch character
+ const crunchElem = document.createElement("div");
+ characterSelectElem.appendChild(crunchElem);
+ const crunchImg = document.createElement("img");
+ crunchImg.classList.add("characterBtn");
+ crunchImg.src = "./images/Crunch.jpg";
+ crunchImg.onclick = () => { this._onCharacterClicked("Crunch"); }
+ crunchElem.appendChild(crunchImg);
+
+ // Make skin selection title
+ const skinSelectTitle = document.createElement("p");
+ skinSelectTitle.innerText = "Select a skin: ";
+ this._exampleSettingsElem.appendChild(skinSelectTitle);
+
+ // Make skin selection
+ const skinSelectElem = document.createElement("div");
+ skinSelectElem.classList.add("spaced-row");
+ this._exampleSettingsElem.appendChild(skinSelectElem);
+
+ // Make skin selection buttons
+
+ // Skin1
+ const skin1Btn = document.createElement("button");
+ skin1Btn.classList.add("btn-flat");
+ skin1Btn.onclick = () => { this._onSkinClicked(0); }
+ skin1Btn.innerText = "Skin 1";
+ skinSelectElem.appendChild(skin1Btn);
+
+ // Skin2
+ const skin2Btn = document.createElement("button");
+ skin2Btn.classList.add("btn-flat");
+ skin2Btn.onclick = () => { this._onSkinClicked(1); }
+ skin2Btn.innerText = "Skin 2";
+ skinSelectElem.appendChild(skin2Btn);
+
+ // Skin3
+ const skin3Btn = document.createElement("button");
+ skin3Btn.classList.add("btn-flat");
+ skin3Btn.onclick = () => { this._onSkinClicked(2); }
+ skin3Btn.innerText = "Skin 3";
+ skinSelectElem.appendChild(skin3Btn);
+ }
+
+ private _createUECommandExample() {
+
+ this._infoElem.innerHTML =
+ `
+ Example: Triggering Commands in Unreal Engine
+-windowed
application).Under the hood these interactions use the WebRTC data channel to send command messages that we interpret on the UE side to call specific UE functions.
+There are a very select set of built-in commands such as changing resolution and change encoder QP, which can be triggered like so:
+pixelStreaming.emitCommand({"Encoder.MinQP": 51,})
+
+ However, you can bind your own custom commands in C++ using:
+
+ // C++ side
+
+ IPixelStreamingInputHandler::SetCommandHandler(const FString& CommandName, const TFunction& Handler)
+
+ // JS side
+
+ pixelstreaming.emitCommand({"MyCustomCommand": "MyCustomCommandParameter"});
+
+
+ Additionally you can also trigger Unreal Engine console commands like stat gpu
if you launch Pixel Streaming with -AllowPixelStreamingCommands
then calling:
pixelstreaming.emitConsoleCommand(command: string)
+ `;
+
+ // Add a new element for containing elements for res changing feature
+ const changeResElem = document.createElement("div");
+ this._exampleSettingsElem.appendChild(changeResElem);
+
+ // Make res change title
+ const changeResTitle = document.createElement("h2");
+ changeResTitle.innerText = "Send a custom command: ";
+ changeResElem.appendChild(changeResTitle);
+
+ // Make change resolution text
+ const changeResText = document.createElement("p");
+ changeResText.innerHTML = "Change resolution"
+ changeResElem.appendChild(changeResText);
+
+ // Make res change button container
+ const changeResBtnContainer = document.createElement("div");
+ changeResBtnContainer.classList.add("spaced-row");
+ this._exampleSettingsElem.appendChild(changeResBtnContainer);
+
+ // Make res change buttons
+
+ // 720p
+ const res720pBtn = document.createElement("button");
+ res720pBtn.classList.add("btn-flat");
+ res720pBtn.onclick = () => { this._onResClicked(1280, 720); }
+ res720pBtn.innerText = "720p";
+ changeResBtnContainer.appendChild(res720pBtn);
+
+ // 1080p
+ const res1080pBtn = document.createElement("button");
+ res1080pBtn.classList.add("btn-flat");
+ res1080pBtn.onclick = () => { this._onResClicked(1920, 1080); }
+ res1080pBtn.innerText = "1080p";
+ changeResBtnContainer.appendChild(res1080pBtn);
+
+ // 1440p
+ const res1440pBtn = document.createElement("button");
+ res1440pBtn.classList.add("btn-flat");
+ res1440pBtn.onclick = () => { this._onResClicked(2560, 1440); }
+ res1440pBtn.innerText = "1440p";
+ changeResBtnContainer.appendChild(res1440pBtn);
+
+ // 4k
+ const res4kBtn = document.createElement("button");
+ res4kBtn.classList.add("btn-flat");
+ res4kBtn.onclick = () => { this._onResClicked(3840, 2160); }
+ res4kBtn.innerText = "4k";
+ changeResBtnContainer.appendChild(res4kBtn);
+
+ // Add a new element for containing elements for res changing feature
+ const consoleCommandElem = document.createElement("div");
+ this._exampleSettingsElem.appendChild(consoleCommandElem);
+
+ // Make console command title
+ const consoleCommandTitle = document.createElement("h2");
+ consoleCommandTitle.innerText = "Send a console command: ";
+ consoleCommandElem.appendChild(consoleCommandTitle);
+
+ // Text informing using about -AllowPixelStreamingCommands
+ const informPSCommandsText = document.createElement("p");
+ informPSCommandsText.innerHTML = "(Requires UE side launched with -AllowPixelStreamingCommands
)"
+ consoleCommandElem.appendChild(informPSCommandsText);
+
+ // Make buttons for stat fps/stat gpu
+ const consoleCmdBtnsContainer = document.createElement("div");
+ consoleCmdBtnsContainer.classList.add("spaced-row");
+ this._exampleSettingsElem.appendChild(consoleCmdBtnsContainer);
+
+ // stat fps
+ const statfpsBtn = document.createElement("button");
+ statfpsBtn.classList.add("btn-flat");
+ statfpsBtn.onclick = () => { this._pixelStreaming.emitConsoleCommand("stat fps"); }
+ statfpsBtn.innerText = "stat fps";
+ consoleCmdBtnsContainer.appendChild(statfpsBtn);
+
+ // stat pixelstreaming
+ const statgpuBtn = document.createElement("button");
+ statgpuBtn.classList.add("btn-flat");
+ statgpuBtn.onclick = () => { this._pixelStreaming.emitConsoleCommand("stat pixelstreaming"); }
+ statgpuBtn.innerText = "stat pixelstreaming";
+ consoleCmdBtnsContainer.appendChild(statgpuBtn);
+
+ }
+
+}
+
+
diff --git a/Frontend/implementations/EpicGames/webpack.common.js b/Frontend/implementations/EpicGames/webpack.common.js
index 0af7cf62..d5d0e0fe 100644
--- a/Frontend/implementations/EpicGames/webpack.common.js
+++ b/Frontend/implementations/EpicGames/webpack.common.js
@@ -44,12 +44,12 @@ module.exports = {
}
},
{
- test: /\.(png|svg)$/i,
+ test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name][ext]'
}
- },
+ }
],
},
resolve: {