emscripten: redesign shell, always use whole window for game canvas
This commit is contained in:
parent
e3ff572d90
commit
021584a83b
4 changed files with 156 additions and 80 deletions
5
emscripten/postamble.js
Normal file
5
emscripten/postamble.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
ENV["TAISEI_NOASYNC"] = "1";
|
||||
ENV["TAISEI_NOUNLOAD"] = "1";
|
||||
ENV["TAISEI_PREFER_SDL_VIDEODRIVERS"] = "emscripten";
|
||||
ENV["TAISEI_RENDERER"] = "gles30";
|
|
@ -47,6 +47,7 @@
|
|||
color: #eeeeee;
|
||||
overflow: overlay;
|
||||
margin: 0px;
|
||||
text-shadow: 2px 2px black;
|
||||
}
|
||||
|
||||
div.emscripten {
|
||||
|
@ -62,32 +63,67 @@
|
|||
}
|
||||
|
||||
div.header {
|
||||
padding: 0px 16px;
|
||||
padding: 10vh 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
bottom: 0;
|
||||
padding-bottom: 16px;
|
||||
width: 100%;
|
||||
transition: all 0.25s ease-in-out;
|
||||
}
|
||||
|
||||
div.centered {
|
||||
position: absolute;
|
||||
bottom: 50%;
|
||||
div.footer.backdrop {
|
||||
background-color: #000000C0;
|
||||
}
|
||||
|
||||
div.footer.hidden {
|
||||
opacity: 0.0;
|
||||
background-color: #00000000;
|
||||
}
|
||||
|
||||
div.footer.hidden:hover {
|
||||
opacity: 1.0;
|
||||
background-color: #000000C0;
|
||||
}
|
||||
|
||||
div#infoContainer {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(50%);
|
||||
transform: translateY(-50%);
|
||||
background-color: #000000C0;
|
||||
padding: 16px 0px;
|
||||
z-index: 1;
|
||||
transition: all 0.25s ease-in-out;
|
||||
}
|
||||
|
||||
div#infoContainer.top {
|
||||
top: 0%;
|
||||
transform: translateY(0%);
|
||||
background-color: #00000000;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
div#infoContainer.top:hover {
|
||||
top: 0%;
|
||||
transform: translateY(0%);
|
||||
background-color: #000000C0;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
|
||||
canvas.emscripten {
|
||||
border: 0px none;
|
||||
background-color: none;
|
||||
position: fixed;
|
||||
display: block;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#spinner {
|
||||
|
@ -105,10 +141,9 @@
|
|||
}
|
||||
|
||||
#logToggleContainer {
|
||||
display: /* inline-block */ none;
|
||||
display: none;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
transform: translateX(25%);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
|
@ -184,18 +219,11 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1 style="z-index: -10;"></canvas>
|
||||
<div class="header">
|
||||
<h3>Note: this web port is experimental and may not perform as well as the original game, which you can <a href="https://taisei-project.org/download">download here</a>.</h3>
|
||||
</div>
|
||||
<div class="centered">
|
||||
<div class="spinner" id="spinner"><img src="scythe.webp" class="spinner"/></div>
|
||||
<div class="emscripten" id="status">Girls are now downloading, please wait warmly…</div>
|
||||
<div class="emscripten">
|
||||
<progress value="0" max="100" id="progress" ></progress>
|
||||
</div>
|
||||
<div class="emscripten_border" id="canvasContainer" hidden>
|
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
|
||||
<h3 id="warning">WARNING: This game is not designed to run in a browser.<br/><a href="https://taisei-project.org/download">Download</a> the desktop version for a smoother experience.</h3>
|
||||
</div>
|
||||
<div id="infoContainer">
|
||||
<div id="logToggleContainer" hidden>
|
||||
<input type="checkbox" name="logToggle" id="logToggle" onclick="toggleLog()"/>
|
||||
<label for="logToggle"> Show log</label>
|
||||
|
@ -203,13 +231,18 @@
|
|||
<div id="logContainer" hidden>
|
||||
<textarea class="emscripten" id="output" rows="12" readonly></textarea>
|
||||
</div>
|
||||
<div class="spinner" id="spinner"><img src="scythe.webp" class="spinner"/></div>
|
||||
<div class="emscripten" id="status">Girls are now downloading, please wait warmly…</div>
|
||||
<div class="emscripten">
|
||||
<progress value="0" max="100" id="progress" ></progress>
|
||||
</div>
|
||||
<div class="footer">
|
||||
</div>
|
||||
<div id="footer" class="footer">
|
||||
<a href="https://taisei-project.org/">Taisei Project</a> ·
|
||||
<a href="https://taisei-project.org/code">Source code</a> ·
|
||||
<a href="https://taisei-project.org/discord">Discord</a>
|
||||
<br/>
|
||||
Powered by <a href="https://emscripten.org/">Emscripten</a>
|
||||
Web port powered by <a href="https://emscripten.org/">Emscripten</a>
|
||||
</div>
|
||||
<!--<script type="text/javascript" src="webgl-debug.js"></script>-->
|
||||
<script type="application/javascript">
|
||||
|
@ -219,7 +252,8 @@
|
|||
var progressElement = E('progress');
|
||||
var spinnerElement = E('spinner');
|
||||
var canvasElement = E('canvas');
|
||||
var canvasContainerElement = E('canvasContainer');
|
||||
var infoContainerElement = E('infoContainer');
|
||||
var footerElement = E('footer');
|
||||
var logToggleElement = E('logToggle');
|
||||
var logToggleContainerElement = E('logToggleContainer');
|
||||
var logContainerElement = E('logContainer');
|
||||
|
@ -256,9 +290,7 @@
|
|||
};
|
||||
})();
|
||||
|
||||
window.onerror = function(error) {
|
||||
setStatus('Error: ' + error);
|
||||
};
|
||||
window.onerror = error => setStatus('Error: ' + error);
|
||||
|
||||
window['toggleLog'] = function toggleLog() {
|
||||
logContainerElement.hidden = !logToggleElement.checked;
|
||||
|
@ -266,13 +298,13 @@
|
|||
}
|
||||
|
||||
var glContext = canvasElement.getContext('webgl2', {
|
||||
'alpha' : false,
|
||||
'antialias' : false,
|
||||
'depth' : false,
|
||||
'powerPreference' : 'high-performance',
|
||||
'premultipliedAlpha' : true,
|
||||
'preserveDrawingBuffer' : false,
|
||||
'stencil' : false,
|
||||
alpha : false,
|
||||
antialias : false,
|
||||
depth : false,
|
||||
powerPreference : 'high-performance',
|
||||
premultipliedAlpha : true,
|
||||
preserveDrawingBuffer : false,
|
||||
stencil : false,
|
||||
});
|
||||
|
||||
if(!glContext) {
|
||||
|
@ -281,36 +313,53 @@
|
|||
|
||||
// glContext = WebGLDebugUtils.makeDebugContext(glContext);
|
||||
|
||||
canvasElement.addEventListener("webglcontextlost", function(e) {
|
||||
canvasElement.addEventListener("webglcontextlost", e => {
|
||||
alert('WebGL context lost. You will need to reload the page.');
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if(event.key === 'F11' || event.key === 'F12') {
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
|
||||
window.onresize = function() {
|
||||
canvasElement.width = canvasElement.offsetWidth;
|
||||
canvasElement.height = canvasElement.offsetHeight;
|
||||
};
|
||||
|
||||
logOutputElement.value = ''; // clear browser cache
|
||||
|
||||
var taisei;
|
||||
taiseiScriptElement.addEventListener('load', async() => {
|
||||
taisei = await createTaisei({
|
||||
'canvas': canvasElement,
|
||||
'preinitializedWebGLContext': glContext,
|
||||
'onFirstFrame': function() {
|
||||
canvasContainerElement.hidden = false;
|
||||
var taisei = {
|
||||
canvas: canvasElement,
|
||||
preinitializedWebGLContext: glContext,
|
||||
onFirstFrame: function() {
|
||||
canvasElement.style.zIndex = "0";
|
||||
logToggleContainerElement.style.display = "inline-block";
|
||||
infoContainerElement.classList.add('top');
|
||||
footerElement.insertBefore(E('warning'), footerElement.childNodes[0]);
|
||||
footerElement.classList.add('backdrop');
|
||||
setTimeout(function() {
|
||||
footerElement.classList.add('hidden');
|
||||
}, 7000);
|
||||
setStatus('', true);
|
||||
},
|
||||
'print': function(text) {
|
||||
print: function(text) {
|
||||
if(arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.log(text);
|
||||
logOutputElement.value += text + "\n";
|
||||
logOutputElement.scrollTop = logOutputElement.scrollHeight; // focus on bottom
|
||||
},
|
||||
'printErr': function(text) {
|
||||
printErr: function(text) {
|
||||
if(arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.error(text);
|
||||
},
|
||||
'setStatus': setStatus,
|
||||
});
|
||||
setStatus: setStatus,
|
||||
};
|
||||
|
||||
taiseiScriptElement.addEventListener('load', async () => {
|
||||
await createTaisei(taisei);
|
||||
taisei.initFilesystem();
|
||||
taisei.callMain();
|
||||
});
|
||||
|
|
|
@ -301,7 +301,7 @@ if host_machine.system() == 'emscripten'
|
|||
'-s', 'EXIT_RUNTIME=0',
|
||||
'-s', 'EXPORT_NAME=createTaisei',
|
||||
'-s', 'EXPORTED_FUNCTIONS=["_main", "_vfs_sync_callback"]',
|
||||
'-s', 'EXPORTED_RUNTIME_METHODS=["ccall","callMain"]',
|
||||
'-s', 'EXPORTED_RUNTIME_METHODS=["ccall","callMain","FS","ENV"]',
|
||||
'-s', 'FETCH_SUPPORT_INDEXEDDB=0',
|
||||
'-s', 'FETCH',
|
||||
'-s', 'FILESYSTEM=1',
|
||||
|
|
58
src/video.c
58
src/video.c
|
@ -186,6 +186,12 @@ static VideoCapabilityState video_query_capability_switch(VideoCapability cap) {
|
|||
static VideoCapabilityState video_query_capability_webcanvas(VideoCapability cap) {
|
||||
switch(cap) {
|
||||
case VIDEO_CAP_EXTERNAL_RESIZE:
|
||||
return VIDEO_ALWAYS_ENABLED;
|
||||
|
||||
case VIDEO_CAP_FULLSCREEN:
|
||||
return VIDEO_NEVER_AVAILABLE;
|
||||
|
||||
case VIDEO_CAP_CHANGE_RESOLUTION:
|
||||
return VIDEO_NEVER_AVAILABLE;
|
||||
|
||||
case VIDEO_CAP_VSYNC_ADAPTIVE:
|
||||
|
@ -498,12 +504,30 @@ static void video_new_window_internal(uint display, uint w, uint h, uint32_t fla
|
|||
video_new_window_internal(display, RESX, RESY, flags & ~SDL_WINDOW_FULLSCREEN_DESKTOP, true);
|
||||
}
|
||||
|
||||
static bool restrict_to_capability(bool enabled, VideoCapability cap) {
|
||||
VideoCapabilityState capval = video_query_capability(cap);
|
||||
|
||||
switch(capval) {
|
||||
case VIDEO_ALWAYS_ENABLED:
|
||||
return true;
|
||||
|
||||
case VIDEO_NEVER_AVAILABLE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
static void video_new_window(uint display, uint w, uint h, bool fs, bool resizable) {
|
||||
uint32_t flags = SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
|
||||
if(fs || video_query_capability(VIDEO_CAP_FULLSCREEN) == VIDEO_ALWAYS_ENABLED) {
|
||||
fs = restrict_to_capability(fs, VIDEO_CAP_FULLSCREEN);
|
||||
resizable = restrict_to_capability(resizable, VIDEO_CAP_EXTERNAL_RESIZE);
|
||||
|
||||
if(fs) {
|
||||
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
} else if(resizable && video.backend != VIDEO_BACKEND_EMSCRIPTEN) {
|
||||
} else if(resizable) {
|
||||
flags |= SDL_WINDOW_RESIZABLE;
|
||||
}
|
||||
|
||||
|
@ -538,7 +562,7 @@ INLINE bool should_recreate_on_size_change(void) {
|
|||
/* Resize failures are impossible to detect under some WMs */
|
||||
video.backend == VIDEO_BACKEND_X11 ||
|
||||
/* Needed to work around various SDL bugs and/or HTML/DOM quirks */
|
||||
video.backend == VIDEO_BACKEND_EMSCRIPTEN ||
|
||||
// video.backend == VIDEO_BACKEND_EMSCRIPTEN ||
|
||||
0);
|
||||
|
||||
return env_get("TAISEI_VIDEO_RECREATE_ON_RESIZE", defaultval);
|
||||
|
@ -553,20 +577,6 @@ INLINE bool should_recreate_on_fullscreen_change(void) {
|
|||
return env_get("TAISEI_VIDEO_RECREATE_ON_FULLSCREEN", defaultval);
|
||||
}
|
||||
|
||||
static bool restrict_to_capability(bool enabled, VideoCapability cap) {
|
||||
VideoCapabilityState capval = video_query_capability(cap);
|
||||
|
||||
switch(capval) {
|
||||
case VIDEO_ALWAYS_ENABLED:
|
||||
return true;
|
||||
|
||||
case VIDEO_NEVER_AVAILABLE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void video_set_mode(uint display, uint w, uint h, bool fs, bool resizable) {
|
||||
fs = restrict_to_capability(fs, VIDEO_CAP_FULLSCREEN);
|
||||
|
@ -585,6 +595,14 @@ void video_set_mode(uint display, uint w, uint h, bool fs, bool resizable) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(
|
||||
!restrict_to_capability(true, VIDEO_CAP_CHANGE_RESOLUTION) &&
|
||||
video.current.width > 0 && video.current.height > 0
|
||||
) {
|
||||
w = video.current.width;
|
||||
h = video.current.height;
|
||||
}
|
||||
|
||||
bool display_changed = display != video_current_display();
|
||||
bool size_changed = w != video.current.width || h != video.current.height;
|
||||
bool fullscreen_changed = video_is_fullscreen() != fs;
|
||||
|
@ -599,7 +617,7 @@ void video_set_mode(uint display, uint w, uint h, bool fs, bool resizable) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(size_changed) {
|
||||
if(size_changed && !fs) {
|
||||
if(!fullscreen_changed && should_recreate_on_size_change()) {
|
||||
video_new_window(display, w, h, fs, resizable);
|
||||
return;
|
||||
|
@ -626,6 +644,10 @@ SDL_Window *video_get_window(void) {
|
|||
}
|
||||
|
||||
void video_set_fullscreen(bool fullscreen) {
|
||||
if(video_query_capability(VIDEO_CAP_FULLSCREEN) != VIDEO_AVAILABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
video_set_mode(
|
||||
SDL_GetWindowDisplayIndex(video.window),
|
||||
video.intended.width,
|
||||
|
|
Loading…
Reference in a new issue