Kode / Kha

Ultra-portable, high performance, open source multimedia framework.
http://kha.tech
zlib License
1.49k stars 170 forks source link

window/canvas resizing #94

Closed wighawag closed 2 years ago

wighawag commented 9 years ago

I have been looking at the html5 backend mostly but this should apply to the other backends

I am used to have my game resize based on the browser window size ( I want my game to be full screen by default on mobile and desktop) Unfortunately Kha currently set the size of the canvas as the beginning and do not touch it afterward.

I also noticed Kha use canvas.width/height instead of canvas.clientWidth/clientHeight or even better gl.drawingBufferWidth/drawingBufferHeight to get the size of the gl canvas.

While this work when the canvas do not change, it fail when it does.

see some explanation here : http://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html

Any plan to support window resizing ?

RafaelOliveira commented 9 years ago

I'm working on html5 game that adjust the canvas when game starts to use all the window size. http://sudoestegames.com/play/tower/ It is specially made for mobile, but it's ok for desktop too. I was waiting to finish the game to see specifically what need to change in Kha. This is the things that I needed to do (until now):

Main.hx: Change the canvas before start Kha

public static function main() 
{
    #if js
    var canvas = cast(js.Browser.document.getElementById('khanvas'), js.html.CanvasElement);
    canvas.width = js.Browser.window.innerWidth;
    canvas.height = js.Browser.window.innerHeight;      
    #end

    var starter = new Starter();
    starter.start(new Tower());
} 

kha.Loader.hx: Change width/height of the parsed project to use window.innerWidth/Heigth

private function parseProject() : Dynamic {
    #if js
    var proj = Json.parse(getBlob("project.kha").toString());
    proj.game.width = js.Browser.window.innerWidth;
    proj.game.height = js.Browser.window.innerHeight;
    return proj;
    #else
    return Json.parse(getBlob("project.kha").toString());
    #end
}

This was just to make things to work, but can be translated to a better code, using a option in project.kha as discussed in the irc chat.

There is another thing I didn't touch yet, is about the orientation. Mobile browsers don't lock the orientation, so when the orientation is changed the canvas need to be adjusted to match the new size. And we need a function to be overrided, where we resize the game and adjust the position of the elements of the game.

wighawag commented 9 years ago

That's cool it does not support resize as the player resize the browser though. Also since I want to use kha for its cross platform support, I want it to work the same across targets I think there should be an option in Kha to tell Kha that window/canvas size is manual (including viewport (see https://github.com/KTXSoftware/Kha/issues/85) and there should be a way to get resize events.
I ll think I ll do some thing like you did in the mean time. Thanks

wighawag commented 9 years ago

Actually I do not really mind the events as if I can get the current window/canvas size I can handle the rest on a frame basis. The main thing for me is the ability to control canvas size and that Kha handle such resize For example let say I want a game embedded in my own html page (maybe I want full screen but maybe I want it to be 80% wide (or with a margin of 50 px) to allow some UI arround. I can do it via css but currently Kha will not resize the canvas to match canvas.clientWidth/clientHeight (see http://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html)

RobDangerous commented 9 years ago

Does it make any sense to resize the canvas element using css? When you don't do that you can use Kha's render to texture features to resize everything in a portable way.

wighawag commented 9 years ago

It is not that I plan to use css to explictely resize the canvas element but more that if my game is embeded in a html page, and the canvas is relative to the window size (whether it is by the use of css or other) the game canvas should be resized appropriately (to match canvas.clientWidth/canvas.clientHeight). One way to think about it is that the canvas is the equivalent of a window in a desktop os (and not the browser window) (it is actually like this in Kha right now) and that any resizing to the canvas (from css or not) should be handled properly.

Not sure if I am clear :P

RobDangerous commented 9 years ago

So just ala if (canvas.style.width != canvas.width) canvas.width = canvas.style.width?

wighawag commented 9 years ago

yes but instead of canvas.style.width (which is dependent on the css) you can use canvas.clientWidth which will work for every case

also for hdpi device you could increase the size to give game a more high definition but there should probably be a setting to not scale too much for these device

from the link mentioned above :

function resize(gl) {
  var realToCSSPixels = window.devicePixelRatio || 1; //There could be a setting to cap the scale so to not scale too much (as it require to draw more pixels)

  var displayWidth  = Math.floor(gl.canvas.clientWidth  * realToCSSPixels);
  var displayHeight = Math.floor(gl.canvas.clientHeight * realToCSSPixels);

  if (gl.canvas.width  != displayWidth || gl.canvas.height != displayHeight) {
    gl.canvas.width  = displayWidth;
    gl.canvas.height = displayHeight;
  }
}
RafaelOliveira commented 9 years ago

Html5 games can appear in many ways in a page, so I think the best way is just implement the glViewPort, and let the rest be managed by the programmer. It's best to just give the tools and we create libs that fits in each use case. I'm already trying to do this for html5 mobile. And another thing, Loader.hx should get width/height from the canvas, not from the project.kha, because the values can be changed. And about the resizing event, we can setup using haxe with js.Browser.window.onresize.

I just don't know if there is some side effect in kha if we change the viewport size manually.

wighawag commented 9 years ago

I agree about the viewport thing, I wanted to make a pull request but did not have time to look into it yet as I can use kha.Sys.gl.viewport on the html5 target and get what I want for now. there is an issue for that : https://github.com/KTXSoftware/Kha/issues/85

Indeed Loader.width/height should probably reflect the canvas size. At the same time, do we really need the Loader to have these property. Since kha.Framebuffer already have these

Regarding js.Browser.window.onresize, this will not be sufficient since the canvas can be resized for many reason, some not including a resize of the window. a check on every frame like used in commit : https://github.com/KTXSoftware/Kha/commit/62db76a6df764f09da20ab87a630fd821d6c56cf do the trick

In my opinion, Kha game should take place in the canvas. The canvas should be the equivalent of a window for native game. Kha does not need to be aware of the browser window. This way the website including the game have complete freedom of how the game is displayed. This is actually how Kha handle it currently, even though its default template use fixed width/height for the template. This can be overridden by modifying the file at build/html5/index.html I also created a pull request to allow specifying your own template (https://github.com/KTXSoftware/khamake/pull/5) but this is still in review

By using the template at : https://github.com/wighawag/khamake/blob/allow_own_template/Data/html5/fullWindow.html you can for example have a full window game (usefull for mobile) Then you can use viewport to keep the ratio of the game. I am working currently on a library to handle that automatically

Hope it helps

RblSb commented 7 years ago

Full code without edits in kha to made fullwindow canvas: https://github.com/Kode/Kha/wiki/HTML5#full-page-canvas Or make a check on width / height in System.init and if they are zero, then execute about that kind of code in it. Robert, what do you think about creating a resize event, although it is only needed for flash / html5?