QOpenGLFramebufferObject's image not updating - qt5

The following is the code for my widget which subclasses QOpenGLWidget. What should be happening is that the framebuffer object flashes between white and black between each frame, but it only displays white, which tells me it's rendering once and then never updating.
void GLWidget::paintEvent(QPaintEvent *event)
{
QRect sourceRect(0, 0, 320, 240);
QSize sourceSize = sourceRect.size();
QOpenGLFramebufferObject sourceBuffer(sourceSize);
sourceBuffer.bind();
QOpenGLPaintDevice device(sourceSize);
QPainter sourcePainter;
sourcePainter.begin(&device);
static bool flash = true;
if (flash)
{
sourcePainter.fillRect(sourceRect, QBrush(Qt::white));
}
else
{
sourcePainter.fillRect(sourceRect, QBrush(Qt::black));
}
flash = !flash;
sourcePainter.end();
sourceBuffer.release();
QPainter destinationPainter;
destinationPainter.begin(this);
destinationPainter.setRenderHint(QPainter::Antialiasing);
destinationPainter.fillRect(event->rect(), QBrush(Qt::black));
int destinationWidth = event->rect().width();
int destinationHeight = event->rect().height();
QImage sourceImage = sourceBuffer.toImage();
//sourceImage.save(&process, "bmp");
QImage scaledSourceImage = sourceImage.scaled(destinationWidth, destinationHeight, Qt::KeepAspectRatio);
int translationX = destinationWidth - scaledSourceImage.width();
int translationY = destinationHeight - scaledSourceImage.height();
destinationPainter.translate(translationX / 2, translationY / 2);
destinationPainter.drawImage(0, 0, scaledSourceImage);
destinationPainter.end();
}
Am I using the framebuffer object correctly here? Also is there a more appropriate way to draw something offscreen and then display it in a QOpenGLWidget?

Related

First Person Camera controls

I have recently started up a 3d first person shooter game in Monogame and I am having some issues with the camera controls, I am unable to figure out how I make the camera slowly turn on it's X axis when I hold down the left/right arrow keys.
At the minute, the code I have is as follows:
Matrix view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(0, 0, 0), Vector3.UnitZ);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 600f, 0.1f, 100f);
And then down in the update section I have this:
if (kb.IsKeyDown(Keys.Left))
{
view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(-2, -2, -2), Vector3.UnitZ);
}
The issue is at the minute this code simply moves the camera to the side a little then stops. I am unsure on how to keep having it move until I let go of the key?
The entire of my code will be shown below incase I forgot something (the floor verts currently don't work and the names related to a ship is due to me working from a tutorial):
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game1
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Model model;
Vector3 ship1Location = new Vector3(40, 0, 0);
Vector3 ship2Location = new Vector3(20, 0, 0);
Matrix view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(0, 0, 0), Vector3.UnitZ);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 600f, 0.1f, 100f);
VertexPositionTexture[] floorVerts;
BasicEffect effect;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
floorVerts = new VertexPositionTexture[6];
floorVerts[0].Position = new Vector3(-20, -20, 0);
floorVerts[1].Position = new Vector3(-20, 20, 0);
floorVerts[2].Position = new Vector3(20, -20, 0);
floorVerts[3].Position = floorVerts[1].Position;
floorVerts[4].Position = new Vector3(20, 20, 0);
floorVerts[5].Position = floorVerts[2].Position;
effect = new BasicEffect(graphics.GraphicsDevice);
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
model = Content.Load<Model>("health2");
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
Matrix ship1WorldMatrix = Matrix.CreateTranslation(ship1Location);
Matrix ship2WorldMatrix = Matrix.CreateTranslation(ship2Location);
if (IsCollision(model, ship1WorldMatrix, model, ship2WorldMatrix))
{
ship1Location = new Vector3(0, -20, 0);
}
KeyboardState kb = Keyboard.GetState();
if (kb.IsKeyDown(Keys.A))
{
ship1Location += new Vector3(-0.1f, 0, 0);
}
if (kb.IsKeyDown(Keys.Left))
{
view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(-2, -2, -2), Vector3.UnitZ);
}
ship2Location += new Vector3(0, 0, 0);
base.Update(gameTime);
}
private bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2)
{
for (int meshIndex1 = 0; meshIndex1 < model1.Meshes.Count; meshIndex1++)
{
BoundingSphere sphere1 = model1.Meshes[meshIndex1].BoundingSphere;
sphere1 = sphere1.Transform(world1);
for (int meshIndex2 = 0; meshIndex2 < model2.Meshes.Count; meshIndex2++)
{
BoundingSphere sphere2 = model2.Meshes[meshIndex2].BoundingSphere;
sphere2 = sphere2.Transform(world2);
if (sphere1.Intersects(sphere2))
return true;
}
}
return false;
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
DrawGround();
Matrix ship1WorldMatrix = Matrix.CreateTranslation(ship1Location);
Matrix ship2WorldMatrix = Matrix.CreateTranslation(ship2Location);
DrawModel(model, ship1WorldMatrix, view, projection);
DrawModel(model, ship2WorldMatrix, view, projection);
base.Draw(gameTime);
}
void DrawGround()
{
// The assignment of effect.View and effect.Projection
// are nearly identical to the code in the Model drawing code.
float aspectRatio =
graphics.PreferredBackBufferWidth / (float)graphics.PreferredBackBufferHeight;
float fieldOfView = Microsoft.Xna.Framework.MathHelper.PiOver4;
float nearClipPlane = 1;
float farClipPlane = 200;
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
fieldOfView, aspectRatio, nearClipPlane, farClipPlane);
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
graphics.GraphicsDevice.DrawUserPrimitives(
// We’ll be rendering two trinalges
PrimitiveType.TriangleList,
// The array of verts that we want to render
floorVerts,
// The offset, which is 0 since we want to start
// at the beginning of the floorVerts array
0,
// The number of triangles to draw
2);
}
}
private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.AmbientLightColor = new Vector3(2f, 0, 0);
effect.World = world;
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
}
}
Since the camera's position and the point it is looking at are necessary parameters to create a view matrix, you can simply rotate (think orbit) the LookAt camLookAt around the camPosition like this:
//declare class scope variables
Vector3 camPosition = new Vector3(60, 20, 10);//your starting camera position
Vector3 camLookAt = Vector3.Zero;//your starting camera focus point (look at)
Vector2 camUp = Vector3.Up;
float camYawRate = 0.004f;//set to taste
//in the Update method
float elapsed = gameTime.ElapsedGameTime.TotalSeconds;
//later in the method...
if (kb.IsKeyDown(Keys.Left))
{
camLookAt = Vector3.Transform(camLookAt - camPosition,Matrix.CreateRotationY(-camYawRate * elapsedTime)) + camPosition;);//remove the - sign from camYawRate to rotate to the right (or vice versa)
view = Matrix.CreateLookAt(camPosition, camLookAt, camUp);
}
And that's it, give it a shot. Add another similar block to rotate to the right.

How do you convert a Uint8ClampedArray string to an android Bitmap?

Im using a custom WebView component in android to display an html page with HTML5 canvas.
Due to lack of WebView support for the getDataUrl from canvas function,
im passing the getImageData.data Uint8ClampedArray to webview through web view JavascriptInterface.
It saves the images as a dark blue image. Any ideias?
// html
...canvas id="canvas" width="20px" height="20px"...
// javascript
imgData=context.getImageData(0,0,20,20);
webViewArray = Array.prototype.slice.call(imgData.data);
webviewApp.procData(webViewArraySTRING);
// android
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int[] results = new int[1600];
int[] icnt = 0;
int width = 20;
int height = 20;
int pos = 0, end;
while((end = webViewArraySTRING.indexOf(',', pos)) >= 0) {
results[icnt] = Integer.parseInt(webViewArraySTRING.substring(pos,end));
pos = end + 1;
icnt++;
}
// create image - tried using ARGB_8888, ARGB_4444
System.out.println("results size:" + icnt); // prints out 1599
Bitmap bitmap = Bitmap.createBitmap(width,height,Bitmap.Config.RGB_565);
bitmap.setPixels(results, 0, width, 0, 0, width, height);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
// save image `
FileOutputStream os = new FileOutputStream(file,true);
os.write(boas.toByteArray());

Monotouch: Generating UIImage from PDF leaking entire document size

In a Monotouch application the following code converts a page from a PDF document to a UIImage. It works, but it doesn't correctly dispose the PDF document.
public class KillerLeak
{
public static void RunOnce()
{
using (CGPDFDocument doc = CGPDFDocument.FromFile("DMSWorkbook.pdf"))
{
Console.WriteLine("Opened: pages={0}", doc.Pages);
UIImage img = GetThumbImage(doc, 1000, 1);
img.Dispose();
}
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
}
private static UIImage GetThumbImage(CGPDFDocument document, float thumbContentSize, int pageNumber)
{
if ((pageNumber <= 0) || (pageNumber > document.Pages)) {
return null;
}
// Calc page view size
SizeF pageSize = new SizeF(768, 1024);
if (pageSize.Width % 2 > 0) {
pageSize.Width--;
}
if (pageSize.Height % 2 > 0) {
pageSize.Height--;
}
// Calc target size
var targetSize = new Size((int)pageSize.Width, (int)pageSize.Height);
// Draw page on CGImage
CGImage pageImage;
using (CGColorSpace rgb = CGColorSpace.CreateDeviceRGB()) {
using (CGBitmapContext context = new CGBitmapContext(null, targetSize.Width, targetSize.Height, 8, 0, rgb, CGBitmapFlags.ByteOrder32Little | CGBitmapFlags.NoneSkipFirst)) {
using (CGPDFPage pdfPage = document.GetPage(pageNumber)) {
RectangleF thumbRect = new RectangleF(0.0f, 0.0f, targetSize.Width, targetSize.Height);
context.SetFillColor(1.0f, 1.0f, 1.0f, 1.0f);
context.FillRect(thumbRect);
context.ConcatCTM(pdfPage.GetDrawingTransform(CGPDFBox.Crop, thumbRect, 0, true));
context.SetRenderingIntent(CGColorRenderingIntent.Default);
context.InterpolationQuality = CGInterpolationQuality.Default;
context.DrawPDFPage(pdfPage);
pageImage = context.ToImage();
}
}
}
UIImage result = UIImage.FromImage(pageImage);
pageImage.Dispose();
return result;
}
}
If I comment out the DrawPDFPage(...) line, the code doesn't leak. Is this a Monotouch bug or am I doing something wrong?
Turns out the leak is not related to Monotouch as I previously thought. The leak does not occur on IOS 5, but does leak under the next version of IOS which is still under beta. I've tested using the same code written in Monotouch and Objective-C and they both exhibit the same behavior.

Getting the area occupied by a certain color onscreen - iOS

I'm trying to do something similar to what is asked in this question, but I don't really understand the answer given to that question and I'm not sure if it is what I need.
What I need is simple, though I'm not so sure it's easy. I want to calculate the number of pixels on the screen that are a certain color. I understand that each 'pixel' that we see is actually a combination of pixels of different colors that appear to be, say, green. So what I need is that actual color- the one that the user sees.
For example, if I created a UIView, set the background color to [UIColor greenColor], and set its dimensions to half of the area of the screen (we can assume that the status bar is hidden for simplicity and that we are on an iPhone), I would expect this 'magic method' to return 240 * 160 or 38,400- half the area of the screen.
I don't expect anyone to write out this 'magic method,' but I'd like to know
a) If this is possible
b) If so, if it be done in almost-realtime
c) If so again, where to start. I've heard it can be done with OpenGL, but I have no experience in that area.
Here is my solution, thanks to Radif Sharafullin:
int pixelsFromImage(UIImage *inImage) {
CGSize s = inImage.size;
const int width = s.width;
const int height = s.height;
unsigned char* pixelData = malloc(width * height);
int pixels = 0;
CGContextRef context = CGBitmapContextCreate(pixelData,
width,
height,
8,
width,
NULL,
kCGImageAlphaOnly);
CGContextClearRect(context, CGRectMake(0, 0, width, height));
CGContextDrawImage(context, CGRectMake(0, 0, width, height), inImage.CGImage );
CGContextRelease(context);
for(int idx = 0; idx < width * height; ++idx) {
if(pixelData[idx]) {
++pixels;
}
}
free(pixelData);
return pixels;
}
it is possible. I've done something similar to calculate the percentage of transparent pixels, but since I needed the rough estimate, I was not looking at each pixel but at every tenth pixel, step variable in the code below.
BOOL isImageErased(UIImage *inImage, float step, int forgivenessCount){
CGSize s = inImage.size;
int width = s.width;
int height = s.height;
unsigned char* pixelData = malloc( width * height );
int forgivenessCounter=0;
CGContextRef context = CGBitmapContextCreate ( pixelData,
width,
height,
8,
width,
NULL,
kCGImageAlphaOnly );
CGContextClearRect(context, CGRectMake(0, 0, width, height));
CGContextDrawImage( context, CGRectMake(0, 0, width, height), inImage.CGImage );
CGContextRelease( context );
for (int x=0; x<width; x=x+step) {
for (int y=0; y<height; y=y+step) {
if(pixelData[y * width + x]) {
forgivenessCounter++;
if (forgivenessCounter==forgivenessCount) {
free(pixelData);
return FALSE;
}
};
}
}
free( pixelData );
return TRUE;}
I believe this code can be used for your purpose if you pass a preprocessed grayscaled image or modify the kCGImageAlphaOnly setting of the API.
Hope that helps
eric.mitchell solution written in Swift 3
func pixelsFromImage(inImage: UIImage) -> Int {
let width = Int(inImage.size.width)
let height = Int(inImage.size.height)
let bitmapBytesPerRow = width
let bitmapByteCount = bitmapBytesPerRow * height
let pixelData = UnsafeMutablePointer<UInt8>.allocate(capacity: bitmapByteCount)
let colorSpace = CGColorSpaceCreateDeviceGray()
let context = CGContext(data: pixelData,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: bitmapBytesPerRow,
space: colorSpace,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.alphaOnly.rawValue).rawValue)!
let rect = CGRect(x: 0, y: 0, width: width, height: height)
context.clear(rect)
context.draw(inImage.cgImage!, in: rect)
var pixels = 0
for x in 0...width {
for y in 0...height {
if pixelData[y * width + x] > 0 {
pixels += 1
}
}
}
free(pixelData)
return pixels
}

Change text fill colour when rect is overlayed - Processing

I have this little animation here that animates in a repeated seamless pattern.
I have text, colored white, in the middle of the canvas that the looped shapes pass over. What I am trying to work out is when the white bars pass over the text it turns black. So as half the white bar goes over the T of "Text", half the T would be black and the half not covered would be still white on a diagonal.
Would this be done with splitting up the letters? By doing masking, or using vector images?
Here is a graphic example of what I'm trying to achieve.
http://imm.io/2Qsb
drawLine wob1;
drawLine wob2;
drawLine wob3;
drawLine wob4;
drawLine wob5;
PFont helv;
drawText title;
void setup() {
//frame.setResizable(true);
size(320, 480);
smooth();
frameRate(50);
wob1 = new drawLine(0);
wob2 = new drawLine(200);
wob3 = new drawLine(400);
wob4 = new drawLine(600);
wob5 = new drawLine(800);
title = new drawText();
}
void draw() {
background(#000000);
wob1.increment();
wob1.display(#ffffff);
wob1.pos();
wob1.boundary();
wob2.increment();
wob2.display(#ffffff);
wob2.boundary();
wob3.increment();
wob3.display(#ffffff);
wob3.boundary();
wob4.increment();
wob4.display(#ffffff);
wob4.boundary();
wob5.increment();
wob5.display(#ffffff);
wob5.boundary();
title.rendertitle(#ffffff;
}
class drawLine {
int x = -480;
int y = 0;
int count;
drawLine(int offset) {
this.x = this.x + offset;
}
void increment() {
this.x += 3;
this.y += 4;
}
void display(int col) {
//noStroke();
fill(col);
//translate(0,0);
rectMode(CENTER);
rotate(-PI/3.0);
rect(x,y,100,3000);
rotate(PI/3.0);
}
void pos() {
println(this.x);
//if(this.x >= -218 && this.x <= 207){ colr = #000000; } else { colr = #ffffff; }
}
void boundary() {
if(this.x > 520) {
this.x = -480; this.y = 0;
}
}
}
class drawText {
drawText() {
helv = loadFont("Helvetica-Bold.vlw");
}
void rendertitle(int colr) {
fill(colr);
textFont(helv, 30);
text("Text goes here", width/2, height/2, 240, 50);
}
}
I worked out a solution using two generated images. The first one imgText contains only text (white) in front of black background. The second one imgMaskfunctions as mask and therefore contains the screen line pattern. It's fine to generate the first (text image) only once within the setup() part; because your type doesn't change/move or transform. The mask image has to be updated every frame if you want to achieve the effect of "scanning" lines. This happens every draw() loop through the shift of the offset parameter.
The rest is pretty basic; clear the background every frame and draw the inverted version of imgText before you display the actual masked image.
PImage imgText;
PImage imgMask;
PFont font;
int barHeight = 20;
float offset = 0;
float offsetTick = 0.3;
void setup () {
size (320, 240);
noStroke ();
smooth ();
font = createFont ("Helvetica-Bold.vlw", 18);
// Create new image containing only
// the white text infront of an empty
// black sketch background
background (0);
fill (255);
textFont (font);
textAlign (CENTER);
text ("Text goes here", width/2, height/2);
imgText = createImage (width, height, ARGB);
copySketchIntoImage (imgText);
// Create empty mask image
imgMask = createImage (width, height, ARGB);
}
void draw () {
// Move the scan lines further down
// by increasing offset
offset += offsetTick;
if (offset > barHeight * 2) {
offset = 0;
}
// Update the text mask image
updateMask (offset);
imgText.mask (imgMask);
// Draw the inverted background+text
background (255);
fill (0);
text ("Text goes here", width/2, height/2);
// Display the masked version of the
// text image above the inverted background
image (imgText, 0, 0);
}
void updateMask (float theOffset) {
background (0);
fill (255);
for (float i=theOffset - barHeight; i < height; i += barHeight * 2) {
rect (0, i, width, barHeight);
}
copySketchIntoImage (imgMask);
}
// Method to copy all sketch pixels
// into an existing PImage.
void copySketchIntoImage (PImage theDestImage) {
loadPixels ();
theDestImage.loadPixels ();
for (int i=0; i < pixels.length; i++) {
theDestImage.pixels[i] = pixels[i];
}
theDestImage.updatePixels ();
}