Freeing loaded texture on WebGL - webgl

The Textured Box demo on http://www.khronos.org/webgl/wiki/Demo_Repository has the following code snippets:
function loadImageTexture(ctx, url)
{
var texture = ctx.createTexture(); // allocate texture
texture.image = new Image();
texture.image.onload = function()
{ doLoadImageTexture(ctx, texture.image, texture) }
texture.image.src = url;
return texture;
}
function doLoadImageTexture(ctx, image, texture)
{
ctx.bindTexture(ctx.TEXTURE_2D, texture);
ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); // loaded the image
...
}
...
var spiritTexture = loadImageTexture(gl, "resources/spirit.jpg");
...
How do you free the allocated/loaded texture in order to avoid (graphics) memory leak?
Will the following code free both the loaded/allocated texture and image?
spiritTexture = null;
Thanks in advance for your help.
NOTE: Cross post on http://www.khronos.org/message_boards/viewtopic.php?f=43&t=3367 on December 23, 2010 but no answer so far.

ctx.deleteTexture(spiritTexture);
That should free the texture on the gpu.
Regarding the image, you should just modify loadImageTexture so that it doesn't store image inside texture. The reference to image is not needed outside loadImageTexture and you can let it go out of scope naturally when doLoadImageTexture completes.
i.e. make it something like:
function loadImageTexture(ctx, url)
{
var texture = ctx.createTexture(); // allocate texture
var image = new Image();
image.onload = function() { doLoadImageTexture(ctx, image, texture) }
image.src = url;
return texture;
}

Related

p5.js image in a buffer

I am trying to load image "image.png" and place it in the preaviously created createGraphics() buffer.
However when I load the buffer in draw() the image is not there.
I am wondering if an image can be loaded into a buffer, and if so how ?
var buffer;
var image;
function setup() {
createCanvas(800, 800);
image = loadImage("image.png");
buffer = createGraphics(800, 800);
buffer.background(255, 255, 0);
buffer.image(image, 0, 0)
}
function draw() {
image(buffer, 0, 0);
}
any help would be greatly appreciated.
It is not good to call your variable image as p5.js already has an image() function (which you use).
Use preload() to load the image. This ensures that the image is actually loaded before you try to load it in your buffer within setup(). See here for more info on this.
A working example is given here. It uses the following p5 code.
var buffer;
var img;
function preload() {
img = loadImage("p5im.png");
}
function setup() {
createCanvas(600, 600);
buffer = createGraphics(400, 400);
buffer.background(255, 255, 0);
buffer.image(img, 0, 0)
}
function draw() {
image(buffer, 0, 0);
}

Export collage video using metalkit

How can i export collage video using different resolution videos? I'm trying to achieve like showing first image below, I'm using AVCustomEdit demo and have done so far, I created AVMutableVideoComposition pass all video trackIDs to customVideoCompositorClass and getting all videos CVPixelBuffer and than converting in MTLTexture than render all textures but problem is my video output size is square(destinationTexture) and videos size is portrait or landscape thats why every video is squeezed also how can i rotate scale position and mask shape every video? also how can i apply cifilters? should i convert every CVPixelBuffer to ciImage and ciImage back to CVPixelBuffer?
override func renderPixelBuffer(backgroundTexture: MTLTexture,
firstPixelBuffer: CVPixelBuffer,
secondPixelBuffer: CVPixelBuffer,
thirdPixelBuffer: CVPixelBuffer,
fourthPixelBuffer: CVPixelBuffer,
destinationPixelBuffer: CVPixelBuffer) {
// Create a MTLTexture from the CVPixelBuffer.
guard let firstTexture = buildTextureForPixelBuffer(firstPixelBuffer) else { return }
guard let secondTexture = buildTextureForPixelBuffer(secondPixelBuffer) else { return }
guard let thirdTexture = buildTextureForPixelBuffer(thirdPixelBuffer) else { return }
guard let fourthTexture = buildTextureForPixelBuffer(fourthPixelBuffer) else { return }
guard let destinationTexture = buildTextureForPixelBuffer(destinationPixelBuffer) else { return }
/*
We must maintain a reference to the pixel buffer until the Metal rendering is complete. This is because the
'buildTextureForPixelBuffer' function above uses CVMetalTextureCacheCreateTextureFromImage to create a
Metal texture (CVMetalTexture) from the IOSurface that backs the CVPixelBuffer, but
CVMetalTextureCacheCreateTextureFromImage doesn't increment the use count of the IOSurface; only the
CVPixelBuffer, and the CVMTLTexture own this IOSurface. Therefore we must maintain a reference to either
the pixel buffer or Metal texture until the Metal rendering is done. The MTLCommandBuffer completion
handler below is then used to release these references.
*/
pixelBuffers = RenderPixelBuffers(firstBuffer: firstPixelBuffer,
secondBuffer: secondPixelBuffer,
thirdBuffer: thirdPixelBuffer,
fourthBuffer: fourthPixelBuffer,
destinationBuffer: destinationPixelBuffer)
// Create a new command buffer for each renderpass to the current drawable.
let commandBuffer = commandQueue.makeCommandBuffer()!
commandBuffer.label = "MyCommand"
/*
Obtain a drawable texture for this render pass and set up the renderpass
descriptor for the command encoder to render into.
*/
let renderPassDescriptor = setupRenderPassDescriptorForTexture(destinationTexture)
// Create a render command encoder so we can render into something.
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
renderEncoder.label = "MyRenderEncoder"
guard let renderPipelineState = renderPipelineState else { return }
modelConstants.modelViewMatrix = matrix_identity_float4x4
// Render background texture.
renderTexture(renderEncoder, texture: backgroundTexture, pipelineState: renderPipelineState)
var translationMatrix = matrix_float4x4(translation: simd_float3(-0.5, 0.5, 0))
// var rotationMatrix = matrix_float4x4(rotationZ: radians(fromDegrees: -90))
var scaleMatrix = matrix_float4x4(scaling: 0.25)
var modelMatrix = translationMatrix * scaleMatrix
modelConstants.modelViewMatrix = modelMatrix
// Render first texture.
renderTexture(renderEncoder, texture: firstTexture, pipelineState: renderPipelineState)
// translationMatrix = matrix_float4x4(translation: simd_float3(0.5, -0.5, 0))
// rotationMatrix = matrix_float4x4(rotationZ: radians(fromDegrees: -45))
// scaleMatrix = matrix_float4x4(scaling: 0.5)
// modelMatrix = translationMatrix * scaleMatrix * rotationMatrix
// modelConstants.modelViewMatrix = modelMatrix
// // Render second texture.
// renderTexture(renderEncoder, texture: secondTexture, pipelineState: renderPipelineState)
//
// // Render third texture.
// renderTexture(renderEncoder, texture: thirdTexture, pipelineState: renderPipelineState)
//
// // Render fourth texture.
// renderTexture(renderEncoder, texture: fourthTexture, pipelineState: renderPipelineState)
// We're done encoding commands.
renderEncoder.endEncoding()
// Use the command buffer completion block to release the reference to the pixel buffers.
commandBuffer.addCompletedHandler({ _ in
self.pixelBuffers = nil // Release the reference to the pixel buffers.
})
// Finalize rendering here & push the command buffer to the GPU.
commandBuffer.commit()
}
I would recommend to use a library called MetalPetal. It is an image processing framework based on Metal.You have to convert the CVPixelBuffer in to MetalImage that is MTIImage. and then you can do anything in the image like there are premade filters and you can apply to it or you can use even CIFilter or your custom filters and you can transform , rotate , crop every frame so that collage frames are accurate . then you have to convert the MTIimage to cvpixelbuffer again . Here you can also CIImage but it will be slow i guess. And you are getting box images maybe for the render size . Please see the render size .

PDF.js displays PDF documents in really low resolution/ blurry almost. Is this how it is?

I am trying to use PDF.js to view PDF documents. I find the display really low resolutions to the point of being blurry. Is there a fix?
// URL of PDF document
var url = "https://www.myFilePath/1Mpublic.pdf";
// Asynchronous download PDF
PDFJS.getDocument(url)
.then(function(pdf) {
return pdf.getPage(1);
})
.then(function(page) {
// Set scale (zoom) level
var scale = 1.2;
// Get viewport (dimensions)
var viewport = page.getViewport(scale);
// Get canvas#the-canvas
var canvas = document.getElementById('the-canvas');
// Fetch canvas' 2d context
var context = canvas.getContext('2d');
// Set dimensions to Canvas
canvas.height = viewport.height;
canvas.width = viewport.width;
// Prepare object needed by render method
var renderContext = {
canvasContext: context,
viewport: viewport
};
// Render PDF page
page.render(renderContext);
});
There are two things you can do. I tested and somehow it worked, but you will get a bigger memory consumption.
1 . Go to pdf.js and change the parameter MAX_GROUP_SIZE to like 8192 (double it for example) . Be sure to have your browser cache disable while testing.
You can force the getViewport to retrieve the image in better quality but like, I don't know how to say in English, compress it so a smaller size while showing:
// URL of PDF document
var url = "https://www.myFilePath/1Mpublic.pdf";
// Asynchronous download PDF
PDFJS.getDocument(url)
.then(function(pdf) {
return pdf.getPage(1);
})
.then(function(page) {
// Set scale (zoom) level
var scale = 1.2;
// Get viewport (dimensions)
var viewport = page.getViewport(scale);
// Get canvas#the-canvas
var canvas = document.getElementById('the-canvas');
// Fetch canvas' 2d context
var context = canvas.getContext('2d');
// Set dimensions to Canvas
var resolution = 2 ; // for example
canvas.height = resolution*viewport.height; //actual size
canvas.width = resolution*viewport.width;
canvas.style.height = viewport.height; //showing size will be smaller size
canvas.style .width = viewport.width;
// Prepare object needed by render method
var renderContext = {
canvasContext: context,
viewport: viewport,
transform: [resolution, 0, 0, resolution, 0, 0] // force it bigger size
};
// Render PDF page
page.render(renderContext);
});
enter code here
Hope it helps!
This code will help you, my issue was pdf was not rendering in crisp quality according with the responsiveness. So i searched , and modified my code like this. Now it works for rendering crisp and clear pdf according to the div size you want to give. `var loadingTask = pdfjsLib.getDocument("your_pdfurl");
loadingTask.promise.then(function(pdf) {
console.log('PDF loaded');
// Fetch the first page
var pageNumber = 1;
pdf.getPage(pageNumber).then(function(page) {
console.log('Page loaded');
var container = document.getElementById("container") //Container of the body
var wrapper = document.getElementById("wrapper");//render your pdf inside a div called wrapper
var canvas = document.getElementById('pdf');
var context = canvas.getContext('2d');
const pageWidthScale = container.clientWidth / page.view[2];
const pageHeightScale = container.clientHeight / page.view[3];
var scales = { 1: 3.2, 2: 4 },
defaultScale = 4,
scale = scales[window.devicePixelRatio] || defaultScale;
var viewport = page.getViewport({ scale: scale });
canvas.height = viewport.height;
canvas.width = viewport.width;
var displayWidth = Math.min(pageWidthScale, pageHeightScale);;
canvas.style.width = `${(viewport.width * displayWidth) / scale}px`;
canvas.style.height = `${(viewport.height * displayWidth) / scale}px`;
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function() {
console.log('Page rendered');
});
});
}, function(reason) {
// PDF loading error
console.error(reason);
});`

SlimDX Camera setup

Please, tell me what I'm doing wrongly:
that's my Camera class
public class Camera
{
public Matrix view;
public Matrix world;
public Matrix projection;
public Vector3 position;
public Vector3 target;
public float fov;
public Camera(Vector3 pos, Vector3 tar)
{
this.position = pos;
this.target = tar;
view = Matrix.LookAtLH(position, target, Vector3.UnitY);
projection = Matrix.PerspectiveFovLH(fov, 1.6f, 0.001f, 100.0f);
world = Matrix.Identity;
}
}
that's my Constant buffer struct:
struct ConstantBuffer
{
internal Matrix mWorld;
internal Matrix mView;
internal Matrix mProjection;
};
and here I'm drawing the triangle and setting camera:
x+= 0.01f;
camera.position = new Vector3(x, 0.0f, 0.0f);
camera.view = Matrix.LookAtLH(camera.position, camera.target, Vector3.UnitY);
camera.projection = Matrix.PerspectiveFovLH(camera.fov, 1.6f, 0.0f, 100.0f);
var buffer = new Buffer(device, new BufferDescription
{
Usage = ResourceUsage.Default,
SizeInBytes = sizeof(ConstantBuffer),
BindFlags = BindFlags.ConstantBuffer
});
////////////////////////////// camera setup
ConstantBuffer cb;
cb.mProjection = Matrix.Transpose(camera.projection);
cb.mView = Matrix.Transpose(camera.view);
cb.mWorld = Matrix.Transpose(camera.world);
var data = new DataStream(sizeof(ConstantBuffer), true, true);
data.Write(cb);
data.Position = 0;
context.UpdateSubresource(new DataBox(0, 0, data), buffer, 0);
//////////////////////////////////////////////////////////////////////
// set the shaders
context.VertexShader.Set(vertexShader);
context.PixelShader.Set(pixelShader);
// draw the triangle
context.Draw(4, 0);
swapChain.Present(0, PresentFlags.None);
Please, if you can see what's wrong, tell me! :) I have spent two days writing this already..
Attempt the second:
#paiden I initialized fov now ( thanks very much :) ) but still no effect (now it's fov = 1.5707963267f;) and #Nico Schertler , thank you too, I put it in use by
context.VertexShader.SetConstantBuffer(buffer, 0);
context.PixelShader.SetConstantBuffer(buffer, 0);
but no effect still... probably my .fx file is wrong? for what purpose do I need this:
cbuffer ConstantBuffer : register( b0 ) { matrix World; matrix View; matrix Projection; }
Attepmpt the third:
#MHGameWork
Thank you very much too, but no effect still ;)
If anyone has 5 minutes time, I can just drop source code to his/her e-mail and then we will publish the answer... I guess it will help much to some newbies like me :)
unsafe
{
x+= 0.01f;
camera.position = new Vector3(x, 0.0f, 0.0f);
camera.view = Matrix.LookAtLH(camera.position, camera.target, Vector3.UnitY);
camera.projection = Matrix.PerspectiveFovLH(camera.fov, 1.6f, 0.01f, 100.0f);
var buffer = new Buffer(device, new BufferDescription
{
Usage = ResourceUsage.Default,
SizeInBytes = sizeof(ConstantBuffer),
BindFlags = BindFlags.ConstantBuffer
});
THE PROBLEM NOW - I SEE MY TRIANGLE BUT THE CAMERA DOESN'T MOVE
You have set your camera's nearplane to 0. This makes all the value in your matrix divide by zero, so you get a matrix filled with 'NAN's
Use a near plane value of about 0.01 in your case, it will solve the problem
I hope you still need help. Here is my camera class, which can be used, and can be easily moved around the scene using mouse/keyboard.
http://pastebin.com/JtiUSiHZ
Call the "TakeALook()" method in each frame (or when you move the camera).
You can move around it with the "CameraMove" method. It takes a Vector3 - where you want to move your camera (dont give it huge values, I use 0,001f for each frame)
And with the "CameraRotate()" you can turn it around - it take a Vector2 as a Left-Right and Up-Down rotation.
Its pretty easy. I use EventHandlers to call there two function, but feel free to edit as you wish.

how to make alpha part of movieClip non-clickable (actionscript starling)?

I am using Starling.
I can't figure out how to make alpha part of bitmap non-clickable - say I have a rabbit in center and alpha around.
first i embed the bitmap:
[Embed(source="assets/stuff.xml", mimeType="application/octet-stream")]public static const Axml:Class;
[Embed(source="assets/stuff.png")]public static const Apng:Class;
Then create the bitmap atlass (spritesheet):
var tx1:Texture = Texture.fromBitmap(new Apng());
var xm1:XML = XML(new Axml());
var atlas:TextureAtlas = new TextureAtlas(tx1, xm1);
I made a MovieClip and add bitmap to it like that:
var movie:MovieClip = new MovieClip(atlas.getTextures("rabbit_run_"), 18);
addChild(movie);
movie.play();
starling.core.Starling.juggler.add(movie);
but when I click on it even on alpha part movieClip becomes "clicked".
I only need rabbit itself to be clickable, not around it!
How to make alpha non-clickable? Thanks
1: You cannot make image clickable in one area and nonclickable in another. But you can get color of pixel under mouse and ignore ckicks over transparent pixels
import flash.events.MouseEvent;
import flash.display.BitmapData;
var rabbitBitmap:BitmapData = new BitmapData(rabbit.width, rabbit.height, true, 0xFFFFFFFF);
rabbitBitmap.draw(rabbit);
addEventListener(MouseEvent.MOUSE_MOVE, mmh)
rabbit.addEventListener(MouseEvent.CLICK, mch)
rabbit.buttonMode = true;
function mmh(e:MouseEvent):void {
rabbit.useHandCursor = getAlpha() != 255;
}
function mch(e:MouseEvent):void {
if (getAlpha() != 255) {
// ... do someth
}
}
function getAlpha ():int {
var rgba:uint = rabbitBitmap.getPixel32(rabbit.mouseX, rabbit.mouseY);
return rgba & 0xff;
}
2: Use vector graphics for your rabbit :)

Resources