How to blur background image in Fabric.js - fabricjs

I want to overlay background image with some text, in Fabric.js is there a way to blur the background so the text will become more readable?
I have tried filter, but could only change the background image to grayscale, blur didn't seem to have any effect.
Thanks in advance.

Perhaps with filter blur :
https://developer.mozilla.org/fr/docs/Web/API/CanvasRenderingContext2D/filter
Example : http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html

I have created this gist, it adds stack blurring as a filter to fabric class.
https://gist.github.com/human-a/25b7f58565b89de4e999ef2f4de1982c
/**
* Stack blur filter for fabricjs
* Example:
* obj.filters.push(new fabric.Image.filters.StackBlur(6));
* obj.applyFilters(canvas.renderAll.bind(canvas));
*
* Heavily inspired by:
* https://gist.github.com/pierrickouw/2ab679159beee9d80ca6
* http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
* uses stackBlurCanvasRGBA function but could be swapped be stackBlurCanvasRGB
* #see: http://www.quasimondo.com/StackBlurForCanvas/StackBlur.js
*/
(function() {
var fabric = window.fabric,
extend = fabric.util.object.extend;
var mul_table = [
512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,
454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,
482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,
437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,
497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,
320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,
446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,
329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,
505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,
399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,
324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,
268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,
451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,
385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,
332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,
289,287,285,282,280,278,275,273,271,269,267,265,263,261,259
];
var shg_table = [
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
];
function BlurStack() {
this.r = 0;
this.g = 0;
this.b = 0;
this.a = 0;
this.next = null;
}
fabric.Image.filters.StackBlur = fabric.util.createClass(fabric.Image.filters.BaseFilter,{
/**
* Filter type
*/
type: 'StackBlur',
/**
* Constructor
*/
initialize: function(radius) { //radius of the blur
this.radius = radius || 0;
if(this.radius > 180) {
this.radius = 180;
}
if(this.radius < 1) {
this.radius = 0;
}
},
/**
* Applies blur to canvas element
*/
applyTo: function(canvas) {
// Don't apply blur if it's zero
if (!this.radius) return;
var radius = this.radius;
var width = canvas.width;
var height = canvas.height;
var context = canvas.getContext("2d");
var imageData;
imageData = context.getImageData( 0, 0, width, height );
var pixels = imageData.data;
var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, a_sum,
r_out_sum, g_out_sum, b_out_sum, a_out_sum,
r_in_sum, g_in_sum, b_in_sum, a_in_sum,
pr, pg, pb, pa, rbs;
var div = radius + radius + 1;
var widthMinus1 = width - 1;
var heightMinus1 = height - 1;
var radiusPlus1 = radius + 1;
var sumFactor = radiusPlus1 * ( radiusPlus1 + 1 ) / 2;
var stackStart = new BlurStack();
var stack = stackStart;
for ( i = 1; i < div; i++ ) {
stack = stack.next = new BlurStack();
if ( i === radiusPlus1 ) var stackEnd = stack;
}
stack.next = stackStart;
var stackIn = null;
var stackOut = null;
yw = yi = 0;
var mul_sum = mul_table[radius];
var shg_sum = shg_table[radius];
for ( y = 0; y < height; y++ ) {
r_in_sum = g_in_sum = b_in_sum = a_in_sum = r_sum = g_sum = b_sum = a_sum = 0;
r_out_sum = radiusPlus1 * ( pr = pixels[yi] );
g_out_sum = radiusPlus1 * ( pg = pixels[yi+1] );
b_out_sum = radiusPlus1 * ( pb = pixels[yi+2] );
a_out_sum = radiusPlus1 * ( pa = pixels[yi+3] );
r_sum += sumFactor * pr;
g_sum += sumFactor * pg;
b_sum += sumFactor * pb;
a_sum += sumFactor * pa;
stack = stackStart;
for( i = 0; i < radiusPlus1; i++ ) {
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack.a = pa;
stack = stack.next;
}
for( i = 1; i < radiusPlus1; i++ ) {
p = yi + (( widthMinus1 < i ? widthMinus1 : i ) << 2 );
r_sum += ( stack.r = ( pr = pixels[p])) * ( rbs = radiusPlus1 - i );
g_sum += ( stack.g = ( pg = pixels[p+1])) * rbs;
b_sum += ( stack.b = ( pb = pixels[p+2])) * rbs;
a_sum += ( stack.a = ( pa = pixels[p+3])) * rbs;
r_in_sum += pr;
g_in_sum += pg;
b_in_sum += pb;
a_in_sum += pa;
stack = stack.next;
}
stackIn = stackStart;
stackOut = stackEnd;
for ( x = 0; x < width; x++ ) {
pixels[yi+3] = pa = (a_sum * mul_sum) >> shg_sum;
if ( pa !== 0 )
{
pa = 255 / pa;
pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa;
pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa;
pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa;
} else {
pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0;
}
r_sum -= r_out_sum;
g_sum -= g_out_sum;
b_sum -= b_out_sum;
a_sum -= a_out_sum;
r_out_sum -= stackIn.r;
g_out_sum -= stackIn.g;
b_out_sum -= stackIn.b;
a_out_sum -= stackIn.a;
// eslint-disable-next-line
p = ( yw + ( ( p = x + radius + 1 ) < widthMinus1 ? p : widthMinus1 ) ) << 2;
r_in_sum += ( stackIn.r = pixels[p]);
g_in_sum += ( stackIn.g = pixels[p+1]);
b_in_sum += ( stackIn.b = pixels[p+2]);
a_in_sum += ( stackIn.a = pixels[p+3]);
r_sum += r_in_sum;
g_sum += g_in_sum;
b_sum += b_in_sum;
a_sum += a_in_sum;
stackIn = stackIn.next;
r_out_sum += ( pr = stackOut.r );
g_out_sum += ( pg = stackOut.g );
b_out_sum += ( pb = stackOut.b );
a_out_sum += ( pa = stackOut.a );
r_in_sum -= pr;
g_in_sum -= pg;
b_in_sum -= pb;
a_in_sum -= pa;
stackOut = stackOut.next;
yi += 4;
}
yw += width;
}
for ( x = 0; x < width; x++ ) {
g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0;
yi = x << 2;
r_out_sum = radiusPlus1 * ( pr = pixels[yi]);
g_out_sum = radiusPlus1 * ( pg = pixels[yi+1]);
b_out_sum = radiusPlus1 * ( pb = pixels[yi+2]);
a_out_sum = radiusPlus1 * ( pa = pixels[yi+3]);
r_sum += sumFactor * pr;
g_sum += sumFactor * pg;
b_sum += sumFactor * pb;
a_sum += sumFactor * pa;
stack = stackStart;
for( i = 0; i < radiusPlus1; i++ )
{
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack.a = pa;
stack = stack.next;
}
yp = width;
for( i = 1; i <= radius; i++ )
{
yi = ( yp + x ) << 2;
r_sum += ( stack.r = ( pr = pixels[yi])) * ( rbs = radiusPlus1 - i );
g_sum += ( stack.g = ( pg = pixels[yi+1])) * rbs;
b_sum += ( stack.b = ( pb = pixels[yi+2])) * rbs;
a_sum += ( stack.a = ( pa = pixels[yi+3])) * rbs;
r_in_sum += pr;
g_in_sum += pg;
b_in_sum += pb;
a_in_sum += pa;
stack = stack.next;
if( i < heightMinus1 )
{
yp += width;
}
}
yi = x;
stackIn = stackStart;
stackOut = stackEnd;
for ( y = 0; y < height; y++ )
{
p = yi << 2;
pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum;
if ( pa > 0 )
{
pa = 255 / pa;
pixels[p] = ((r_sum * mul_sum) >> shg_sum ) * pa;
pixels[p+1] = ((g_sum * mul_sum) >> shg_sum ) * pa;
pixels[p+2] = ((b_sum * mul_sum) >> shg_sum ) * pa;
} else {
pixels[p] = pixels[p+1] = pixels[p+2] = 0;
}
r_sum -= r_out_sum;
g_sum -= g_out_sum;
b_sum -= b_out_sum;
a_sum -= a_out_sum;
r_out_sum -= stackIn.r;
g_out_sum -= stackIn.g;
b_out_sum -= stackIn.b;
a_out_sum -= stackIn.a;
// eslint-disable-next-line
p = ( x + (( ( p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1 ) * width )) << 2;
r_sum += ( r_in_sum += ( stackIn.r = pixels[p]));
g_sum += ( g_in_sum += ( stackIn.g = pixels[p+1]));
b_sum += ( b_in_sum += ( stackIn.b = pixels[p+2]));
a_sum += ( a_in_sum += ( stackIn.a = pixels[p+3]));
stackIn = stackIn.next;
r_out_sum += ( pr = stackOut.r );
g_out_sum += ( pg = stackOut.g );
b_out_sum += ( pb = stackOut.b );
a_out_sum += ( pa = stackOut.a );
r_in_sum -= pr;
g_in_sum -= pg;
b_in_sum -= pb;
a_in_sum -= pa;
stackOut = stackOut.next;
yi += width;
}
}
context.putImageData( imageData, 0, 0 );
},
/**
* Returns object representation of an instance
*/
toObject: function() {
return extend(this.callSuper('toObject'), {
radius: this.radius
});
}
});
fabric.Image.filters.StackBlur.fromObject = function(object) {
return new fabric.Image.filters.StackBlur(object);
};
})()

Related

Nothing gets sent to Arduino from Processing

I have a problem where I kwow that my bluetooth module (HC-05) is connected to a processing sketch, but nothing ever gets sent from the processing sketch,why?
No error messages but the info never gets sent over because I never see it in Arduino, where it would be printed to the Serial Monitor.
Full Processing Code:
import processing.serial.*;
import controlP5.*;
Serial myPort;
ControlP5 cp5;
int slider1 = 0;
int slider2 = 0;
int slider3 = 0;
void setup() {
size(800, 800);
cp5 = new ControlP5(this);
PFont roboto = createFont("Roboto-Bold.ttf", 1, true);
ControlFont font = new ControlFont(roboto, 28);
Controller Aslider1 = cp5.addSlider("slider1")
.setPosition(85, 100)
.setCaptionLabel("Red")
.setRange(0, 255)
.setWidth(191)
.setHeight(50);
cp5.getController("slider1").getValueLabel().setFont(font).align(ControlP5.LEFT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
cp5.getController("slider1").getCaptionLabel().setFont(font).align(ControlP5.RIGHT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
Controller Aslider2 = cp5.addSlider("slider2")
.setPosition(301, 100)
.setCaptionLabel("Green")
.setRange(0, 255)
.setWidth(191)
.setHeight(50);
cp5.getController("slider2").getValueLabel().setFont(font).align(ControlP5.LEFT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
cp5.getController("slider2").getCaptionLabel().setFont(font).align(ControlP5.RIGHT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
Controller Aslider3 = cp5.addSlider("slider3")
.setPosition(517, 100)
.setCaptionLabel("Blue")
.setRange(0, 255)
.setWidth(191)
.setHeight(50);
cp5.getController("slider3").getValueLabel().setFont(font).align(ControlP5.LEFT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
cp5.getController("slider3").getCaptionLabel().setFont(font).align(ControlP5.RIGHT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
myPort = new Serial(this, "COM5", 9600);
}
void draw() {
background(255, 100, 100);
fill(255);
stroke(1);
rectMode(CENTER);
rect(width/2, 350, 200, 75);
fill(0);
textSize(32);
text("Send", width/2 - textWidth("Send") / 2, 350 + 10);
if (mouseX > width/2 - 100 && mouseX < width/2 + 100 && mouseY > 350 - 75/2 && mouseY < 350 + 75/2) {
if (mousePressed) {
fill(100);
stroke(1);
rectMode(CENTER);
rect(width/2, 350, 200, 75);
fill(0);
textSize(32);
text("Send", width/2 - textWidth("Send") / 2, 350 + 10);
} else {
fill(170);
stroke(1);
rectMode(CENTER);
rect(width/2, 350, 200, 75);
fill(0);
textSize(32);
text("Send", width/2 - textWidth("Send") / 2, 350 + 10);
}
}
}
void mouseReleased() {
if (mouseX > width/2 - 100 && mouseX < width/2 + 100 && mouseY > 350 - 75/2 && mouseY < 350 + 75/2) {
fill(100);
stroke(1);
rectMode(CENTER);
rect(width/2, 350, 200, 75);
fill(0);
textSize(32);
text("Send", width/2 - textWidth("Send") / 2, 350 + 10);
println(hex(color(int(slider1), int(slider2), int(slider3))).toString().substring(2));
myPort.write(hex(color(int(slider1), int(slider2), int(slider3))).toString().substring(2));
myPort.clear();
}
}
Full Arduino Code:
#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>
const int PIN = 6;
const int NUMPIXELS = 30;
const byte rxPin = 2;
const byte txPin = 3;
SoftwareSerial mySerial (rxPin, txPin);
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
unsigned long currentMillis;
unsigned long loopMillis;
unsigned long waitMillis;
int interval = 100;
int waitInterval = 0;
int redBrightness = 0;
int greenBrightness = 0;
int blueBrightness = 0;
bool wait = false;
bool goToRed = true;
bool goToOrange = false;
bool goToYellow = false;
bool goToGreen = false;
bool goToAqua = false;
bool goToPurple = false;
String hexValue;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
mySerial.begin(9600);
pixels.begin();
pixels.show();
}
void loop() {
if (mySerial.available() > 0) {
hexValue = mySerial.read();
Serial.println(hexValue);
if (hexValue != "shiftN" || hexValue != "shiftY") {
shiftMode = false;
// value is a hex
redBrightness = hexValue.substring(0, 2).toInt();
greenBrightness = hexValue.substring(2, 4).toInt();
greenBrightness = hexValue.substring(4, 6).toInt();
} else {
if (hexValue = "shiftY") {
shiftMode = true;
} else {
shiftMode = false;
}
}
}
pixels.show();
setColor(redBrightness, greenBrightness, blueBrightness);
}
void setColor(int red, int green, int blue) {
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, red, green, blue);
}
}
Thanks for the help, cheers!
Other links:
https://discourse.processing.org/t/nothing-gets-sent-to-arduino-from-processing/13654
https://arduino.stackexchange.com/questions/68233/nothing-gets-sent-to-arduino-from-processing
https://forum.arduino.cc/index.php?board=11.0
Assuming myPort is an output stream, it may be buffered. If so, try flushing it after writing:
myPort.flush();
check if hc-05 9600 baud or 38400 baud
For everyone wondering, here is updated code:
Arduino:
#include <SoftwareSerial.h>
#include <Adafruit_NeoPixel.h>
const int pin = 6;
const int numOfPixels = 30;
int r = 0;
int g = 0;
int b = 0;
Adafruit_NeoPixel pixels(numOfPixels, pin, NEO_GRB + NEO_KHZ800);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pixels.begin();
pixels.show();
pinMode(11, OUTPUT);
}
void loop() {
pixels.show();
// put your main code here, to run repeatedly:
if (Serial.available() > 0) {
Serial.println(String(Serial.read()));
r = Serial.parseInt();
g = Serial.parseInt();
b = Serial.parseInt();
setColor(r, g, b);
}
serialFlush();
}
void setColor(int red, int green, int blue) {
pixels.fill(pixels.Color(red, green, blue), 0, numOfPixels);
Serial.println("Red");
Serial.println(red);
Serial.println("Green");
Serial.println(green);
Serial.println("Blue");
Serial.println(blue);
}
void serialFlush() {
while (Serial.available() > 0) {
char t = Serial.read();
}
}
Processing:
import processing.serial.*;
import controlP5.*;
Serial myPort;
ControlP5 cp5;
int slider1 = 0;
int slider2 = 0;
int slider3 = 0;
void setup() {
size(800, 800);
cp5 = new ControlP5(this);
PFont roboto = createFont("Roboto-Bold.ttf", 1, true);
ControlFont font = new ControlFont(roboto, 28);
Controller Aslider1 = cp5.addSlider("slider1")
.setPosition(85, 100)
.setCaptionLabel("Red")
.setRange(0, 255)
.setWidth(191)
.setHeight(50);
cp5.getController("slider1").getValueLabel().setFont(font).align(ControlP5.LEFT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
cp5.getController("slider1").getCaptionLabel().setFont(font).align(ControlP5.RIGHT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
Controller Aslider2 = cp5.addSlider("slider2")
.setPosition(301, 100)
.setCaptionLabel("Green")
.setRange(0, 255)
.setWidth(191)
.setHeight(50);
cp5.getController("slider2").getValueLabel().setFont(font).align(ControlP5.LEFT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
cp5.getController("slider2").getCaptionLabel().setFont(font).align(ControlP5.RIGHT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
Controller Aslider3 = cp5.addSlider("slider3")
.setPosition(517, 100)
.setCaptionLabel("Blue")
.setRange(0, 255)
.setWidth(191)
.setHeight(50);
cp5.getController("slider3").getValueLabel().setFont(font).align(ControlP5.LEFT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
cp5.getController("slider3").getCaptionLabel().setFont(font).align(ControlP5.RIGHT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
myPort = new Serial(this, "COM4", 9600);
}
void draw() {
background(slider1, slider2, slider3);
fill(255);
stroke(1);
rectMode(CENTER);
rect(width/2, 350, 200, 75);
fill(0);
textSize(32);
text("Send", width/2 - textWidth("Send") / 2, 350 + 10);
if (mouseX > width/2 - 100 && mouseX < width/2 + 100 && mouseY > 350 - 75/2 && mouseY < 350 + 75/2) {
if (mousePressed) {
fill(100);
stroke(1);
rectMode(CENTER);
rect(width/2, 350, 200, 75);
fill(0);
textSize(32);
text("Send", width/2 - textWidth("Send") / 2, 350 + 10);
} else {
fill(170);
stroke(1);
rectMode(CENTER);
rect(width/2, 350, 200, 75);
fill(0);
textSize(32);
text("Send", width/2 - textWidth("Send") / 2, 350 + 10);
}
}
}
void mouseReleased() {
if (mouseX > width/2 - 100 && mouseX < width/2 + 100 && mouseY > 350 - 75/2 && mouseY < 350 + 75/2) {
fill(100);
stroke(1);
rectMode(CENTER);
rect(width/2, 350, 200, 75);
fill(0);
textSize(32);
text("Send", width/2 - textWidth("Send") / 2, 350 + 10);
myPort.write(str(slider1) + " " + str(slider2) + " " + str(slider3));
println(str(slider1) + " " + str(slider2) + " " + str(slider3));
}
}
Then look at this link:
https://forum.arduino.cc/index.php?topic=634061.0

WebGL draw perspective view volume

I'm trying to calculate the 8 (4+4) vertices of a view volume's plane : near and far.
I need this vertices to draw, in webGL, the view volume of a camera.
So far I managed to calculate them by using trigonometry from each perspective but somehow the result does not seem accurate when I draw the vertices.
I reached this equations for vertices so far:
y = sqrt(hypotenuse^2 - plane^2)
x = sqrt(hypotenuse^2 - plane^2)
z = plane (near or far)
Can anyone help? Thank you in advance.
you can just project a standard cube through an inverse projection matrix.
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const vs = `
attribute vec4 position;
uniform mat4 u_worldViewProjection;
void main() {
gl_Position = u_worldViewProjection * position;
}
`;
const fs = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const arrays = {
position: [
-1, 1, -1,
1, 1, -1,
1, -1, -1,
-1, -1, -1,
-1, 1, 1,
1, 1, 1,
1, -1, 1,
-1, -1, 1,
],
indices: [
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
],
};
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
let projectionToViewWith;
{
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.5;
const zFar = 100;
projectionToViewWith = m4.perspective(fov, aspect, zNear, zFar);
}
let projectionToBeViewed;
{
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 2;
const zFar = 10;
projectionToBeViewed = m4.perspective(fov, aspect, zNear, zFar);
}
const inverseProjectionToBeViewed = m4.inverse(projectionToBeViewed);
const radius = 20;
const eye = [Math.sin(time) * radius, 4, Math.cos(time) * radius];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projectionToViewWith, view);
const worldViewProjection = m4.multiply(
viewProjection,
inverseProjectionToBeViewed);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, {
u_worldViewProjection: worldViewProjection,
});
twgl.drawBufferInfo(gl, bufferInfo, gl.LINES);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
To get the points of the 8 corners you just have to do a reverse projection. The projection matrix takes the space of the frustum that is fovy tall, fovy * aspect wide, starting at -zNear and ending at -zFar and converting that space to -1 <-> +1 box after the perspective divide.
To go backward and compute the points of that box we just project a -1 to +1 box through the inverse projection matrix and do the perpective divide again (which is exactly what's happening in the example above, we're just doing it all in the GPU)
So, we pull it out of the GPU and do it in JavaScript
[
[-1, 1, -1],
[ 1, 1, -1],
[ 1, -1, -1],
[-1, -1, -1],
[-1, 1, 1],
[ 1, 1, 1],
[ 1, -1, 1],
[-1, -1, 1],
].forEach((point) => {
console.log(m4.transformPoint(inverseProjectionMatrix, point));
});
Here's an example.
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const vs = `
attribute vec4 position;
uniform mat4 u_worldViewProjection;
void main() {
gl_Position = u_worldViewProjection * position;
gl_PointSize = 10.;
}
`;
const fs = `
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const positions = [
-1, 1, -1,
1, 1, -1,
1, -1, -1,
-1, -1, -1,
-1, 1, 1,
1, 1, 1,
1, -1, 1,
-1, -1, 1,
];
const arrays = {
position: positions,
indices: [
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
],
};
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
let projectionToViewWith;
{
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.5;
const zFar = 100;
projectionToViewWith = m4.perspective(fov, aspect, zNear, zFar);
}
let projectionToBeViewed;
{
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 2;
const zFar = 10;
projectionToBeViewed = m4.perspective(fov, aspect, zNear, zFar);
}
const inverseProjectionToBeViewed = m4.inverse(projectionToBeViewed);
const radius = 20;
const eye = [Math.sin(time) * radius, 4, Math.cos(time) * radius];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projectionToViewWith, view);
const worldViewProjection = m4.multiply(
viewProjection,
inverseProjectionToBeViewed);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, {
u_worldViewProjection: worldViewProjection,
u_color: [1, 0, 0, 1],
});
twgl.drawBufferInfo(gl, bufferInfo, gl.LINES);
// just because I'm lazy let's draw each point one at a time
// note: since in our case the frustum is not moving we
// could have computed these at init time.
const positionLoc = programInfo.attribSetters.position.location;
gl.disableVertexAttribArray(positionLoc);
for (let i = 0; i < positions.length; i += 3) {
const point = positions.slice(i, i + 3);
const worldPosition = m4.transformPoint(
inverseProjectionToBeViewed, point);
gl.vertexAttrib3f(positionLoc, ...worldPosition);
twgl.setUniforms(programInfo, {
u_color: [0, 1, 0, 1],
u_worldViewProjection: viewProjection,
});
gl.drawArrays(gl.POINT, 0, 1);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
Mention in a comment you wanted to show the view frustum of a camera in one canvas in another canvas.
That's effectively what's happening above except the camera in canvasWhosFrustumWeWantToRender is not moving. Instead it's just sitting at the origin looking down the -Z axis with +Y up. To allow the frustum to move to show where it is relative to teh camera just need to add in the camera matrix
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const ext = gl.getExtension("OES_standard_derivatives");
const vs = `
attribute vec4 position;
uniform mat4 u_worldViewProjection;
varying vec3 v_position;
void main() {
gl_Position = u_worldViewProjection * position;
v_position = position.xyz; // for fake lighting
}
`;
const fs = `
#extension GL_OES_standard_derivatives : enable
precision mediump float;
varying vec3 v_position;
uniform vec4 u_color;
void main() {
vec3 fdx = dFdx(v_position);
vec3 fdy = dFdy(v_position);
vec3 n = normalize(cross(fdx,fdy));
float l = dot(n, normalize(vec3(1,2,-3))) * .5 + .5;
gl_FragColor = u_color;
gl_FragColor.rgb *= l;
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const arrays = {
position: [
-1, 1, -1,
1, 1, -1,
1, -1, -1,
-1, -1, -1,
-1, 1, 1,
1, 1, 1,
1, -1, 1,
-1, -1, 1,
],
indices: [
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
],
};
const concat = twgl.primitives.concatVertices;
const reorient = twgl.primitives.reorientVertices;
const wireCubeBufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
const solidCubeBufferInfo = twgl.primitives.createCubeBufferInfo(gl, 2);
const cameraBufferInfo = twgl.createBufferInfoFromArrays(gl,
concat([
reorient(twgl.primitives.createCubeVertices(2),
m4.translation([0, 0, 1])),
reorient(twgl.primitives.createTruncatedConeVertices(0, 1, 2, 12, 1),
m4.rotationX(Math.PI * -.5)),
])
);
const black = [0, 0, 0, 1];
const blue = [0, 0, 1, 1];
function drawScene(viewProjection, clearColor) {
gl.clearColor(...clearColor);
gl.clear(gl.COLOR_BUFFER_BIT);
const numCubes = 10;
for (let i = 0; i < numCubes; ++i) {
const u = i / numCubes;
let mat = m4.rotationY(u * Math.PI * 2);
mat = m4.translate(mat, [0, 0, 10]);
mat = m4.scale(mat, [1, 1 + u * 23 % 1, 1]);
mat = m4.translate(mat, [0, .5, 0]);
mat = m4.multiply(viewProjection, mat);
drawModel(solidCubeBufferInfo, mat, [u, u * 3 % 1, u * 7 % 1,1]);
}
}
function drawModel(bufferInfo, worldViewProjection, color, mode) {
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, {
u_worldViewProjection: worldViewProjection,
u_color: color,
});
twgl.drawBufferInfo(gl, bufferInfo, mode);
}
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
const width = gl.canvas.width;
const height = gl.canvas.height;
const halfWidth = width / 2;
gl.viewport(0, 0, width, height);
gl.disable(gl.SCISSOR_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
let projectionToViewWith; // the projection on the right
{
const fov = 60 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / 2 / gl.canvas.clientHeight;
const zNear = 0.5;
const zFar = 100;
projectionToViewWith = m4.perspective(fov, aspect, zNear, zFar);
}
let projectionToBeViewed; // the projeciton on the left
{
const fov = 60 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / 2 / gl.canvas.clientHeight;
const zNear = 1.5;
const zFar = 15;
projectionToBeViewed = m4.perspective(fov, aspect, zNear, zFar);
}
const inverseProjectionToBeViewed = m4.inverse(projectionToBeViewed);
let cameraViewingScene; // camera for right view
{
const t1 = 0;
const radius = 30;
const eye = [Math.sin(t1) * radius, 4, Math.cos(t1) * radius];
const target = [0, 0, 0];
const up = [0, 1, 0];
cameraViewingScene = m4.lookAt(eye, target, up);
}
let cameraInScene; // camera for left view
{
const t1 = time;
const t2 = time + .4;
const r1 = 10 + Math.sin(t1);
const r2 = 10 + Math.sin(t2) * 2;
const eye = [Math.sin(t1) * r1, 0 + Math.sin(t1) * 4, Math.cos(t1) * r1];
const target = [Math.sin(t2) * r2, 1 + Math.sin(t2), Math.cos(t2) * r2];
const up = [0, 1, 0];
cameraInScene = m4.lookAt(eye, target, up);
}
// there's only one shader program so just set it once
gl.useProgram(programInfo.program);
// draw only on left half of canvas
gl.enable(gl.SCISSOR_TEST);
gl.scissor(0, 0, halfWidth, height);
gl.viewport(0, 0, halfWidth, height);
// draw the scene on the left using the camera inside the scene
{
const view = m4.inverse(cameraInScene);
const viewProjection = m4.multiply(projectionToBeViewed, view);
drawScene(viewProjection, [.9, 1, .9, 1]);
}
// draw only on right half of canvas
gl.scissor(halfWidth, 0, halfWidth, height);
gl.viewport(halfWidth, 0, halfWidth, height);
// draw the same scene on the right using the camera outside the scene
{
const view = m4.inverse(cameraViewingScene);
const viewProjection = m4.multiply(projectionToViewWith, view);
drawScene(viewProjection, [.9, 1, 1, 1]);
// draw the in scene camera's frustum
{
const world = m4.multiply(cameraInScene, inverseProjectionToBeViewed);
const worldViewProjection = m4.multiply(viewProjection, world);
drawModel(wireCubeBufferInfo, worldViewProjection, black, gl.LINES);
}
// draw the in scene camera's camera model
{
const worldViewProjection = m4.multiply(viewProjection, cameraInScene);
drawModel(cameraBufferInfo, worldViewProjection, blue);
}
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>

PGraphics set different colormode not working

I have the following code:
import processing.video.*;
import oscP5.*;
import netP5.*;
//sending the data to wekinator
int numPixelsOrig, numPixels, boxWidth = 64, boxHeight = 48, numHoriz = 640/boxWidth, numVert = 480/boxHeight;
color[] downPix = new color[numHoriz * numVert];
PGraphics buffer;
Capture video;
OscP5 oscSend;
//recieving data from the wekinatorino
ArrayList<Blob> blobs = new ArrayList<Blob>();
int amt = 5;
int cons1 = 200, cons2 = 150;
float xspeed, yspeed, radius;
float p1, p2, p3, p4, p5, p6;
OscP5 oscRecieve;
NetAddress dest;
void setup() {
colorMode(RGB, 100);
size(600, 600, P2D);
buffer = createGraphics(600, 600, P3D);
buffer.beginDraw();
buffer.colorMode(HSB, 100);
buffer.endDraw();
String[] cameras = Capture.list();
if (cameras == null) {
video = new Capture(this, 640, 480);
}
if (cameras.length == 0) {
exit();
} else {
video = new Capture(this, 640, 480);
video.start();
numPixelsOrig = video.width * video.height;
}
oscSend = new OscP5(this, 9000);
oscRecieve = new OscP5(this, 12000);
dest = new NetAddress("127.0.0.1", 6448);
}
void draw() {
//println(blobs.size());
if (video.available() == true) {
video.read();
video.loadPixels();
int boxNum = 0;
int tot = boxWidth*boxHeight;
for (int x = 0; x < 640; x += boxWidth) {
for (int y = 0; y < 480; y += boxHeight) {
float red = 0, green = 0, blue = 0;
for (int i = 0; i < boxWidth; i++) {
for (int j = 0; j < boxHeight; j++) {
int index = (x + i) + (y + j) * 640;
red += red(video.pixels[index]);
green += green(video.pixels[index]);
blue += blue(video.pixels[index]);
}
}
downPix[boxNum] = color(red/tot, green/tot, blue/tot);
fill(downPix[boxNum]);
int index = x + 640*y;
red += red(video.pixels[index]);
green += green(video.pixels[index]);
blue += blue(video.pixels[index]);
noStroke();
rect(x, y, boxWidth, boxHeight);
boxNum++;
}
}
if (frameCount % 2 == 0)
sendOsc(downPix);
}
if (blobs.size() < amt) {
blobs.add(new Blob(new PVector(random(100 + (width - 200)), random(100 + (height- 200))), new PVector(-3, 3), random(100, 300)));
}
for (int i = blobs.size() - 1; i >= 0; i--) {
if (blobs.size() > amt) {
blobs.remove(i);
}
}
buffer.beginDraw();
buffer.loadPixels();
for (int x = 0; x < buffer.width; x++) {
for (int y = 0; y < buffer.height; y++) {
int index = x + y * buffer.width;
float sum = 0;
for (Blob b : blobs) {
float d = dist(x, y, b.pos.x, b.pos.y);
sum += 10 * b.r / d;
}
buffer.pixels[index] = color(sum, 255, 255); //constrain(sum, cons1, cons2)
}
}
buffer.updatePixels();
buffer.endDraw();
for (Blob b : blobs) {
b.update();
}
//if () {
//xspeed = map(p1, 0, 1, -5, 5);
//yspeed = map(p2, 0, 1, -5, 5);
//radius = map(p3, 0, 1, 100, 300);
//cons1 = int(map(p4, 0, 1, 0, 255));
//cons2 = int(map(p5, 0, 1, 0, 255));
//amt = int(map(p6, 0, 1, 1, 6));
//for (Blob b : blobs) {
// b.updateAlgorithm(xspeed, yspeed, radius);
//}
//}
image(buffer, 0, 0);
}
void sendOsc(int[] px) {
//println(px);
OscMessage msg = new OscMessage("/wek/inputs");
for (int i = 0; i < px.length; i++) {
msg.add(float(px[i]));
}
oscSend.send(msg, dest);
}
void oscEvent(OscMessage theOscMessage) {
if (theOscMessage.checkAddrPattern("/wek/outputs")==true) {
if (theOscMessage.checkTypetag("fff")) {
p1 = theOscMessage.get(0).floatValue();
p2 = theOscMessage.get(1).floatValue();
p3 = theOscMessage.get(2).floatValue();
p4 = theOscMessage.get(2).floatValue();
p5 = theOscMessage.get(2).floatValue();
p6 = theOscMessage.get(2).floatValue();
} else {
}
}
}
void mousePressed() {
xspeed = random(-5, 5);
yspeed = random(-5, 5);
radius = random(100, 300);
cons1 = int(random(255));
cons2 = int(random(255));
amt = int(random(6));
for (Blob b : blobs) {
b.updateAlgorithm(xspeed, yspeed, radius);
}
}
class Blob {
PVector pos;
PVector vel;
float r;
Blob(PVector pos, PVector vel, float r) {
this.pos = pos.copy();
this.vel = vel.copy();
this.r = r;
}
void update(){
pos.add(vel);
if (pos.x > width || pos.x < 0) {
vel.x *= -1;
}
if (pos.y > height || pos.y < 0) {
vel.y *= -1;
}
}
void updateAlgorithm(float vx, float vy, float nr){
vel.x = vx;
vel.y = vy;
r = nr;
}
}
Then I create some graphics in the buffer element. but the graphics aren't using my HSB color mode with the result i only see blue and white...
so how do i correct my code, or change the colorMode for a PGraphics element to HSB?
According to the PGraphics reference:
The beginDraw() and endDraw() methods (see above example) are
necessary to set up the buffer and to finalize it
therefore you should try this:
buffer = createGraphics(600, 600, P3D);
buffer.beginDraw();
buffer.colorMode(HSB, 100);
buffer.endDraw();
Here's a full test sketch to run and compare:
PGraphics buffer;
void setup(){
colorMode(RGB, 100);
size(600, 600, P2D);
//draw test gradient in RGB buffer
noStroke();
for(int i = 0 ; i < 10; i++){
fill(i * 10,100,100);
rect(0,i * 60,width,60);
}
buffer = createGraphics(600, 600, P3D);
buffer.beginDraw();
buffer.colorMode(HSB, 100);
buffer.endDraw();
//draw test gradient in HSB buffer
buffer.beginDraw();
buffer.noStroke();
for(int i = 0 ; i < 10; i++){
buffer.fill(i * 10,100,100);
buffer.rect(0,i * 60,width,60);
}
buffer.endDraw();
//finally render the buffer on screen, offset to the right for comparison
image(buffer,300,0);
}

How do I stop sound chopping in Processing while using Minim?

I have been working on the piece of code below in Processing using the sound library Minim, and have been trying to stop the audio recorded into the program from chopping the sound, rendering it somewhat unaudible.
Setup():
import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;
Minim sound;
AudioOutput speak;
AudioInput mic;
Sampler samp;
MultiChannelBuffer bigBuf;
AudioPlayer loadAudio;
slider frequency, amplitude;
button mute, record, play, stop;
trigger freqBut, ampBut, load;
float[] mainLeft = new float[1024];
float[] mainRight = new float[1024];
float amp = 1;
boolean muted = false, recording = false, playInit = false;
int sampleCount = 0;
int tempCount = 0;
int tempFreq = 0;
boolean tempUnder = false;
int tempTimeNew = 0;
int tempTimeOld = 0;
void setup() {
size(512, 300);
// UI
frequency = new slider(10, 60, 300, 20, 0, 30, true, color(120), color(180), color(255), color(80, 0, 0));
amplitude = new slider(10, 90, 300, 20, 0, 20, false, color(120), color(180), color(255), color(0, 0, 80));
mute = new button(10, 10, 40, 40, color(120), color(180), color(255));
record = new button(60, 10, 40, 40, color(120), color(180), color(255));
play = new button(110, 10, 40, 40, color(120), color(180), color(255));
stop = new button(160, 10, 40, 40, color(120), color(180), color(255));
load = new trigger(210, 10, 40, 40, color(120), color(210), color(180), color(255));
freqBut = new trigger(320, 60, 20, 20, color(40, 0, 0), color(220, 0, 0), color(180, 0, 0), color(255));
ampBut = new trigger(320, 90, 20, 20, color(0, 0, 40), color(0, 0, 220), color(0, 0, 180), color(255));
// Minim
sound = new Minim(this);
mic = sound.getLineIn();
speak = sound.getLineOut(sound.STEREO, mic.bufferSize(), mic.sampleRate());
loadAudio = sound.loadFile("sound.mp3");
loadAudio.loop();
loadAudio.mute();
bigBuf = new MultiChannelBuffer(mic.bufferSize(), 2);
samp = new Sampler(bigBuf, mic.sampleRate(), 2);
samp.patch(speak);
}
And draw():
void draw() {
float[] micLeft;
float[] micRight;
micLeft = mic.left.toArray();
micRight = mic.right.toArray();
if (record.state == true) {
recording = !recording;
}
if (recording == true) {
int temp = mainLeft.length - 1;
mainLeft = expand(mainLeft, temp + micLeft.length);
mainRight = expand(mainRight, temp + micRight.length);
sampleCount++;
for (int i = 0; i < micLeft.length - 1; i++) {
mainLeft[i + temp] = micLeft[i];
mainRight[i + temp] = micRight[i];
}
}
// Play
if (play.state == true) {
playInit = true;
}
if (playInit == true) {
println("playing");
if (tempTimeOld > tempTimeNew) {
tempUnder = true;
}
tempTimeOld = tempTimeNew;
tempTimeNew = millis() % micLeft.length;
println(millis() % (micLeft.length));
if (tempUnder == true) {
if (tempCount == sampleCount) {
playInit = false;
tempCount = 0;
}
else {
// Amplitude
if (ampBut.state == true) {
amp = map(amplitude.value, amplitude.minVal, amplitude.maxVal, 0.05, 20);
}
else {
amp = 1;
}
if (freqBut.state == true) {
float newFreq = map(frequency.value, frequency.minVal, frequency.maxVal, 140, 940);
tempFreq = 0;
for (int i = 0; i < micLeft.length - 2; i++) {
if (micLeft[i] < micLeft[i + 1]) {
tempFreq ++;
}
}
for (int i = 0; i < micLeft.length - 1; i++) {
bigBuf.setSample(0, i, mainLeft[int(i * newFreq / tempFreq) + (tempCount * micLeft.length)] * amp);
bigBuf.setSample(1, i, mainRight[int(i * newFreq / tempFreq) + (tempCount * micRight.length)] * amp);
}
}
else {
for (int i = 0; i < micLeft.length - 1; i++) {
bigBuf.setSample(0, i, mainLeft[i + (tempCount * micLeft.length)] * amp);
bigBuf.setSample(1, i, mainRight[i + (tempCount * micRight.length)] * amp);
}
}
samp.trigger();
tempCount++;
}
}
}
}
Any advise on solving this problem would be a really big help.
And sorry if it have not been asking to right way, it is my first question, and the guide confused me a little.

Display lcudi.canvas from lwuit Form

I have two classes in one package one extends lcudi.Canvas and another extends lwuit.Form
I create two buttons on my Form
My purpose is displaying the canvas when one of the buttons is pressed.
In my mind this function should display the canvas .
setFullScreenMode(true);
but it doesn't.
This is the Canvas Class
[code]
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;
import java.util.*;
import javax.microedition.rms.*;
public class MainCanvas extends Canvas implements Runnable {
HelloLWUITMidlet mid;
int screen_width;
int screen_height;
int mode;
int selected;
String current_time;
int[] time_numbers;
long current_time_milli;
long start_timestamp;
int selected_preset;
static String s;
Random generator;
final static int MODE_SETUP = 0;
final static int MODE_RUNNING = 1;
final static int MODE_RINGING = 2;
final static int MODE_PRESETS_TYPE = 3;
final static int MODE_PRESETS_MODE = 4;
public MainCanvas(HelloLWUITMidlet h) {
mid =h;
this.setFullScreenMode(true);
new Thread(this).start();
screen_width = this.getWidth();
screen_height = this.getHeight();
time_numbers = new int[4];
setCurrentTime();
initImages();
generator = new Random(System.currentTimeMillis());
mode = MODE_SETUP;
selected = 0;
}
Image back;
Image numbers;
Image font;
int numberFontWidths[];
int numberFontOffsets[];
int numberFontCodes[];
int fontData[] = new int[]
{
0, 0, 0, 0, 4,
0, 0, 4, 16, 3,
4, 0, 4, 16, 4,
8, 0, 10, 16, 10,
18, 0, 7, 16, 7,
25, 0, 9, 16, 9,
34, 0, 9, 16, 8,
43, 0, 2, 16, 2,
45, 0, 4, 16, 4,
49, 0, 4, 16, 4,
53, 0, 6, 16, 6,
59, 0, 11, 16, 10,
70, 0, 3, 16, 3,
73, 0, 5, 16, 5,
78, 0, 3, 16, 3,
81, 0, 5, 16, 4,
86, 0, 8, 16, 8,
94, 0, 4, 16, 4,
98, 0, 7, 16, 6,
105, 0, 7, 16, 7,
112, 0, 8, 16, 8,
120, 0, 7, 16, 6,
127, 0, 7, 16, 7,
134, 0, 6, 16, 6,
140, 0, 7, 16, 7,
147, 0, 7, 16, 7,
154, 0, 3, 16, 3,
157, 0, 3, 16, 3,
160, 0, 11, 16, 10,
171, 0, 11, 16, 10,
182, 0, 11, 16, 10,
193, 0, 6, 16, 6,
199, 0, 13, 16, 13,
212, 0, 8, 16, 8,
220, 0, 8, 16, 8,
228, 0, 8, 16, 7,
236, 0, 9, 16, 9,
245, 0, 6, 16, 6,
0, 16, 6, 16, 6,
6, 16, 9, 16, 9,
15, 16, 10, 16, 9,
25, 16, 4, 16, 3,
29, 16, 6, 16, 5,
35, 16, 8, 16, 8,
43, 16, 6, 16, 6,
49, 16, 11, 16, 11,
60, 16, 10, 16, 9,
70, 16, 10, 16, 9,
80, 16, 8, 16, 7,
88, 16, 10, 16, 9,
98, 16, 8, 16, 7,
106, 16, 7, 16, 7,
113, 16, 6, 16, 6,
119, 16, 9, 16, 9,
128, 16, 7, 16, 7,
135, 16, 12, 16, 11,
147, 16, 7, 16, 7,
154, 16, 7, 16, 6,
161, 16, 7, 16, 6,
168, 16, 4, 16, 4,
172, 16, 5, 16, 4,
177, 16, 4, 16, 4,
181, 16, 13, 16, 13,
194, 16, 6, 16, 6,
200, 16, 6, 16, 6,
206, 16, 8, 16, 7,
214, 16, 8, 16, 7,
222, 16, 6, 16, 6,
228, 16, 8, 16, 7,
236, 16, 7, 16, 7,
243, 16, 4, 16, 4,
247, 16, 8, 16, 7,
0, 32, 8, 16, 7,
8, 32, 3, 16, 3,
11, 32, 3, 16, 3,
14, 32, 7, 16, 6,
21, 32, 3, 16, 3,
24, 32, 11, 16, 11,
35, 32, 8, 16, 7,
43, 32, 7, 16, 7,
50, 32, 8, 16, 7,
58, 32, 8, 16, 7,
66, 32, 5, 16, 4,
71, 32, 5, 16, 5,
76, 32, 4, 16, 4,
80, 32, 7, 16, 7,
87, 32, 6, 16, 6,
93, 32, 10, 16, 9,
103, 32, 6, 16, 6,
109, 32, 6, 16, 6,
115, 32, 6, 16, 5,
121, 32, 6, 16, 6,
127, 32, 6, 16, 6,
133, 32, 6, 16, 6,
139, 32, 11, 16, 10
};
int[] fontCodes = new int[]
{
0x0020,
0x0021,
0x0022,
0x0023,
0x0024,
0x0025,
0x0026,
0x0027,
0x0028,
0x0029,
0x002a,
0x002b,
0x002c,
0x002d,
0x002e,
0x002f,
0x0030,
0x0031,
0x0032,
0x0033,
0x0034,
0x0035,
0x0036,
0x0037,
0x0038,
0x0039,
0x003a,
0x003b,
0x003c,
0x003d,
0x003e,
0x003f,
0x0040,
0x0041,
0x0042,
0x0043,
0x0044,
0x0045,
0x0046,
0x0047,
0x0048,
0x0049,
0x004a,
0x004b,
0x004c,
0x004d,
0x004e,
0x004f,
0x0050,
0x0051,
0x0052,
0x0053,
0x0054,
0x0055,
0x0056,
0x0057,
0x0058,
0x0059,
0x005a,
0x005b,
0x005c,
0x005d,
0x005e,
0x005f,
0x0060,
0x0061,
0x0062,
0x0063,
0x0064,
0x0065,
0x0066,
0x0067,
0x0068,
0x0069,
0x006a,
0x006b,
0x006c,
0x006d,
0x006e,
0x006f,
0x0070,
0x0071,
0x0072,
0x0073,
0x0074,
0x0075,
0x0076,
0x0077,
0x0078,
0x0079,
0x007a,
0x007b,
0x007c,
0x007d,
0x007e
};
int[] fontKerning = new int[]
{
70, 44, -1,
70, 46, -1,
76, 86, -1,
76, 89, -1,
80, 44, -2,
80, 46, -2,
84, 44, -1,
84, 45, -1,
84, 46, -1,
84, 97, -1,
84, 99, -1,
84, 101, -1,
84, 111, -1,
84, 115, -1,
86, 44, -1,
86, 46, -1,
87, 44, -1,
87, 46, -1,
89, 44, -2,
89, 45, -1,
89, 46, -2,
89, 58, -1,
89, 59, -1,
89, 97, -1,
89, 101, -1,
89, 111, -1,
114, 44, -1,
114, 46, -1
};
int[] fontCodeTable;
public void initImages() {
try{
// back = Image.createImage("/numbers.png");
numbers = Image.createImage("/numbers.png");
font = Image.createImage("/font.png");
numberFontWidths = new int[]
{
17,10,15,15,18,15,16,15,15,16,8
};
int offset = 0;
numberFontOffsets = new int[numberFontWidths.length];
for(int i=0;i<numberFontWidths.length;i++) {
numberFontOffsets[i] = offset;
offset+=numberFontWidths[i];
}
numberFontCodes = new int[256];
numberFontCodes[(int) "0".charAt(0)] = 0;
numberFontCodes[(int) "1".charAt(0)] = 1;
numberFontCodes[(int) "2".charAt(0)] = 2;
numberFontCodes[(int) "3".charAt(0)] = 3;
numberFontCodes[(int) "4".charAt(0)] = 4;
numberFontCodes[(int) "5".charAt(0)] = 5;
numberFontCodes[(int) "6".charAt(0)] = 6;
numberFontCodes[(int) "7".charAt(0)] = 7;
numberFontCodes[(int) "8".charAt(0)] = 8;
numberFontCodes[(int) "9".charAt(0)] = 9;
numberFontCodes[(int) ":".charAt(0)] = 10;
fontCodeTable = new int[256];
for(int i=0;i<fontCodes.length;i++)
fontCodeTable[fontCodes[i]] = i;
} catch(Exception e) {
}
}
public void setCurrentTime() {
current_time = "";
for(int i=0;i<4;i++) {
current_time = current_time + Integer.toString(time_numbers[i]);
if(i==1)
current_time = current_time + ":";
}
}
public void run() {
while(true) {
update();
Refresh();
this.repaint();
long nexttime = System.currentTimeMillis() +60;
// set your framerate here
while(System.currentTimeMillis() < nexttime)
Thread.yield();
}
}
int blinker;
public void update() {
switch(mode) {
case MODE_SETUP:
case MODE_PRESETS_TYPE:
case MODE_PRESETS_MODE:
blinker++;
break;
case MODE_RUNNING:
int left = (int) (current_time_milli - (System.currentTimeMillis() - start_timestamp));
if(left<=0) {
playMidi();
mode = MODE_RINGING;
}
int minutes = left / (60*1000);
int seconds = (left-minutes*60*1000)/1000;
String min_string = ""+minutes;
if(min_string.length()==1)min_string = "0"+min_string;
String sec_string = ""+seconds;
if(sec_string.length()==1)sec_string = "0"+sec_string;
current_time = min_string+":"+sec_string;
break;
case MODE_RINGING:
blinker++;
shake_x = (generator.nextInt()%5);
shake_y = (generator.nextInt()%5);
break;
}
}
public void keyPressed(int key) {
if(mode == MODE_SETUP) {
int number_pressed = -1;
if(key == KEY_NUM0)
number_pressed = 0;
if(key == KEY_NUM1)
number_pressed = 1;
if(key == KEY_NUM2)
number_pressed = 2;
if(key == KEY_NUM3)
number_pressed = 3;
if(key == KEY_NUM4)
number_pressed = 4;
if(key == KEY_NUM5)
number_pressed = 5;
if(key == KEY_NUM6 & selected != 2)
number_pressed = 6;
if(key == KEY_NUM7 & selected != 2)
number_pressed = 7;
if(key == KEY_NUM8 & selected != 2)
number_pressed = 8;
if(key == KEY_NUM9& selected != 2)
number_pressed = 9;
if(number_pressed>-1 & selected < 4) {
time_numbers[selected] = number_pressed;
selected++;
} else {
int action = getGameAction(key);
if(action == UP) {
if(selected<4) {
if(selected==2)
time_numbers[2] = (time_numbers[2]+1)%6;
else
time_numbers[selected] = (time_numbers[selected]+1)%10;
} else {
if(selected>4)
selected--;
else
selected=0;
}
}
if(action == DOWN) {
if(selected<4) {
int new_val = time_numbers[selected]-1;
if(selected==2) {
if(new_val==-1)
new_val=5;
} else {
if(new_val==-1)
new_val=9;
}
time_numbers[selected] = new_val;
} else {
selected++;
if(selected>6)
selected = 6;
}
}
if(action == FIRE) {
if(selected<4)
selected++;
else {
if(selected==4) {
start_timestamp = System.currentTimeMillis();
int minutes = ((time_numbers[0]*10) + time_numbers[1]);
int seconds = ((time_numbers[2]*10) + time_numbers[3])+1;
current_time_milli = (minutes * 60 * 1000) + (seconds * 1000);
mode = MODE_RUNNING;
}
if(selected==5) {
selected=0;
mode = MODE_PRESETS_TYPE;
}
if(selected==6) {
mid.notifyDestroyed();
}
}
}
if(action == LEFT & selected>0) {
selected--;
}
if(action == RIGHT & selected<6)
selected++;
}
} else if(mode==MODE_PRESETS_TYPE) {
int action = getGameAction(key);
if(action == UP && selected>0)
selected--;
if(action == DOWN && selected<2)
selected++;
if(action == FIRE) {
selected_preset = selected;
selected = 0;
mode = MODE_PRESETS_MODE;
}
} else if(mode==MODE_PRESETS_MODE)
{
int action = getGameAction(key);
if(action == UP && selected>0)
selected--;
if(action == DOWN && selected<1)
selected++;
if(action == FIRE) {
int[] presets = new int[]
{
0,3,0,0,
0,4,3,0,
0,5,3,0,
0,5,0,0,
0,6,5,0,
0,8,0,0,
};
int offset = selected * 12 + selected_preset * 4;
time_numbers[0]=presets[offset++];
time_numbers[1]=presets[offset++];
time_numbers[2]=presets[offset++];
time_numbers[3]=presets[offset++];
mode = MODE_SETUP;
selected = 4;
}
}
else {
int action = getGameAction(key);
if(action==FIRE)
{
mode = MODE_SETUP;
stopMidi();
}
}
if(mode != MODE_RUNNING)
setCurrentTime();
}
public void keyReleased(int key) {
}
int shake_x;
int shake_y;
public void paint(Graphics g) {
int color = 0xFFFF00;
if(mode == MODE_RINGING && (blinker%10>5))
color = 0xFF0000;
g.setColor(color);
g.fillRect( 0, 0,screen_width ,screen_height );
Graphics gg ;
color = 0x00FF00;
g.setColor(color);
g.fillRect(0,50,50,0);
color = 0x000FF;
g.drawString( s ,40,50, 0);
int x = (screen_width-128)>>1;
int y = (screen_height-128)>>1;
if(mode != MODE_PRESETS_TYPE && mode != MODE_PRESETS_MODE)
paintNumbersCentered(g);
switch(mode) {
case MODE_SETUP:
y = (screen_height>>1)+10;
if(selected!=4 | (blinker%20>10)) {
paintTextCentered(g,"START",y);
}
y+=15;
if(selected!=5 | (blinker%20>10)) {
paintTextCentered(g,"PRESETS",y);
}
y+=15;
if(selected!=6 | (blinker%20>10)) {
paintTextCentered(g,"EXIT",y);
}
break;
case MODE_PRESETS_TYPE:
y = (screen_height>>1)-10;
if(selected!=0 | (blinker%20>10)) {
paintTextCentered(g,"Supreme Runny",y);
}
y+=20;
if(selected!=1 | (blinker%20>10)) {
paintTextCentered(g,"Perfect Plasma",y);
}
y+=20;
if(selected!=2 | (blinker%20>10)) {
paintTextCentered(g,"Hard Boiled",y);
}
break;
case MODE_PRESETS_MODE:
y = (screen_height>>1)-15;
if(selected!=0 | (blinker%20>10)) {
paintTextCentered(g,"Eggs in cold water",y);
y+=13;
paintTextCentered(g,"Start when water is",y);
y+=13;
paintTextCentered(g,"boiling",y);
}
y = (screen_height>>1)+30;
if(selected!=1 | (blinker%20>10)) {
paintTextCentered(g,"Start when putting",y);
y+=13;
paintTextCentered(g,"eggs in boiling water",y);
}
break;
}
}
public void paintNumbersCentered(Graphics g) {
int width = 0;
for(int i=0;i<current_time.length();i++) {
int c = (int) current_time.charAt(i);
width+=numberFontWidths[numberFontCodes[c]];
}
int x = (screen_width - width) >>1;
int y = (screen_height >>1)-15;
for(int i=0;i<current_time.length();i++) {
int c = (int) current_time.charAt(i);
int code = numberFontCodes[c];
int char_w = numberFontWidths[code];
int char_off = numberFontOffsets[code];
int sel = selected;
if(sel>1)sel++;
if(sel!=i | (blinker%20>10)) {
g.setClip(x+shake_x,y+shake_y,char_w,20);
g.drawImage(numbers,x-char_off+shake_x,y+shake_y,0);
}
x+=char_w;
}
}
public void Refresh()
{
Date t = new java.util.Date(System.currentTimeMillis());
s = t.toString();
}
public void paintTextCentered(Graphics g,String text,int y) {
int width = 0;
int textlen = text.length();
for(int i=0;i<textlen;i++) {
int code = fontCodeTable[(int)text.charAt(i)];
int char_width = fontData[code*5+4];
width+=char_width;
}
int x = (screen_width-width)>>1;
int last_char = -1;
for(int i=0;i<textlen;i++) {
int this_char = (int)text.charAt(i);
int code = fontCodeTable[this_char];
int offset = code*5;
int sx = fontData[offset++];
int sy = fontData[offset++];
int sw = fontData[offset++];
int sh = fontData[offset++];
int aw = fontData[offset++];
if(i>0) {
int koff = 0;
int klen = fontKerning.length / 3;
for(int k=0;k<klen;k++) {
koff = k*3;
if(last_char==fontKerning[koff] && this_char==fontKerning[koff+1]) {
x+=fontKerning[koff+2];
break;
}
}
}
if(sw>0 && sh>0) {
g.setClip(x,y,sw,sh);
g.drawImage(font,x-sx,y-sy,0);
}
x+=aw;
last_char = (int)text.charAt(i);
}
}
Player player = null;
public void stopMidi() {
try{
if(player!=null) {
player.stop();
player.deallocate();
}
player = null;
System.gc();
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
public void playMidi() {
try {
stopMidi();
player = Manager.createPlayer(this.getClass().getResourceAsStream("/ring.mid"),"audio/midi");
player.realize();
VolumeControl vc = (VolumeControl) player.getControl("VolumeControl");
vc.setLevel(100);
player.start();
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
protected void hideNotify() {
}
protected void showNotify() {
}
}
[/code]
And that is the Form
[code]
import Pes.*;
//import Pes.MainCanvas;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import com.sun.lwuit.layouts.*;
import com.sun.lwuit.*;
import javax.microedition.lcdui.Canvas;
import com.sun.lwuit.events.*;
import com.sun.lwuit.plaf.*;
public class HelloLWUITMidlet extends MIDlet implements ActionListener {
HelloLWUITMidlet hh;
public void startApp() {
com.sun.lwuit.Display.init(this);
final com.sun.lwuit.Form f = new com.sun.lwuit.Form( " SOFTWARE SCREENS");
final MainCanvas m = new MainCanvas(hh);
f.getStyle().setBgColor(0X99CCFF);
BoxLayout boxlayout =new BoxLayout(BoxLayout.X_AXIS);
com.sun.lwuit.Command exitCommand = new com.sun.lwuit.Command("Exit");
f.addCommand(exitCommand);
f.addCommandListener(this);
final Button button = new Button(" GOALS ");
final Button button1 = new Button(" TIME SETTING");
Style btnstyle = button.getSelectedStyle() ;
Style btnstyle1 = button1.getSelectedStyle() ;
btnstyle.setBgColor(0X0000FF);
btnstyle.setFgColor(0XFFFFFF);
btnstyle1.setBgColor(0X0000FF);
btnstyle1.setFgColor(0XFFFFFF);
// button.getStyle().setBgColor(0X99CCFF);
button1.addActionListener(new ActionListener() {
private int c = 0;
public void actionPerformed(ActionEvent ae) {
c++;
// Display.init(m);
m.setFullScreenMode(true);
}
});
button.addActionListener(new ActionListener() {
private int c = 0;
public void actionPerformed(ActionEvent ae) {
c++;
m.setFullScreenMode(true);
}
});
f.addComponent(button1);
f.addComponent(button);
f.show();
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void actionPerformed(ActionEvent ae) {
notifyDestroyed();
}
}
[/code]
Notice :- If you need the images and sounds included in my code to test my application you can download eggtime application from here
http://www.bambalam.se/eggtimer/
You are mixing lwuit and javax.microedition code together.
That is why you need to transfer control from lwuit Display to javax.microedition.Display control. For this you need to call
javax.microedition.lcdui.Display.getDisplay(hh).setCurrent(m);
after you call setFullScreenMode in your actionListener.

Resources