HTML5 issue with context.createPattern - html

I have a problem with the method createPattern(). I have this image as background pattern:
When I use it as a pattern, this is what I obtain:
Why, because I expect the output to be as follows:
I think that the problem can be caused in some previous setting of the context, but what type of setting can do this? However this is the specific code that I use to make the pattern:
var pattern_bg = new Image();
pattern_bg.src = 'bg.png';
pattern_bg.onload = function(){
var pattern = context.createPattern(pattern_bg, "repeat");
context.fillStyle = pattern;
context.fillRect(0, 0, 223, 60);
}
Can please anyone help me to fix this issue?

To have the pattern that you want, you need to translate first at the point you want to be the origin of the fill, then draw from here.
So be sure to save() and restore() the context each time you change its transform matrix (translate, rotate, scale) to be able to set the translation as you want.
Do not forget you can always use setTransform to reset the matrix with ctx.setTransform(1,0,1,0,0,0);
I've done a very small jsbin to illustrate, here :
http://jsbin.com/EYArASA/1/edit?js,output
We can see the result on this picture, fill is done directly on the left, and after a translate on the right.
Code is very simple, interesting part is this :
// rect drawn directly : wrong result
ctx.fillRect(10,20,64,64);
// canvas translated, then fillRect at 0,0 :
// right result
ctx.translate(116,20);
ctx.fillRect(0,0,64,64);

Related

Actionscript 3 - alternatives to .hitTestObject or position constraints

I need to detect when MC2 is over MC1 that it is inside MC1's borders.
to do this I would usually use 4 separate if x y constraints,
and unfortunately .hitTestObject in my creations also seem to need 4 separate if x y + - constraints.
Does anyone know a more simplistic way to achieve this.
or is x y + - constraints still the only way to do this?
Thank you in advance.
The final solution for your problem to detect hit of two shapes, is to use bitmapData.hitTest(). you can detect hit between any shapes and not only Rectangles. for that, you have to draw both of your shapes on bitmapData like line belo:
var shape1Bitmap:BitmapData = new BitmapData(shape1MC.with,shape1MC.height,true,0x000000);
shape1Bitmap.draw(shape1MC);
var shape2Bitmap:BitmapData = new BitmapData(shape1MC.with,shape1MC.height,true,0x000000);
shape1Bitmap.draw(shape1MC);
shape1Bitmap.hitTest(new Point(),shape2Bitmap):Boolean;******
to continue usint BitmapData.hitTest(), folow the orders here : https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#hitTest()
http://dougmccune.com/blog/2007/02/03/using-hittestpoint-or-hittest-on-transparent-png-images/
It is a little complicated to add the bitmapData.hitTest() samples here. if any further questions left, please let me know to explain.
Good luck
I don't know of a built in way to do this, but it's easy enough using hitTestPoint with each corner of the square:
function isSquareInsideObject(square:DisplayObject, obj:DisplayObject):Boolean {
if(!obj.hitTestPoint(square.x, square.y, true)) return false;
if(!obj.hitTestPoint(square.x + square.width, square.y, true)) return false;
if(!obj.hitTestPoint(square.x + square.width, square.y + square.height, true)) return false;
if(!obj.hitTestPoint(square.x, square.y + square.height, true)) return false;
return true;
}
For more complex shapes than a square, you'd have to add more points to be accurate and it becomes a less elegant and less performant solution then.
You need that shape argument (third parameter for hitTestPoint) set to true if you want to test against the actual circle shape instead of the rectangular bounding box of the circle. If your circle is a bitmap (and not a shape), then I'd suggest putting a circular mask on the object to achieve the same result.
If your square isn't anchored at 0,0, or you don't mind the extra (small) performance hit, you could also use var bounds:Rectangle = square.getBounds(this) and then use the convenience properties of the rectangle object (bounds.bottomLeft, bottomRight, topLeft, topRight)

Forge function generateTexture()

In the following example, there is a function called generateTexture().
Is it possible to draw text (numbers) into the pixel array? Or is it possible to draw text (numbers) on top of that shader?
Our goal is to draw a circle with a number inside of it.
https://forge.autodesk.com/blog/using-dynamic-texture-inside-custom-shaders
UPDATE:
We noticed that each circle can't use a unique generateTexture(). The generateTexture() result is used by every single one of them. The only thing that can be customized per object is the color, plus what texture is used.
We could create a workaround for this, which is to generate every texture from 0 to 99, and to then have each object choose the correct texture based on the number we want to display. We don't know if this will be efficient enough to work properly though. Otherwise, it might have to be 0 to 9+ or something in that direction. Any guides on our updated question would be really appreciated. Thanks.
I am able to successfully display text with the following code, simply replace generateTexture() by generateCanvasTexture() in the sample and you should get the result below:
const generateCanvasTexture = () => {
const canvas = document.createElement("canvas")
const ctx = canvas.getContext('2d')
ctx.font = '20pt Arial'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText(new Date().toLocaleString(),
canvas.width / 2, canvas.height / 2)
const canvasTexture = new THREE.Texture(canvas)
canvasTexture.needsUpdate = true
canvasTexture.flipX = false
canvasTexture.flipY = false
return canvasTexture
}
It is possible but you would need to implement it yourself. Shaders are a pretty low level feature so there is no way to directly draw a number or a text, but you can convert a given character into its representation as a 2d pixel array.

Using a sprite sheet with createPattern()

I can't seem to find any solid info on how to do this, so I'm wondering if someone can point me in the right direction.
I have a large sprite sheet, let's call it textures.png. Each texture is 64x64 pixels and I need to be able to create patterns out of these textures.
createPattern() is a great function but it seems to only take two arguments, the image source and whether to repeat it or not. This is fine if you are loading a single image for each texture, but I'm wondering how to do this using textures.png.
I found this answer https://gamedev.stackexchange.com/questions/38451/repeat-a-part-of-spritesheet-as-background but I am not sure what the accepted answer is referring to with the generatePattern() method, as far as I can tell this isn't even a canvas method.
Thanks in advance!
Okay I've worked out the solution to this. Basically, createPattern() can take either an image or canvas element as its first argument. So you need to do the following:
var pattern_canvas = document.createElement('canvas');
pattern_canvas.width = texture_width;
pattern_canvas.height = texture_height;
var pattern_context = pattern_canvas.getContext('2d');
pattern_context.drawImage(img , texture_sx , texture_sy , texture_width , texture_height);
var final_pattern = canvas_context.createPattern(pattern_canvas , "repeat");
canvas_context.fillStyle = final_pattern;
canvas_context.fillRect( 0 , 0 , canvas.width , canvas.height );
If you do this then your canvas element will have pattern_canvas repeatedly drawn to cover its dimensions.

AS3: BitmapData linked to certain sprite in library?

I have a problem. I have a sprite added to library and I linked and named its class "CarriedHead_Normal". Now I want to display this sprite and make every black(000000) pixel invisible (just convert background to alpha).
I know I can use this
var bmpd:BitmapData = new BitmapData(width, height, true, 0x000000)
But how am I supposed to merge this with my function, so I call the class from the library and make it's bg transparent?
My current code:
var imageSprite = new Sprite();
addChild(imageSprite);
var libraryImage:Bitmap = new Bitmap(new CarriedHead_Normal(0, 0))
imageSprite.addChild(libraryImage);
Thanks in advance.
A number of ways you could do it, some working better than others:
On a side node, your question title has nothing to do with your actual question
1) Use blend modes
Depending on your graphics and background, you might be able to get away with a simple blendMode - check out BlendMode.SCREEN in particular. Note that some blend modes require that your parent container have a blendMode of BlendMode.LAYER
2) copyPixels() using an alpha BMD
copyPixels() lets you specify an alpha BitmapData to use when deciding which pixels to copy over (actually the alpha value of the pixels to copy over). If you have an alpha BitmapData that matches your black areas, you can remove it like that:
var b:BitmapData = new BitmapData( myImageBMD.width, myImageBMD.height, true, 0x00000000 );
b.copyPixels( myImageBMD, myImageBMD.rect, new Point, alphaBMD, new Point, false ); // copy our image, using alphaBMD to remove the black
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#copyPixels()
3) floodFill() the black areas
If your black area is continuous and you know a pixel that it starts on (e.g. it's a black frame around an image), then you can use floodFill() to remove the black areas
var b:BitmapData = new BitmapData( myImageBMD.width, myImageBMD.height, true, 0x00000000 );
b.copyPixels( myImageBMD, myImageBMD.rect, new Point ); // copy our image so we keep the original
b.floodFill( 0, 0, 0x00000000 ); // assuming the first pixel is black, floodFill() from here, replacing with transparence
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#floodFill()
This technique will work best on pixel art, where the edges are well defined.
4) threshold() to remove the black
threshold() takes pixel values and replaces them with the value you set if they pass a certain test (<, <=, ==, etc). You can use this to replace black with transparence.
var b:BitmapData = new BitmapData( myImageBMD.width, myImageBMD.height, true, 0x00000000 );
b.copyPixels( myImageBMD, myImageBMD.rect, new Point ); // copy our image so we keep the original
b.threshold( b, b.rect, new Point, "==", 0xff000000, 0x00000000 ); // test the pixels; if they're black, replace with transparence
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#threshold()
Again, this works best when the edges are well defined.
5) Use filters
You can use applyFilter() to create a new image, using a BitmapFilter to remove the black. Possibly only of the other filters will work, but ShaderFilter should definitely do the job (you write your own shader, so you can essentially do what you want). I don't have any real experience with filters, so I can't tell you how they work, but some googling should give you the necessary code
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html#applyFilter()
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/filters/ShaderFilter.html
6) Use photoshop (or equivalent)
The easiest method; just edit your image to remove the black; much less hassle :)
Try something like:
var libraryImage:Bitmap = spriteToBitmap(new CarriedHead_Normal());
imageSprite.addChild(libraryImage);
function spriteToBitmap(sprite:Sprite, smoothing:Boolean = false):Bitmap
{
var bitmapData:BitmapData = new BitmapData(sprite.width, sprite.height, true, 0x00000000);
bitmapData.draw(sprite);
bitmapData.threshold(bitmapData, bitmapData.rect, new Point(), '==', 0xff000000, 0x00000000);
return new Bitmap(bitmapData, "auto", smoothing);
}

html canvas shadow being applied to everything

If you define a shadow ONCE, then it applies to all "graphics" on the canvas from thereon after (which is what it's supposed to do).
Sample:
http://flanvas.com/development/flanvas/test.html
Does anyone know best practice to turn the shadow off after you've used it? I'm setting shadowColor to "rgba(0,0,0,0)" which is a no-alpha black. I'm sure there is a better way.
case sample: The text is also getting a shadow. I'm using the no-alpha black to combat this for now.
http://flanvas.com/development/flanvas/examples/filters-dropShadowFilter.html
By using save, translate and restore you can perform your tasks without worrying about the style changes, for eg.
ctx.save();
ctx.translate(X,Y);
ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
// do some stuff
ctx.restore();
here X & Y are the co-ordinates where you intended to draw and you do your stuff relative to the co-ordinates 0,0.
This method solves the problem of caching and restoring the previous styles/values and is also very helpful when you work with gradients as they are always plotted relative to the origin (0,0)
(EDIT: Oops! I see that's what you were already doing with a 0 alpha black.)
This is what you were looking for:
context.shadowColor = "transparent";
It's usually a good idea to store the old value of these kind of "global" attributes before you change it and use this stored value to restore it later on. Example:
var origShadowColor = ctx.shadowColor;
ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
// ... do some stuff
ctx.shadowColor = origShadowColor;
I created a function i can call to reset the shadow if needed.
resetShadow() {
this.ctx.shadowOffsetX = 0;
this.ctx.shadowOffsetY = 0;
this.ctx.shadowColor = "transparent";
}