From 2fe6f269a1bb9299d7b7ef4eeb7d65296831392d Mon Sep 17 00:00:00 2001 From: kts Date: Thu, 18 Sep 2014 17:44:29 -0600 Subject: [PATCH] Added an image loader system, wherein files to be loaded notify the display of their status. The status of images can be polled by an App thereafter. Added fairly limited Spritesheet and Sprite Drawables. Added vertical and horizontal centering flags, as well as scale to parent element flags for the display. Some changes may have broken other functionality, but this is likely moot, as CBDL will be rewritten later on. --- CBDL.js | 2 + CBDL_graphics.js | 268 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 246 insertions(+), 24 deletions(-) diff --git a/CBDL.js b/CBDL.js index 3879060..436e741 100644 --- a/CBDL.js +++ b/CBDL.js @@ -72,6 +72,8 @@ CBDL.Includes Object that manages includes for an App. Attempts to load all includes specified by the App, providing they are provided prior to the App's onExecute member function being called. + +TODO: fix on mobile, yoo =============================================================================== */ CBDL.Includes = function(app) { diff --git a/CBDL_graphics.js b/CBDL_graphics.js index 6a64069..ad1a513 100644 --- a/CBDL_graphics.js +++ b/CBDL_graphics.js @@ -7,7 +7,7 @@ CBDL.Graphics = CBDL.Graphics || { version: 0.1, BACKEND: {DIV: 0x00, CANVAS_2D:0x01, WEBGL:0x02}, // FILL sets the initial Display to the width and height of the browser window. Resizing when the window's dimensions change is left to the developer. - VM: {SCALE: 0x01, ABSOLUTE: 0x02, FILL: 0x03}, + VM: {ABSOLUTE: 0x01, SCALE: 0x02, FILL: 0x04, VCENTER: 0x08, HCENTER: 16}, RADIAN: (Math.PI/180), getViewport: function() { var h = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight; @@ -31,6 +31,7 @@ bulk. CBDL.Graphics.BaseDisplay = function(video_mode, target_element) { this.video_mode = video_mode; this.target_element = target_element; + this.loading_elements = []; }; CBDL.Graphics.BaseDisplay.prototype.Init = function() {}; @@ -39,7 +40,26 @@ CBDL.Graphics.BaseDisplay.prototype.setHeight = function() {}; CBDL.Graphics.BaseDisplay.prototype.Fill = function(red, green, blue) {}; CBDL.Graphics.BaseDisplay.prototype.clear = function() {}; CBDL.Graphics.BaseDisplay.prototype.draw = function() {}; - +CBDL.Graphics.BaseDisplay.prototype.getViewport = function() { + if (!this.target_element) return null; + var h = this.target_element.innerHeight || this.target_element.clientHeight; + var w = this.target_element.innerWidth || this.target_element.clientWidth; + return { width : w , height : h } +}; +CBDL.Graphics.BaseDisplay.prototype.checkLoading = function() { + var len = this.loading_elements.length; + for (i = 0; i < len; i++) { + if (this.loading_elements[i].state != 1) { + return i+1; + } + } + return 0; +}; +CBDL.Graphics.BaseDisplay.prototype.addLoading = function(name) { + var load = { name: name, state: 0 }; + this.loading_elements.push(load); + return load; +}; CBDL.Graphics.BaseDisplay.prototype._Drawable_ = function(display, size, scale, rotation) { this.display = display; this.size = size; @@ -67,13 +87,16 @@ CBDL.Graphics.BaseDisplay.prototype._Drawable_.prototype.destroy = function() {} CBDL.Graphics.BaseDisplay.prototype._Image_ = function(display, image, scale, rotation) { this.display = display; this.data = new Image(); + this.image = image; this.size = { width: 1, height: 1 }; - this.data.onload = (function(scope) { + var load_obj = display.addLoading(image); + this.data.onload = (function(scope, load_obj) { return function() { scope.size.width = this.width; scope.size.height = this.height; + load_obj.state = 1; } - })(this); + })(this, load_obj); this.data.src = image; this.scale = scale; this.rotation = rotation; @@ -82,6 +105,47 @@ CBDL.Graphics.BaseDisplay.prototype._Image_.prototype.destroy = function() { this.data = null; }; +CBDL.Graphics.BaseDisplay.prototype._Spritesheet_ = function(display, image, size, sprite_size) { + this.display = display; + this.data = new Image(); + this.image = image; + this.size = size; + this.cols = size.width / sprite_size.width; + this.rows = size.height / sprite_size.height; + this.sprite_size = sprite_size; + var load_obj = display.addLoading(image); + this.data.onload = (function(scope, load_obj) { + return function() { + //scope.size.width = this.width; + //scope.size.height = this.height; + //scope.rows = this.width / scope.sprite_width; + //scope.cols = this.height / scope.sprite_height; + load_obj.state = 1; + } + })(this, load_obj); + + this.data.src = image; + this.scale = 1; + this.rotation = 0; +};CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Drawable_, CBDL.Graphics.BaseDisplay.prototype._Spritesheet_); +CBDL.Graphics.BaseDisplay.prototype._Spritesheet_.prototype.destroy = function() { + this.data = null; +}; +CBDL.Graphics.BaseDisplay.prototype._Sprite_ = function(display, spritesheet, position, size) { + this.display = display; + this.data = spritesheet.data; + this.position = position; + this.size = size; + this.scale = 1; + this.rotation = 0; +};CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Drawable_, CBDL.Graphics.BaseDisplay.prototype._Sprite_); +CBDL.Graphics.BaseDisplay.prototype._Sprite_.prototype.destroy = function() { + this.data = null; +}; +CBDL.Graphics.BaseDisplay.prototype._Sprite_.prototype.setPosition = function(x, y) { + this.position.x = x; + this.position.y = y; +}; CBDL.Graphics.BaseDisplay.prototype._Box_ = function(display, size, scale, rotation) { this.display = display; @@ -247,6 +311,7 @@ CBDL.Graphics.WebGlDisplay.prototype._Image_ = function(display, image, scale, r CBDL.Graphics.Canvas2dDisplay = function(target_element, video_mode) { this.video_mode = video_mode; this.target_element = target_element; + this.scale = {x: 1, y: 1}; this.type = 'Canvas2dDisplay'; }; CBDL.extend(CBDL.Graphics.BaseDisplay, CBDL.Graphics.Canvas2dDisplay); @@ -274,7 +339,15 @@ CBDL.Graphics.Canvas2dDisplay.prototype.Init = function() { } this.element_context = this.element.getContext("2d"); + // FIXME: should be handled as a render flag + /*this.element_context.imageSmoothingEnabled = false; + this.element_context.mozImageSmoothingEnabled = false; + this.element_context.webkitImageSmoothingEnabled = false;*/ this.target_element.appendChild(this.element); + // FIXME: it seems elements do not trigger resize events :S + CBDL.addEvent(this.target_element, "resize", (function(scope) { return function(event) { + scope.updateViewport(); + }})(this), true); // offscreen canvas, used for any transformations that must be done via putImageData // or getImageData. (e.g., opacity) @@ -290,23 +363,41 @@ CBDL.Graphics.Canvas2dDisplay.prototype.updateViewport = function() { this.element.width = this.viewport.width; this.element.height = this.viewport.height; } + var viewport = this.getViewport(); + if (this.video_mode.flags & CBDL.Graphics.VM.SCALE) { + var ratio = Math.min(viewport.width / this.video_mode.width, viewport.height / this.video_mode.height); + this.scale.x = ratio; + this.scale.y = ratio; + this.element.width = this.viewport.width * ratio; + this.element.height = this.viewport.height * ratio; + } + if (this.video_mode.flags & CBDL.Graphics.VM.VCENTER) { + this.element.style.top = (viewport.height/2 - this.viewport.height/2)+"px"; + } + if (this.video_mode.flags & CBDL.Graphics.VM.HCENTER) { + this.element.style.left = (viewport.width/2 - this.viewport.width/2)+"px"; + } }; CBDL.Graphics.Canvas2dDisplay.prototype.setWidth = function(width) { this.video_mode.width = width; this.element.width = width; + this.viewport.width = width; + this.element.style.width = width+"px"; }; CBDL.Graphics.Canvas2dDisplay.prototype.setHeight = function(height) { this.video_mode.height = height; this.element.height = height; + this.viewport.height = height; + this.element.style.height = height+"px"; }; CBDL.Graphics.Canvas2dDisplay.prototype.Fill = function(red, green, blue) { var hex_value = ((1 << 24) + (red << 16) + (green << 8) + blue); var hex_string = hex_value.toString(16).substr(1); this.element_context.fillStyle = "#"+hex_string; - this.element_context.fillRect(0, 0, this.video_mode.width, this.video_mode.height); + this.element_context.fillRect(0, 0, this.video_mode.width*this.scale.x, this.video_mode.height*this.scale.y); }; CBDL.Graphics.Canvas2dDisplay.prototype.clear = function() { @@ -328,6 +419,17 @@ CBDL.Graphics.Canvas2dDisplay.prototype.draw = function(source, s_position, t_po // element_context as an Image when complete. this.element_context.save(); + + if (source instanceof CBDL.Graphics.BaseDisplay.prototype._Sprite_) { + s_position.x -= source.position.x; + s_position.y -= source.position.y; + } + + scale_x = this.scale.x + (source.scale.x ? source.scale.x : 0); + scale_y = this.scale.y + (source.scale.y ? source.scale.y: 0); + t_position.x *= scale_x; + t_position.y *= scale_y; + this.element_context.translate(t_position.x, t_position.y); if (source.data instanceof Image) { @@ -339,13 +441,12 @@ CBDL.Graphics.Canvas2dDisplay.prototype.draw = function(source, s_position, t_po if (typeof source.rotation !== 'undefined') { this.element_context.rotate(source.rotation * CBDL.Graphics.RADIAN); } - if (typeof source.scale !== 'undefined') { - this.element_context.scale(source.scale.x, source.scale.y); - } - + //if (typeof source.scale !== 'undefined') { + this.element_context.scale(scale_x, scale_y); + //} // Set transparency offscreen due to putImageData overwriting all pixel values in // the canvas. - this.offscreen_context.drawImage(source.data, 0, 0); + this.offscreen_context.drawImage(source.data, s_position.x, s_position.y); if (typeof source.opacity !== 'undefined') { // NOTE: getImageData & putImageData are painfully slow! :( var image = this.offscreen_context.getImageData(0, 0, width, height); @@ -443,6 +544,14 @@ CBDL.Graphics.Canvas2dDisplay.prototype.Image = function(image, scale, rotation) return (new CBDL.Graphics.BaseDisplay.prototype._Image_(this, image, scale, rotation)); }; +CBDL.Graphics.Canvas2dDisplay.prototype.Spritesheet = function(image, size, sprite_size) { + return (new CBDL.Graphics.Canvas2dDisplay.prototype._Spritesheet_(this, image, size, sprite_size)); +}; + +CBDL.Graphics.Canvas2dDisplay.prototype.Sprite = function(image, position, size) { + return (new CBDL.Graphics.BaseDisplay.prototype._Sprite_(this, image, position, size)); +}; + CBDL.Graphics.Canvas2dDisplay.prototype.Box = function(size, scale, rotation) { return (new CBDL.Graphics.BaseDisplay.prototype._Box_(this, size, scale, rotation)); }; @@ -475,6 +584,7 @@ CBDL.Graphics.DivDisplay = function(target_element, video_mode) { this.target_element = target_element; this.video_mode = video_mode; this.type = 'DivDisplay'; + this.scale = {x: 1, y: 1}; }; CBDL.extend(CBDL.Graphics.BaseDisplay, CBDL.Graphics.DivDisplay); CBDL.Graphics.DivDisplay.prototype.Init = function() { @@ -487,16 +597,20 @@ CBDL.Graphics.DivDisplay.prototype.Init = function() { this.element.style.position = "relative"; } if (this.video_mode.flags & CBDL.Graphics.VM.FILL) { - this.viewport = CBDL.Graphics.getViewport(); - this.element.style.width = this.viewport.width+"px"; - this.element.style.height = this.viewport.height+"px"; + alert(this.video_mode.flags); + this.viewport = CBDL.Graphics.getViewport(); + this.video_mode.width = this.viewport.width; + this.video_mode.height = this.viewport.height; + this.element.width = this.viewport.width; + this.element.height = this.viewport.height; } else { this.viewport = {}; this.viewport.width = this.video_mode.width; this.viewport.height = this.video_mode.height; - this.element.style.width = this.video_mode.width+"px"; - this.element.style.height = this.video_mode.height+"px"; + this.element.width = this.video_mode.width; + this.element.height = this.video_mode.height; } + this.updateViewport(); this.element.style.display = "block"; this.element.style.overflow = "hidden"; this.target_element.appendChild(this.element); @@ -509,13 +623,29 @@ CBDL.Graphics.DivDisplay.prototype.updateViewport = function() { this.element.style.width = this.viewport.width+"px"; this.element.style.height = this.viewport.height+"px"; } + var viewport = this.getViewport(); + if (this.video_mode.flags & CBDL.Graphics.VM.SCALE) { + var ratio = Math.min(viewport.width / this.video_mode.width, viewport.height / this.video_mode.height); + this.scale.x = ratio; + this.scale.y = ratio; + this.element.style.width = this.viewport.width * ratio + "px"; + this.element.style.height = this.viewport.height * ratio + "px"; + } + if (this.video_mode.flags & CBDL.Graphics.VM.VCENTER) { + this.element.style.top = (viewport.height/2 - this.viewport.height/2)+"px"; + } + if (this.video_mode.flags & CBDL.Graphics.VM.HCENTER) { + this.element.style.left = (viewport.width/2 - this.viewport.width/2)+"px"; + } }; CBDL.Graphics.DivDisplay.prototype.setWidth = function(width) { + this.viewport.width = width; this.element.style.width = width+"px"; }; CBDL.Graphics.DivDisplay.prototype.setHeight = function(height) { + this.viewport.height = height; this.element.style.height = height+"px"; }; @@ -533,10 +663,25 @@ CBDL.Graphics.DivDisplay.prototype.draw = function(source, s_position, t_positio if (!source.isDrawn) { source.data.style.position = "absolute"; source.data.style.display = "block"; + source.data.style.overflow = "hidden"; + if (source instanceof CBDL.Graphics.DivDisplay.prototype._Sprite_) { + source.image_data.style.position = "absolute"; + source.image_data.style.display = "block"; + } this.element.appendChild(source.data); source.isDrawn = true; } + if (source instanceof CBDL.Graphics.DivDisplay.prototype._Sprite_) { + source.image_data.style.left = -(source.position.x)+"px"; + source.image_data.style.top = -(source.position.y)+"px"; + } + + scale_x = this.scale.x; + scale_y = this.scale.y; + t_position.x *= scale_x; + t_position.y *= scale_y; + var transform = ''; if (source instanceof CBDL.Graphics.BaseDisplay.prototype._Line_) { @@ -555,15 +700,15 @@ CBDL.Graphics.DivDisplay.prototype.draw = function(source, s_position, t_positio t_position.y += rot_y; transform += "rotate("+angle+"deg)"; } else { - source.data.style.height = source.size.height; + source.data.style.height = source.size.height+"px"; } if (typeof source.rotation !== 'undefined') { - transform += "rotate("+source.rotation+"deg)" - } - if (typeof source.scale !== 'undefined') { - transform += "scale("+source.scale.x+", "+source.scale.y+")" + transform += "rotate("+source.rotation+"deg)"; } + //if (typeof source.scale !== 'undefined') { + transform += "scale("+scale_x+", "+scale_y+")"; + //} if (typeof source.opacity !== 'undefined') { source.data.style.opacity = source.opacity; } @@ -582,7 +727,6 @@ CBDL.Graphics.DivDisplay.prototype.clear = function() { CBDL.Graphics.DivDisplay.prototype.Drawable = function() { this.lol = "lol"; - console.log("buh"); }; CBDL.Graphics.DivDisplay.prototype.Image = function(image, scale, rotation) { @@ -592,16 +736,93 @@ CBDL.Graphics.DivDisplay.prototype.Image = function(image, scale, rotation) { CBDL.Graphics.DivDisplay.prototype._Image_ = function(display, image, scale, rotation) { this.isDrawn = false; this.display = display; - this.data = document.createElement("img"); - this.data.src = image; + this.data = document.createElement("div"); + this.size = { width: 1, height: 1 }; + this.image = image; + this.image_data = document.createElement("img"); + var load_obj = display.addLoading(image); + this.image_data.onload = (function(scope, load_obj) { + return function() { + scope.size.width = this.width; + scope.size.height = this.height; + load_obj.state = 1; + } + })(this, load_obj); + this.image_data.src = image; + this.image_data.style.position = "absolute"; + this.data.appendChild(this.image_data); + this.scale = scale; this.rotation = rotation; this.data.style.visibility = 'hidden'; };CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Drawable_, CBDL.Graphics.DivDisplay.prototype._Image_); CBDL.Graphics.DivDisplay.prototype._Image_.prototype.destroy = function() { + this.data.removeChild(this.image_data); this.data.parentNode.removeChild(this.data); }; +// What is a spritesheet? Basically an Image that is not supposed to be displayed. It should pretty much just be the data of the Images. +CBDL.Graphics.DivDisplay.prototype.Spritesheet = function(image, size, sprite_size) { + return (new CBDL.Graphics.DivDisplay.prototype._Spritesheet_(this, image, size, sprite_size)); +}; +CBDL.Graphics.DivDisplay.prototype._Spritesheet_ = function(display, image, size, sprite_size) { + this.isDrawn = false; + this.display = display; + this.data = document.createElement("div"); + this.size = size; + this.sprite_size = sprite_size; + this.cols = size.width / sprite_size.width; + this.rows = size.height / sprite_size.height; + this.image_data = document.createElement("img"); + var load_obj = display.addLoading(image); + this.image_data.onload = (function(scope, load_obj) { + return function() { + load_obj.state = 1; + //scope.size.width = this.width; + //scope.size.height = this.height; + //scope.rows = this.width / scope.sprite_width; + //scope.cols = this.height / scope.sprite_height; + } + })(this, load_obj); + this.image_data.src = image; + this.image_data.style.position = "absolute"; + this.data.appendChild(this.image_data); + + this.scale = 1; + this.rotation = 0; + this.data.style.visibility = 'hidden'; +};CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Drawable_, CBDL.Graphics.DivDisplay.prototype._Spritesheet_); + +CBDL.Graphics.DivDisplay.prototype.Sprite = function(spritesheet, position, size) { + return (new CBDL.Graphics.DivDisplay.prototype._Sprite_(this, spritesheet, position, size)); +}; +// DivDisplay uses individual img elements for every Sprite. +CBDL.Graphics.DivDisplay.prototype._Sprite_ = function(display, spritesheet, position, size) { + this.isDrawn = false; + this.display = display; + this.spritesheet = spritesheet; + this.position = position; + this.data = document.createElement("div"); + this.size = size; + this.image_data = document.createElement("img"); + this.image_data.src = spritesheet.image_data.src; + this.image_data.style.position = "absolute"; + this.data.appendChild(this.image_data); + + this.scale = {x: 1, y: 1}; + this.rotation = 0; + this.data.style.visibility = 'hidden'; +};CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Drawable_, CBDL.Graphics.DivDisplay.prototype._Sprite_); +CBDL.Graphics.DivDisplay.prototype._Sprite_.prototype.destroy = function() { + this.data.removeChild(this.image_data); + this.data.parentNode.removeChild(this.data); + this.data = null; +}; +CBDL.Graphics.DivDisplay.prototype._Sprite_.prototype.setPosition = function(x, y) { + this.position.x = x; + this.position.y = y; +}; + CBDL.Graphics.DivDisplay.prototype.Box = function(size, scale, rotation) { return (new CBDL.Graphics.DivDisplay.prototype._Box_(this, size, scale, rotation)); }; @@ -780,7 +1001,6 @@ Usage: CBDL.Graphics.Drawable = function(position, scale, rotation) { this.setPosition = function(x, y) { - } this.setScale = function(x, y) {