diff --git a/CBDL.js b/CBDL.js index 2fc04c9..f67c954 100644 --- a/CBDL.js +++ b/CBDL.js @@ -8,10 +8,6 @@ CBDL.version = 0.1; // TODO: completely redo requires & library includes. At the moment, it is broken and disallows multiple Apps from starting if they both require libraries. -CBDL.dump = function() { - console.log("CBDL version "+CBDL.version); -} - /* =============================================================================== @@ -258,6 +254,8 @@ CBDL.Loop = function(scope, callback, interval) { } } +// TODO: Add CallbackLoop - an alternative object that loops only on some event + /* ================ CBDL.useNamespace(object) @@ -422,6 +420,10 @@ CBDL.loadInclude = function(include) { */ } +CBDL.EventTrigger = function(context, event_type, target, bubble) { + CBDL.addEvent(context, event_type, target, bubble); +}; + /* =============================================================================== CBDL.Event(event_masks) @@ -534,6 +536,11 @@ CBDL.Event.prototype.pollEvent = function() { } }; +// TODO: move this too CBDL.Graphics - it doesn't belong here. +CBDL.Event.prototype.getMouse = function(event, display) { + return ( {x: (event.clientX-display.element.offsetLeft), y: (event.clientY-display.element.offsetTop)} ); +}; + CBDL.Event.EventPool = CBDL.Event.EventPool || function() {}; CBDL.Event.EventPool.prototype.events = []; @@ -556,6 +563,117 @@ CBDL.Event.EventPool.prototype.push = function(event) { this.events.push(event); }; +// TODO: create a CBDL.Loader object that allows for fancier file loading with +// progress, current states, etc. + +/* +======================================== +CBDL.loadFile(file_name, callback_function) + +This function creates a hidden 'iframe' tag, sets its 'src' property to +file_name, and adds a 'load' event which calls callback_function with the +innerHTML of the iframe's document.body. If the iframe also has a 'pre' tag +within document.body, as occurs default within FF, the innerHTML property of +the first 'pre' tag is provided to the callback. +======================================== +*/ +CBDL.loadFile = function(file, callback) { + var iframe = document.createElement('iframe'); + iframe.id = file; + iframe.style.display = 'none'; + document.body.appendChild(iframe); + CBDL.addEvent(iframe, 'load', (function(iframe, callback) { + return function() { + var doc = (iframe.contentDocument || iframe.contentWindow.document || window[iframe.id].document); + var pre = doc.body.getElementsByTagName("pre"); + if (typeof pre[0] === 'undefined') { + callback(doc.body.innerHTML); + } else { + callback(pre[0].innerHTML); + } + // remove self w/ "delay" to prevent resource cancelled msg in Safari + setTimeout((function(iframe) { + return function() { + document.body.removeChild(iframe); + } + })(iframe), 0); + } + })(iframe, callback)); + iframe.src = file; +}; + +/* +======================================== +CBDL.requestFile(file_name, callback_function) + +This function creates an XMLHttpRequest/Microsoft.XMLHTTP request for the +provided 'file_name', calling 'callback_function' with the request's +responseText property upon a 200 status load. CBDL.requestFile and +CBDL.loadFile can be used interchangeably, however requestFile requires the +App to be loaded from a web server, whilst loadFile can work on an App without +a webserver, so long as iframes are supported. +======================================== +*/ +CBDL.requestFile = function(file, callback) { + if (!/*@cc_on!@*/false) { + var request = new XMLHttpRequest(); + } else { + var request = new ActiveXObject("Microsoft.XMLHTTP"); + } + CBDL.addEvent(request, 'readystatechange', (function(scope, callback) { + return function() { + if (scope.readyState == 4) { // done loading + if (scope.status == 200) { + callback(scope.responseText); + } + } + } + })(request, callback)); + request.open('GET', file, true); + request.send(null); +}; + +CBDL.Console = function(name) { + this.name = name; + this.logs = []; + this.is_logging = true; + this.is_printing = true; +}; + +CBDL.Console.prototype.stopLogging = function() { + this.is_logging = false; +}; +CBDL.Console.prototype.startLogging = function() { + this.is_logging = true; +}; +CBDL.Console.prototype.stopPrinting = function() { + this.is_printing = false; +}; +CBDL.Console.prototype.startPrinting = function() { + this.is_printing = true; +}; + + +CBDL.Console.prototype.log = function(string) { + var time = new Date().toJSON(); + if (this.is_logging) { + var new_log = { time: time, string: string }; + this.logs.push(new_log); + } + if(this.is_printing) { + this.print(this.name+":"+time + ": " + string); + } +}; + +CBDL.Console.prototype.print = (typeof console.log !== 'undefined' ? + function(string) { + console.log(string); + } +: + function(string) { + } +); + // CROSS-BROWSER GLUE CBDL.addEvent = (typeof window.attachEvent !== 'undefined' ? function(target, event_type, callback, bubble) { diff --git a/CBDL_graphics.js b/CBDL_graphics.js index 0c39eb7..5e80d19 100644 --- a/CBDL_graphics.js +++ b/CBDL_graphics.js @@ -27,12 +27,10 @@ CBDL.Graphics.BaseDisplay = function(video_mode, target_element) { this.target_element = target_element; }; -CBDL.Graphics.BaseDisplay.prototype.Init = function() { - -}; -CBDL.Graphics.BaseDisplay.prototype.Fill = function(red, green, blue) { - -}; +CBDL.Graphics.BaseDisplay.prototype.Init = 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._Drawable_ = function(display, size, scale, rotation) { this.display = display; @@ -53,15 +51,61 @@ CBDL.Graphics.BaseDisplay.prototype._Drawable_.prototype.setSize = function(size this.size = size; }; +CBDL.Graphics.BaseDisplay.prototype._Drawable_.prototype.setOpacity = function(opacity) { + this.opacity = opacity; +}; +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.data.onload = function() { - }; + this.size = { width: 1, height: 1 }; + this.data.onload = (function(scope) { + return function() { + scope.size.width = this.width; + scope.size.height = this.height; + } + })(this); this.data.src = image; this.scale = scale; this.rotation = rotation; };CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Drawable_, CBDL.Graphics.BaseDisplay.prototype._Image_); +CBDL.Graphics.BaseDisplay.prototype._Image_.prototype.destroy = function() { + this.data = null; +}; + + +CBDL.Graphics.BaseDisplay.prototype._Box_ = function(display, size, scale, rotation) { + this.display = display; + this.size = size; + this.scale = scale; + this.rotation = rotation; +}; CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Drawable_, CBDL.Graphics.BaseDisplay.prototype._Box_); + +CBDL.Graphics.BaseDisplay.prototype._Font_ = function(family) { + this.family = family; +}; +CBDL.Graphics.BaseDisplay.prototype._Font_.prototype.destroy = function() {}; + +CBDL.Graphics.BaseDisplay.prototype._String_ = function(text, font, size) { + this.text = text; + this.font = font; + this.size = size; + this.color = "#000000"; +}; +CBDL.Graphics.BaseDisplay.prototype._String_.prototype.setText = function(text) { + this.text = text; +}; +CBDL.Graphics.BaseDisplay.prototype._String_.prototype.setFont = function(font) { + this.font = font; +}; +CBDL.Graphics.BaseDisplay.prototype._String_.prototype.setSize = function(size) { + this.size = size; +}; +CBDL.Graphics.BaseDisplay.prototype._String_.prototype.setColor = function(color) { + this.color = color; +}; +CBDL.Graphics.BaseDisplay.prototype._String_.prototype.destroy = function() {}; CBDL.Graphics.getBackend = function() { var supports = []; @@ -159,6 +203,11 @@ CBDL.Graphics.Canvas2dDisplay.prototype.Init = function() { this.element.height = this.video_mode.height; this.element_context = this.element.getContext("2d"); this.target_element.appendChild(this.element); + + // offscreen canvas, used for any transformations that must be done via putImageData + // or getImageData. (e.g., opacity) + this.offscreen = document.createElement("canvas"); + this.offscreen_context = this.offscreen.getContext("2d"); }; CBDL.Graphics.Canvas2dDisplay.prototype.Fill = function(red, green, blue) { @@ -169,31 +218,91 @@ CBDL.Graphics.Canvas2dDisplay.prototype.Fill = function(red, green, blue) { }; CBDL.Graphics.Canvas2dDisplay.prototype.clear = function() { - this.element_context.fillStyle = "#000000"; - this.element_context.fillRect(0, 0, this.video_mode.width, this.video_mode.height); +// this.element_context.fillStyle = "#000000"; +// this.element_context.fillRect(0, 0, this.video_mode.width, this.video_mode.height); +// this.offscreen_context.fillStyle = "#000000"; +// this.offscreen_context.fillRect(0, 0, this.video_mode.width, this.video_mode.height); + this.element_context.clearRect(0, 0, this.element.width, this.element.height); + this.offscreen_context.clearRect(0, 0, this.offscreen.width, this.offscreen.height); }; CBDL.Graphics.Canvas2dDisplay.prototype.draw = function(source, s_position, t_position) { - this.element_context.save(); + var width = source.size.width || 1; + var height = source.size.height || 1; + // How this works: element_context, being the overall canvas, handles sprite rotation + // and scaling. offscreen_context handles setting opacity, and is written to + // element_context as an Image when complete. + this.element_context.save(); this.element_context.translate(t_position.x, t_position.y); if (source.data instanceof Image) { - this.element_context.translate(source.data.width/2, source.data.height/2); + // set offscreen + this.offscreen.width = width; + this.offscreen.height = height; + + this.element_context.translate(width/2, height/2); 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); } - this.element_context.drawImage(source.data, -(source.data.width/2), -(source.data.height/2)); + + // Set transparency offscreen due to putImageData overwriting all pixel values in + // the canvas. + this.offscreen_context.drawImage(source.data, 0, 0); + if (typeof source.opacity !== 'undefined') { + // NOTE: getImageData & putImageData are painfully slow! :( + var image = this.offscreen_context.getImageData(0, 0, width, height); + var image_data = image.data; + var length = image_data.length; + for (var i=3;i < length;i +=4) { + if (image_data[i] > 0) { // if not transparent + image_data[i] = image_data[i]*source.opacity; + } + } + image.data = image_data; + this.offscreen_context.putImageData(image, 0, 0); + } + // Copy manipulated image back over to main canvas. + this.element_context.drawImage(this.offscreen, -(width/2), -(height/2)); + } else if (source instanceof CBDL.Graphics.BaseDisplay.prototype._Box_) { + this.offscreen.width = width; + this.offscreen.height = height; + this.element_context.translate(width/2, height/2); + if (typeof source.rotation !== 'undefined') { + this.element_context.rotate(source.rotation * CBDL.Graphics.RADIAN); + } + this.offscreen_context.fillStyle = "#000000"; + this.offscreen_context.fillRect(0, 0, this.video_mode.width, this.video_mode.height); + if (typeof source.opacity !== 'undefined') { + // NOTE: getImageData & putImageData are painfully slow! :( + var image = this.offscreen_context.getImageData(0, 0, width, height); + var image_data = image.data; + var length = image_data.length; + for (var i=3;i < length;i +=4) { + if (image_data[i] > 0) { // if not transparent + image_data[i] = image_data[i]*source.opacity; + } + } + image.data = image_data; + this.offscreen_context.putImageData(image, 0, 0); + } + // Copy manipulated image back over to main canvas. + this.element_context.drawImage(this.offscreen, -(width/2), -(height/2)); + + } else if (source instanceof CBDL.Graphics.BaseDisplay.prototype._String_) { + this.element_context.font = source.size+"px "+source.font.family; + this.element_context.fillStyle = source.color; + this.element_context.fillText(source.text, 0, source.size); } else { - this.element_context.translate(source.size.width/2, source.size.height/2); + /*this.element_context.translate(source.size.width/2, source.size.height/2); if (typeof source.rotation !== 'undefined') { this.element_context.rotate(source.rotation * CBDL.Graphics.RADIAN); } this.element_context.fillStyle = "#FFFFFF"; - this.element_context.fillRect(-(source.size.width/2), -(source.size.height/2), source.size.width, source.size.height); + this.element_context.fillRect(-(source.size.width/2), -(source.size.height/2), source.size.width, source.size.height); */ } this.element_context.restore(); }; @@ -206,6 +315,18 @@ CBDL.Graphics.Canvas2dDisplay.prototype.Image = function(image, scale, rotation) return (new CBDL.Graphics.BaseDisplay.prototype._Image_(this, image, scale, rotation)); }; +CBDL.Graphics.Canvas2dDisplay.prototype.Box = function(size, scale, rotation) { + return (new CBDL.Graphics.BaseDisplay.prototype._Box_(this, size, scale, rotation)); +}; + +CBDL.Graphics.Canvas2dDisplay.prototype.Font = function(family) { + return (new CBDL.Graphics.BaseDisplay.prototype._Font_(family)); +}; + +CBDL.Graphics.Canvas2dDisplay.prototype.String = function(string, font, size) { + return (new CBDL.Graphics.BaseDisplay.prototype._String_(string, font, size)); +}; + /* =============================================================================== @@ -232,6 +353,7 @@ CBDL.Graphics.DivDisplay.prototype.Init = function() { this.element.style.display = "block"; this.element.style.overflow = "hidden"; this.target_element.appendChild(this.element); + this.current_z = 0; }; CBDL.Graphics.DivDisplay.prototype.Fill = function(red, green, blue) { @@ -241,6 +363,7 @@ CBDL.Graphics.DivDisplay.prototype.Fill = function(red, green, blue) { }; CBDL.Graphics.DivDisplay.prototype.draw = function(source, s_position, t_position) { + this.current_z++; source.data.style.visibility = 'hidden'; if (!source.isDrawn) { source.data.style.position = "absolute"; @@ -257,9 +380,13 @@ CBDL.Graphics.DivDisplay.prototype.draw = function(source, s_position, t_positio if (typeof source.scale !== 'undefined') { transform += "scale("+source.scale.x+", "+source.scale.y+")" } + if (typeof source.opacity !== 'undefined') { + source.data.style.opacity = source.opacity; + } source.data.style.left = t_position.x+"px"; source.data.style.top = t_position.y+"px"; + source.data.style.zIndex = this.current_z; CBDL.setElementTransform(source.data, transform); source.data.style.visibility = 'visible'; // source.data.style.width = source.data.width; @@ -268,6 +395,7 @@ CBDL.Graphics.DivDisplay.prototype.draw = function(source, s_position, t_positio CBDL.Graphics.DivDisplay.prototype.clear = function() { this.element.style.backgroundColor = "#000000"; + this.current_z = 0; }; CBDL.Graphics.DivDisplay.prototype.Drawable = function() { @@ -287,6 +415,73 @@ CBDL.Graphics.DivDisplay.prototype._Image_ = function(display, image, scale, rot this.scale = scale; this.rotation = rotation; };CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Drawable_, CBDL.Graphics.DivDisplay.prototype._Image_); +CBDL.Graphics.DivDisplay.prototype._Image_.prototype.destroy = function() { + this.data.parentNode.removeChild(this.data); +}; + +CBDL.Graphics.DivDisplay.prototype.Box = function(size, scale, rotation) { + return (new CBDL.Graphics.DivDisplay.prototype._Box_(this, size, scale, rotation)); +}; + +CBDL.Graphics.DivDisplay.prototype._Box_ = function(display, size, scale, rotation) { + this.isDrawn = false; + this.display = display; + this.data = document.createElement("div"); + this.data.style.width = size.width+"px"; + this.data.style.height = size.height+"px"; + this.data.style.display = "block"; + this.data.style.backgroundColor = "black"; + this.size = size; + this.scale = scale; + this.rotation = rotation; +}; CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._Box_, CBDL.Graphics.DivDisplay.prototype._Box_); +CBDL.Graphics.DivDisplay.prototype._Box_.prototype.destroy = function() { + if (this.data.parentNode) { + this.data.parentNode.removeChild(this.data); + } +}; + +CBDL.Graphics.DivDisplay.prototype.Font = function(family) { + return (new CBDL.Graphics.BaseDisplay.prototype._Font_(family)); +}; + +CBDL.Graphics.DivDisplay.prototype.String = function(text, font, size) { + return (new CBDL.Graphics.DivDisplay.prototype._String_(this, text, font, size)); +}; + +CBDL.Graphics.DivDisplay.prototype._String_ = function(display, text, font, size) { + this.isDrawn = false; + this.display = display; + this.text = text; + this.font = font; + this.size = size; + this.color = "black"; + this.data = document.createElement("div"); + this.data.style.display = "block"; + this.data.style.fontSize = size+"px"; + this.data.style.fontFamily = font.family; + this.data.style.color = "#000000"; + this.data.innerHTML = text; +}; CBDL.extend(CBDL.Graphics.BaseDisplay.prototype._String_, CBDL.Graphics.DivDisplay.prototype._String_); + +CBDL.Graphics.DivDisplay.prototype._String_.prototype.destroy = function() { + if (this.data.parentNode) { + this.data.parentNode.removeChild(this.data); + } +}; +CBDL.Graphics.DivDisplay.prototype._String_.prototype.setText = function(text) { + this.text = text; + this.data.innerHTML = text; +}; + +CBDL.Graphics.DivDisplay.prototype._String_.prototype.setSize = function(size) { + this.size = size; + this.data.style.fontSize = size+"px"; +}; +CBDL.Graphics.DivDisplay.prototype._String_.prototype.setColor = function(color) { + this.color = color; + this.data.style.color = color; +}; CBDL.Graphics.Dispray = function(video_mode, target_element) { var _context = CBDL.Graphics; diff --git a/cbdl.html b/cbdl.html index 411585a..d3c84a8 100644 --- a/cbdl.html +++ b/cbdl.html @@ -89,7 +89,7 @@ myApp2 = function() { var x = 0, y = 0; this.Main = function() { - display = new CBDL.Graphics.Display(document.body, new CBDL.Graphics.VideoMode(320, 240, CBDL.Graphics.VM_SCALE), CBDL.Graphics.BACKEND.DIV); + display = new CBDL.Graphics.Display(document.body, new CBDL.Graphics.VideoMode(320, 240, CBDL.Graphics.VM_SCALE), CBDL.Graphics.BACKEND.WEBGL); console.log("Display Type: "+display.type); display.Init(); display.Fill(0x00, 0x00, 0x00);