I copied the example from this site click
It is working well after fixing some minor things and extending the shader for my purpose. Now i want to move/translate the texture to the right side of the screen.
For that case i have to add a ModelViewProjection Matrix to my code and as well to the shader, right?
After doing this the Texture is not showing up anymore :-( What am I doing wrong?
So the code is working until i change in my shader gl_position from :
gl_Position= a_position to gl_Position= a_position * ModelViewProjectionMatrix
There is no error but also no texture...
The output for the ModelViewProjection is : [0.0,0.0,0.0,0.0] ... why?
This is the Source-Code :
Activity:
//Activity
public class MainActivity extends Activity {
private MainView mView;
//private WakeLock mWL;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mView = new MainView(this);
setContentView(mView);
}
#Override
protected void onPause() {
mView.onPause();
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
mView.onResume();
}
}
SurfaceView
//View
class MainView extends GLSurfaceView {
CameraRenderer mRenderer;
MainView(Context context) {
super(context);
mRenderer = new CameraRenderer(this);
setEGLContextClientVersion(2);
setRenderer(mRenderer);
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
public void surfaceCreated(SurfaceHolder holder) {
super.surfaceCreated(holder);
}
public void surfaceDestroyed(SurfaceHolder holder) {
mRenderer.close();
super.surfaceDestroyed(holder);
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
}
}
CameraRenderer:
public class CameraRenderer implements GLSurfaceView.Renderer,
SurfaceTexture.OnFrameAvailableListener {
private final String vss = "uniform mat4 uMVPMatrix;\n"
+ "attribute vec2 vPosition;\n"
+ "attribute vec2 vTexCoord;\n"
+ ""
+ "varying vec2 texCoord;\n"
+ "vec4 Distort(vec4 p){ \n"
+ " float BarrelPower = 1.0; \n"
+ " vec2 v = p.xy / p.w; \n"
+ " float radius = length(v); \n"
+ " if (radius > 0.0){ \n"
+ " float theta = atan(v.y,v.x); \n"
+ " radius = pow(radius, BarrelPower);\n"
+ " v.x = radius * cos(theta); \n"
+ " v.y = radius * sin(theta); \n"
+ " p.xy = v.xy * p.w; \n"
+ " }"
+ " \n"
+ " return p; \n"
+ " } \n"
+ "void main() {\n"
+" vec4 a_position = vec4 ( vPosition.x, vPosition.y, 0.0, 1.0 );"
+ "vec4 test = uMVPMatrix * a_position; \n"
+ "texCoord = vTexCoord;\n"
+ "gl_Position = test;\n"
+ "}";
private final String fss = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "varying vec2 texCoord;\n" + "void main() {\n"
+ " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}";
private int[] hTex;
private FloatBuffer pVertexRight;
private FloatBuffer pTexCoordRight;
private int hProgram;
private Camera mCamera;
private SurfaceTexture mSTexture;
private boolean mUpdateST = false;
private MainView mView;
private float[] mMVPMatrix = new float[16];
private float[] mProjMatrix = new float[16];
private float[] mMMatrix = new float[16];
private float[] mVMatrix = new float[16];
private int muMVPMatrixHandle;
private int maPositionHandle;
private int maTextureHandle;
CameraRenderer(MainView view) {
mView = view;
float[] vtmpRight = { 0.35f, -0.35f, -0.35f, -0.35f, 0.35f, 0.35f,
-0.35f, 0.35f };
float[] ttmpRight = { 0.35f, 0.35f, 0.0f, 0.35f, 0.35f, 0.0f, 0.0f,
0.0f };
pVertexRight = ByteBuffer.allocateDirect(8 * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
pVertexRight.put(vtmpRight);
pVertexRight.position(0);
pTexCoordRight = ByteBuffer.allocateDirect(8 * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
pTexCoordRight.put(ttmpRight);
pTexCoordRight.position(0);
}
public void close() {
mUpdateST = false;
mSTexture.release();
mCamera.stopPreview();
mCamera = null;
deleteTex();
}
public void onSurfaceCreated(GL10 unused,
javax.microedition.khronos.egl.EGLConfig config) {
// String extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS);
// Log.i("mr", "Gl extensions: " + extensions);
// Assert.assertTrue(extensions.contains("OES_EGL_image_external"));
initTex();
mSTexture = new SurfaceTexture(hTex[0]);
mSTexture.setOnFrameAvailableListener(this);
mCamera = Camera.open();
try {
mCamera.setPreviewTexture(mSTexture);
Log.i("GLES20", "setPreviewTexture success");
} catch (IOException ioe) {
}
GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
hProgram = loadShader(vss, fss);
}
public void onDrawFrame(GL10 unused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
synchronized (this) {
if (mUpdateST) {
mSTexture.updateTexImage();
mUpdateST = false;
}
}
GLES20.glUseProgram(hProgram);
int ph = GLES20.glGetAttribLocation(hProgram, "vPosition");
int tch = GLES20.glGetAttribLocation(hProgram, "vTexCoord");
int th = GLES20.glGetUniformLocation(hProgram, "sTexture");
muMVPMatrixHandle = GLES20.glGetUniformLocation(hProgram, "uMVPMatrix");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, hTex[0]);
GLES20.glUniform1i(th, 0);
GLES20.glVertexAttribPointer(ph, 2, GLES20.GL_FLOAT, false, 4 * 2,
pVertexRight);
GLES20.glVertexAttribPointer(tch, 2, GLES20.GL_FLOAT, false, 4 * 2,
pTexCoordRight);
GLES20.glEnableVertexAttribArray(ph);
GLES20.glEnableVertexAttribArray(tch);
Matrix.setRotateM(mMMatrix, 0, 0, 0, 0, 1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv( muMVPMatrixHandle, 1, false, mMVPMatrix, 0 );
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
// right
GLES20.glFlush();
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
Camera.Parameters param = mCamera.getParameters();
List<Size> psize = param.getSupportedPreviewSizes();
if (psize.size() > 0) {
int i;
for (i = 0; i < psize.size(); i++) {
if (psize.get(i).width < width || psize.get(i).height < height)
break;
}
if (i > 0)
i--;
param.setPreviewSize(psize.get(i).width, psize.get(i).height);
Log.i("mr", "ssize: " + psize.get(i).width + ", "
+ psize.get(i).height);
}
mCamera.setParameters(param);
mCamera.startPreview();
}
private void initTex() {
hTex = new int[1];
GLES20.glGenTextures(1, hTex, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, hTex[0]);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
}
private void deleteTex() {
GLES20.glDeleteTextures(1, hTex, 0);
}
public synchronized void onFrameAvailable(SurfaceTexture st) {
mUpdateST = true;
// mView.requestRender();
}
private static int loadShader(String vss, String fss) {
int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vshader, vss);
GLES20.glCompileShader(vshader);
int[] compiled = new int[1];
GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e("Shader", "Could not compile vshader");
Log.v("Shader",
"Could not compile vshader:"
+ GLES20.glGetShaderInfoLog(vshader));
GLES20.glDeleteShader(vshader);
vshader = 0;
} else {
Log.i("GLES20", "compile vertex success");
}
int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fshader, fss);
GLES20.glCompileShader(fshader);
GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e("Shader", "Could not compile fshader");
Log.v("Shader",
"Could not compile fshader:"
+ GLES20.glGetShaderInfoLog(fshader));
GLES20.glDeleteShader(fshader);
fshader = 0;
} else {
Log.i("GLES20", "compile fragment success");
}
int program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vshader);
GLES20.glAttachShader(program, fshader);
GLES20.glLinkProgram(program);
return program;
}
}
I cant's see where you set the values from the matrix mMVPMatrix to the uniform uMVPMatrix. You should do something like this before drawing the arrays:
GLES20.glUniformMatrix4fv( muMVPMatrixHandle, 1, false, mMVPMatrix, 0 );
EDIT: #derhass #reto-koradi thank you for correcting my answer
Last Post and additionally defining the viewFrustum did it. Thanks a lot ! :-)
onSurfaceChange(width,height){
...
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, ratio, -ratio, -1, 1, 3, 7);
....
Related
I'm still new to Stackoverflow and new to the topic of Processing and Java, so apologies if I can't make my question as clear directly.
My goal is to create a "growing shape" with each mouse click. Below you will find my current code, which currently allows one of these shapes to be created with a mouse click. But as soon as I click again, my first shape stops growing and the second one starts (a bit hard to explain - best copy the code once and try it, then you know what I mean).
I've been trying for hours to somehow generate multiple shapes - one for each mouse click - which each continue to grow on their own, unfortunately without success. The goal is to have a lot of growing shapes at the same time.
Do any of you have an idea how to implement this?
If you need more info, just contact me!
Thank you
Lara
Code:
// PARAMETERS
float _maxForce = 0.9;
float _maxSpeed = 1;
float _desiredSeparation = 30;
float _separationCohesionRation = 1.1;
float _maxEdgeLen = 8;
boolean seed = false;
DifferentialLine _diff_line;
void setup() {
frameRate(60);
background(0);
size(1280, 720);
}
void draw() {
if(seed == true){
//println(frameCount);
background(0);
_diff_line.run();
_diff_line.render();
}
}
void mousePressed(){
seed = true;
malewas();
}
void malewas(){
_diff_line = new DifferentialLine(_maxForce, _maxSpeed, _desiredSeparation, _separationCohesionRation, _maxEdgeLen);
//fill(0);
float nodesStart = 3;
float angInc = TWO_PI/nodesStart;
float rayStart = 5;
for (float a=0; a<TWO_PI; a+=angInc) {
float x = mouseX + cos(a) * rayStart;
float y = mouseY + sin(a) * rayStart;
_diff_line.addNode(new Node(x, y, _diff_line.maxForce, _diff_line.maxSpeed, _diff_line.desiredSeparation, _diff_line.separationCohesionRation));
//println(mouseX);
//println(mouseY);
}
}
class DifferentialLine {
ArrayList<Node> nodes;
float maxForce;
float maxSpeed;
float desiredSeparation;
float separationCohesionRation;
float maxEdgeLen;
DifferentialLine(float mF, float mS, float dS, float sCr, float eL) {
nodes = new ArrayList<Node>();
maxSpeed = mF;
maxForce = mS;
desiredSeparation = dS;
separationCohesionRation = sCr;
maxEdgeLen = eL;
}
void run() {
for (Node n : nodes) {
n.run(nodes);
}
growth();
}
void addNode(Node n) {
nodes.add(n);
}
void addNodeAt(Node n, int index) {
nodes.add(index, n);
}
void growth() {
for (int i=0; i<nodes.size()-1; i++) {
Node n1 = nodes.get(i);
Node n2 = nodes.get(i+1);
float d = PVector.dist(n1.position, n2.position);
if (d>maxEdgeLen) { // Can add more rules for inserting nodes
int index = nodes.indexOf(n2);
PVector middleNode = PVector.add(n1.position, n2.position).div(2);
addNodeAt(new Node(middleNode.x, middleNode.y, maxForce, maxSpeed, desiredSeparation, separationCohesionRation), index);
}
}
}
void render() {
for (int i=0; i<nodes.size()-1; i++) {
PVector p1 = nodes.get(i).position;
PVector p2 = nodes.get(i+1).position;
line(p1.x, p1.y, p2.x, p2.y);
colorMode(HSB);
stroke(255);
//stroke(10,frameCount*0.3,100);
//stroke(255);//Farbe
strokeWeight(1); //Strichstärke
if (i==nodes.size()-2) {
line(p2.x, p2.y, nodes.get(0).position.x, nodes.get(0).position.y);
}
}
}
}
class Node {
PVector position;
PVector velocity;
PVector acceleration;
float maxForce;
float maxSpeed;
float desiredSeparation;
float separationCohesionRation;
Node(float x, float y) {
acceleration = new PVector(0, 0);
velocity =PVector.random2D();
position = new PVector(x, y);
}
Node(float x, float y, float mF, float mS, float dS, float sCr) {
acceleration = new PVector(0, 0);
velocity =PVector.random2D();
position = new PVector(x, y);
maxSpeed = mF;
maxForce = mS;
desiredSeparation = dS;
separationCohesionRation = sCr;
}
void run(ArrayList<Node> nodes) {
differentiate(nodes);
update();
}
void applyForce(PVector force) {
acceleration.add(force);
}
void differentiate(ArrayList<Node> nodes) {
PVector separation = separate(nodes);
PVector cohesion = edgeCohesion(nodes);
separation.mult(separationCohesionRation);
//cohesion.mult(1.0);
applyForce(separation);
applyForce(cohesion);
}
void update() {
velocity.add(acceleration);
velocity.limit(maxSpeed);
position.add(velocity);
acceleration.mult(0);
}
PVector seek(PVector target) {
PVector desired = PVector.sub(target, position);
desired.setMag(maxSpeed);
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxForce);
return steer;
}
PVector separate(ArrayList<Node> nodes) {
PVector steer = new PVector(0, 0);
int count = 0;
for (Node other : nodes) {
float d = PVector.dist(position, other.position);
if (d>0 && d < desiredSeparation) {
PVector diff = PVector.sub(position, other.position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++;
}
}
if (count>0) {
steer.div((float)count);
}
if (steer.mag() > 0) {
steer.setMag(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
}
return steer;
}
PVector edgeCohesion (ArrayList<Node> nodes) {
PVector sum = new PVector(0, 0);
int this_index = nodes.indexOf(this);
if (this_index!=0 && this_index!=nodes.size()-1) {
sum.add(nodes.get(this_index-1).position).add(nodes.get(this_index+1).position);
} else if (this_index == 0) {
sum.add(nodes.get(nodes.size()-1).position).add(nodes.get(this_index+1).position);
} else if (this_index == nodes.size()-1) {
sum.add(nodes.get(this_index-1).position).add(nodes.get(0).position);
}
sum.div(2);
return seek(sum);
}
}
Code after first Answer:
// PARAMETERS
float _maxForce = 0.9;
float _maxSpeed = 1;
float _desiredSeparation = 30;
float _separationCohesionRation = 1.1;
float _maxEdgeLen = 8;
boolean seed = false;
DifferentialLine _diff_line;
ArrayList<DifferentialLine> lines = new ArrayList<DifferentialLine>();
void setup() {
frameRate(60);
background(0);
size(1280, 720);
}
void draw() {
if(seed == true){
//println(frameCount);
background(0);
//_diff_line.run();
//_diff_line.render();
for (DifferentialLine line : lines) {
line.run();
line.render();
}
}
}
void mousePressed(){
seed = true;
DifferentialLine newLine = new DifferentialLine(_maxForce, _maxSpeed, _desiredSeparation, _separationCohesionRation, _maxEdgeLen);
malewas();
lines.add(newLine);
}
void malewas(){
_diff_line = new DifferentialLine(_maxForce, _maxSpeed, _desiredSeparation, _separationCohesionRation, _maxEdgeLen);
//fill(0);
float nodesStart = 3;
float angInc = TWO_PI/nodesStart;
float rayStart = 5;
for (float a=0; a<TWO_PI; a+=angInc) {
float x = mouseX + cos(a) * rayStart;
float y = mouseY + sin(a) * rayStart;
_diff_line.addNode(new Node(x, y, _diff_line.maxForce, _diff_line.maxSpeed, _diff_line.desiredSeparation, _diff_line.separationCohesionRation));
//println(mouseX);
//println(mouseY);
}
}
class DifferentialLine {
ArrayList<Node> nodes;
float maxForce;
float maxSpeed;
float desiredSeparation;
float separationCohesionRation;
float maxEdgeLen;
DifferentialLine(float mF, float mS, float dS, float sCr, float eL) {
nodes = new ArrayList<Node>();
maxSpeed = mF;
maxForce = mS;
desiredSeparation = dS;
separationCohesionRation = sCr;
maxEdgeLen = eL;
}
void run() {
for (Node n : nodes) {
n.run(nodes);
}
growth();
}
void addNode(Node n) {
nodes.add(n);
}
void addNodeAt(Node n, int index) {
nodes.add(index, n);
}
void growth() {
for (int i=0; i<nodes.size()-1; i++) {
Node n1 = nodes.get(i);
Node n2 = nodes.get(i+1);
float d = PVector.dist(n1.position, n2.position);
if (d>maxEdgeLen) { // Can add more rules for inserting nodes
int index = nodes.indexOf(n2);
PVector middleNode = PVector.add(n1.position, n2.position).div(2);
addNodeAt(new Node(middleNode.x, middleNode.y, maxForce, maxSpeed, desiredSeparation, separationCohesionRation), index);
}
}
}
void render() {
for (int i=0; i<nodes.size()-1; i++) {
PVector p1 = nodes.get(i).position;
PVector p2 = nodes.get(i+1).position;
line(p1.x, p1.y, p2.x, p2.y);
colorMode(HSB);
stroke(255);
//stroke(10,frameCount*0.3,100);
//stroke(255);//Farbe
strokeWeight(1); //Strichstärke
if (i==nodes.size()-2) {
line(p2.x, p2.y, nodes.get(0).position.x, nodes.get(0).position.y);
}
}
}
}
class Node {
PVector position;
PVector velocity;
PVector acceleration;
float maxForce;
float maxSpeed;
float desiredSeparation;
float separationCohesionRation;
Node(float x, float y) {
acceleration = new PVector(0, 0);
velocity =PVector.random2D();
position = new PVector(x, y);
}
Node(float x, float y, float mF, float mS, float dS, float sCr) {
acceleration = new PVector(0, 0);
velocity =PVector.random2D();
position = new PVector(x, y);
maxSpeed = mF;
maxForce = mS;
desiredSeparation = dS;
separationCohesionRation = sCr;
}
void run(ArrayList<Node> nodes) {
differentiate(nodes);
update();
}
void applyForce(PVector force) {
acceleration.add(force);
}
void differentiate(ArrayList<Node> nodes) {
PVector separation = separate(nodes);
PVector cohesion = edgeCohesion(nodes);
separation.mult(separationCohesionRation);
//cohesion.mult(1.0);
applyForce(separation);
applyForce(cohesion);
}
void update() {
velocity.add(acceleration);
velocity.limit(maxSpeed);
position.add(velocity);
acceleration.mult(0);
}
PVector seek(PVector target) {
PVector desired = PVector.sub(target, position);
desired.setMag(maxSpeed);
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxForce);
return steer;
}
PVector separate(ArrayList<Node> nodes) {
PVector steer = new PVector(0, 0);
int count = 0;
for (Node other : nodes) {
float d = PVector.dist(position, other.position);
if (d>0 && d < desiredSeparation) {
PVector diff = PVector.sub(position, other.position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++;
}
}
if (count>0) {
steer.div((float)count);
}
if (steer.mag() > 0) {
steer.setMag(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
}
return steer;
}
PVector edgeCohesion (ArrayList<Node> nodes) {
PVector sum = new PVector(0, 0);
int this_index = nodes.indexOf(this);
if (this_index!=0 && this_index!=nodes.size()-1) {
sum.add(nodes.get(this_index-1).position).add(nodes.get(this_index+1).position);
} else if (this_index == 0) {
sum.add(nodes.get(nodes.size()-1).position).add(nodes.get(this_index+1).position);
} else if (this_index == nodes.size()-1) {
sum.add(nodes.get(this_index-1).position).add(nodes.get(0).position);
}
sum.div(2);
return seek(sum);
}
}
Problem
While you do in fact create a new shape with each mouse click, you're always assigning it to the same variable (_diff_line):
_diff_line = new DifferentialLine(_maxForce, _maxSpeed, _desiredSeparation, _separationCohesionRation, _maxEdgeLen);
So when you call _diff_line.run() and _diff_line.render() it is only ever operating on the one most recently created. The old ones no longer exist.
Solution
To fix this, you'd need to assign each new line to a different variable. Most likely you'd do this by creating an Array or ArrayList and adding a new DifferentialLine to the array on each click:
// create an ArrayList to hold all the lines
ArrayList<DifferentialLine> lines = new ArrayList<DifferentialLine>();
void mousePressed(){
// create the new line
DifferentialLine newLine = new DifferentialLine(_maxForce, _maxSpeed, _desiredSeparation, _separationCohesionRation, _maxEdgeLen);
// ... do your node setup stuff
// add the new line to the ArrayList
lines.add(newLine);
}
Then, when you want to render them, you can loop through the ArrayList (or Array) and draw each one:
for (DifferentialLine line : lines) {
line.run();
line.render();
}
Solution
// PARAMETERS
float _maxForce = 0.9;
float _maxSpeed = 1;
float _desiredSeparation = 30;
float _separationCohesionRation = 1.1;
float _maxEdgeLen = 8;
boolean seed = false;
//DifferentialLine _diff_line;
ArrayList<DifferentialLine> lines = new ArrayList<DifferentialLine>();
void setup() {
frameRate(60);
background(0);
size(1280, 720);
}
void draw() {
if (seed == true) {
//println(frameCount);
background(0);
//_diff_line.run();
//_diff_line.render();
for (DifferentialLine line : lines) {
line.run();
line.render();
}
}
}
void mousePressed() {
seed = true;
DifferentialLine newLine = new DifferentialLine(_maxForce, _maxSpeed, _desiredSeparation, _separationCohesionRation, _maxEdgeLen);
//drawseed();
float nodesStart = 3;
float angInc = TWO_PI/nodesStart;
float rayStart = 5;
for (float a=0; a<TWO_PI; a+=angInc) {
float x = mouseX + cos(a) * rayStart;
float y = mouseY + sin(a) * rayStart;
newLine.addNode(new Node(x, y, newLine.maxForce, newLine.maxSpeed, newLine.desiredSeparation, newLine.separationCohesionRation));
//println(mouseX);
//println(mouseY);
}
lines.add(newLine);
}
/*void drawseed() {
_diff_line = new DifferentialLine(_maxForce, _maxSpeed, _desiredSeparation, _separationCohesionRation, _maxEdgeLen);
//fill(0);
float nodesStart = 3;
float angInc = TWO_PI/nodesStart;
float rayStart = 5;
for (float a=0; a<TWO_PI; a+=angInc) {
float x = mouseX + cos(a) * rayStart;
float y = mouseY + sin(a) * rayStart;
_diff_line.addNode(new Node(x, y, _diff_line.maxForce, _diff_line.maxSpeed, _diff_line.desiredSeparation, _diff_line.separationCohesionRation));
//println(mouseX);
//println(mouseY);
}
}*/
class DifferentialLine {
ArrayList<Node> nodes;
float maxForce;
float maxSpeed;
float desiredSeparation;
float separationCohesionRation;
float maxEdgeLen;
DifferentialLine(float mF, float mS, float dS, float sCr, float eL) {
nodes = new ArrayList<Node>();
maxSpeed = mF;
maxForce = mS;
desiredSeparation = dS;
separationCohesionRation = sCr;
maxEdgeLen = eL;
}
void run() {
for (Node n : nodes) {
n.run(nodes);
}
growth();
}
void addNode(Node n) {
nodes.add(n);
}
void addNodeAt(Node n, int index) {
nodes.add(index, n);
}
void growth() {
for (int i=0; i<nodes.size()-1; i++) {
Node n1 = nodes.get(i);
Node n2 = nodes.get(i+1);
float d = PVector.dist(n1.position, n2.position);
if (d>maxEdgeLen) { // Can add more rules for inserting nodes
int index = nodes.indexOf(n2);
PVector middleNode = PVector.add(n1.position, n2.position).div(2);
addNodeAt(new Node(middleNode.x, middleNode.y, maxForce, maxSpeed, desiredSeparation, separationCohesionRation), index);
}
}
}
void render() {
for (int i=0; i<nodes.size()-1; i++) {
PVector p1 = nodes.get(i).position;
PVector p2 = nodes.get(i+1).position;
line(p1.x, p1.y, p2.x, p2.y);
colorMode(HSB);
stroke(255);
//stroke(10,frameCount*0.3,100);
//stroke(255);//Farbe
strokeWeight(1); //Strichstärke
if (i==nodes.size()-2) {
line(p2.x, p2.y, nodes.get(0).position.x, nodes.get(0).position.y);
}
}
}
}
class Node {
PVector position;
PVector velocity;
PVector acceleration;
float maxForce;
float maxSpeed;
float desiredSeparation;
float separationCohesionRation;
Node(float x, float y) {
acceleration = new PVector(0, 0);
velocity =PVector.random2D();
position = new PVector(x, y);
}
Node(float x, float y, float mF, float mS, float dS, float sCr) {
acceleration = new PVector(0, 0);
velocity =PVector.random2D();
position = new PVector(x, y);
maxSpeed = mF;
maxForce = mS;
desiredSeparation = dS;
separationCohesionRation = sCr;
}
void run(ArrayList<Node> nodes) {
differentiate(nodes);
update();
}
void applyForce(PVector force) {
acceleration.add(force);
}
void differentiate(ArrayList<Node> nodes) {
PVector separation = separate(nodes);
PVector cohesion = edgeCohesion(nodes);
separation.mult(separationCohesionRation);
//cohesion.mult(1.0);
applyForce(separation);
applyForce(cohesion);
}
void update() {
velocity.add(acceleration);
velocity.limit(maxSpeed);
position.add(velocity);
acceleration.mult(0);
}
PVector seek(PVector target) {
PVector desired = PVector.sub(target, position);
desired.setMag(maxSpeed);
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxForce);
return steer;
}
PVector separate(ArrayList<Node> nodes) {
PVector steer = new PVector(0, 0);
int count = 0;
for (Node other : nodes) {
float d = PVector.dist(position, other.position);
if (d>0 && d < desiredSeparation) {
PVector diff = PVector.sub(position, other.position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++;
}
}
if (count>0) {
steer.div((float)count);
}
if (steer.mag() > 0) {
steer.setMag(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
}
return steer;
}
PVector edgeCohesion (ArrayList<Node> nodes) {
PVector sum = new PVector(0, 0);
int this_index = nodes.indexOf(this);
if (this_index!=0 && this_index!=nodes.size()-1) {
sum.add(nodes.get(this_index-1).position).add(nodes.get(this_index+1).position);
} else if (this_index == 0) {
sum.add(nodes.get(nodes.size()-1).position).add(nodes.get(this_index+1).position);
} else if (this_index == nodes.size()-1) {
sum.add(nodes.get(this_index-1).position).add(nodes.get(0).position);
}
sum.div(2);
return seek(sum);
}
}
took the code from the one other forum. This code makes resizeble rectangles. I corrected a little for displaying pictures.
if anyone knows, tell me how to calculate the position of the MovableCircle so that the initial aspect ratio is preserved.
I've implemented part of the algorithm for eBottomRight and eTopLeft, but it still works very bad and doesn't work for BottomLeft and TopRight points. I want that it will be look like Krita or PureRef resize behaviour.
Thanks for any help, regards max
this example gif: https://media.giphy.com/media/7XBNv61efV7S9DbgJO/giphy.gif
calc part:
void MovableCircle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
auto pos = mapToScene(event->pos() + _shiftMouseCoords);
qreal xl = (pos.x() == 0) ? .1 : pos.x();
qreal yl = (pos.y() == 0) ? .1 : pos.y();
qreal arl = qAbs(xl / yl);
if (circlePos_ == eBottomRight) {
if (arl > aspectRatio_) {
pos.setX(yl * aspectRatio_);
} else {
pos.setY(xl / aspectRatio_);
}
}
if (circlePos_ == eTopLeft) {
LOG_WARNING(logger, "Circle Pos: ", circlePos_, ", ", pos.x(), " ", pos.y());
LOG_WARNING(logger, "Init Aspect Ratio: ", aspectRatio_, ", Current AspectRatio:", arl);
if (arl > aspectRatio_) {
LOG_DEBUG(logger, "> Before: ", pos.x(), ", ", pos.y());
pos.setY(xl / aspectRatio_);
LOG_DEBUG(logger, "> After: ", pos.x(), ", ", pos.y());
} else {
LOG_DEBUG(logger, "< Before: ", pos.x(), ", ", pos.y());
pos.setX(yl * aspectRatio_);
LOG_DEBUG(logger, "< After: ", pos.x(), ", ", pos.y());
}
}
setPos(pos);
emit circleMoved();
}
MovableCircle class:
class MovableCircle : public QGraphicsObject
{
Q_OBJECT
public:
enum ECirclePos {
eTopLeft = 0,
eTopRight,
eBottomRight,
eBottomLeft,
};
explicit MovableCircle(ECirclePos cp, double ar, QGraphicsItem *parent = 0);
private:
QRectF boundingRect() const;
QPainterPath shape() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
QPointF _shiftMouseCoords;
private:
double aspectRatio_;
ECirclePos circlePos_;
signals:
void circleMoved();
};
MovableCircle::MovableCircle(ECirclePos cp, double ar, QGraphicsItem *parent) :
QGraphicsObject(parent), aspectRatio_(ar), circlePos_(cp)
{
setFlag(ItemClipsToShape, true);
setCursor(QCursor(Qt::PointingHandCursor));
}
QRectF MovableCircle::boundingRect() const
{
qreal adjust = 0.5;
return QRectF(-5 - adjust, -5 - adjust,
10 + adjust, 10 + adjust);
}
QPainterPath MovableCircle::shape() const
{
QPainterPath path;
qreal adjust = 0.5;
path.addEllipse(-5 - adjust, -5 - adjust,
10 + adjust, 10 + adjust);
return path;
}
void MovableCircle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setBrush(QBrush(QColor(0, 160, 230)));
painter->setPen(QPen(QColor(0, 160, 230)));
painter->drawEllipse(-5, -5, 10, 10);
}
void MovableCircle::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
_shiftMouseCoords = this->pos() - mapToScene(event->pos());
this->setCursor(QCursor(Qt::ClosedHandCursor));
}
void MovableCircle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
auto pos = mapToScene(event->pos() + _shiftMouseCoords);
qreal xl = (pos.x() == 0) ? .1 : pos.x();
qreal yl = (pos.y() == 0) ? .1 : pos.y();
qreal arl = qAbs(xl / yl);
if (circlePos_ == eBottomRight) {
if (arl > aspectRatio_) {
pos.setX(yl * aspectRatio_);
} else {
pos.setY(xl / aspectRatio_);
}
}
if (circlePos_ == eTopLeft) {
if (arl > aspectRatio_) {
pos.setY(xl / aspectRatio_);
} else {
pos.setX(yl * aspectRatio_);
}
}
setPos(pos);
emit circleMoved();
}
void MovableCircle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
this->setCursor(QCursor(Qt::PointingHandCursor));
}
MoveItem class:
class MoveItem : public QObject, public QGraphicsItem//public QGraphicsObject
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
explicit MoveItem(uint64_t& zc, QGraphicsItem *parent = 0);
~MoveItem();
signals:
protected:
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
void wheelEvent(QGraphicsSceneWheelEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
private:
QPointF shiftMouseCoords_;
QImage qimage_;
QPixmap pixmap_;
uint64_t& zCounter_;
MovableCircle *_topLeftCircle, *_topRightCircle, *_bottomLeftCircle, *_bottomRightCircle;
QSizeF _size;
QRectF rect_;
public slots:
};
MoveItem::MoveItem(uint64_t& zc, QGraphicsItem *parent) :
QGraphicsItem(parent), zCounter_(zc)
{
setZValue(zCounter_);
qimage_ = QImage("kot.png");
pixmap_ = QPixmap::fromImage(qimage_);
_size = pixmap_.size();
rect_ = qimage_.rect();
setAcceptHoverEvents(true);
setFlag(QGraphicsItem::ItemIsMovable, true);
double ar = _size.width() / _size.height();
// Top Left
_topLeftCircle = new MovableCircle(MovableCircle::eTopLeft, ar, this);
_topLeftCircle->setPos(0, 0);
// Top Right
_topRightCircle = new MovableCircle(MovableCircle::eTopRight, ar, this);
_topRightCircle->setPos(_size.width(), 0);
// Bottom Right
_bottomRightCircle = new MovableCircle(MovableCircle::eBottomRight, ar, this);
_bottomRightCircle->setPos(_size.width(), _size.height());
// Bottom Left
_bottomLeftCircle = new MovableCircle(MovableCircle::eBottomLeft, ar, this);
_bottomLeftCircle->setPos(0, _size.height());
// Signals
// If a delimiter point has been moved, so force the item to redraw
connect(_topLeftCircle, &MovableCircle::circleMoved, this, [this](){
_bottomLeftCircle->setPos( _topLeftCircle->pos().x(), _bottomLeftCircle->pos().y());
_topRightCircle->setPos(_topRightCircle->pos().x(), _topLeftCircle->pos().y());
update(); // force to Repaint
});
connect(_topRightCircle, &MovableCircle::circleMoved, this, [this](){
_topLeftCircle->setPos(_topLeftCircle->pos().x(), _topRightCircle->pos().y());
_bottomRightCircle->setPos(_topRightCircle->pos().x(), _bottomRightCircle->pos().y());
update(); // force to Repaint
});
connect(_bottomLeftCircle, &MovableCircle::circleMoved, this, [this](){
_topLeftCircle->setPos(_bottomLeftCircle->pos().x(), _topLeftCircle->pos().y());
_bottomRightCircle->setPos(_bottomRightCircle->pos().x(), _bottomLeftCircle->pos().y());
update(); // force to Repaint
});
connect(_bottomRightCircle, &MovableCircle::circleMoved, this, [this](){
_bottomLeftCircle->setPos(_bottomLeftCircle->pos().x(), _bottomRightCircle->pos().y());
_topRightCircle->setPos(_bottomRightCircle->pos().x(), _topRightCircle->pos().y());
update(); // force to Repaint
});
}
MoveItem::~MoveItem()
{
}
QRectF MoveItem::boundingRect() const
{
qreal distX = sqrt(pow(_topLeftCircle->x() - _topRightCircle->x(),2) +
pow(_topLeftCircle->y() - _topRightCircle->y(),2)); // eucledian distance
qreal distY = sqrt(pow(_topLeftCircle->x() - _bottomLeftCircle->x(),2) +
pow(_topLeftCircle->y() - _bottomLeftCircle->y(),2)); // eucledian distance
return QRectF(qMin(_topLeftCircle->pos().x(), _topRightCircle->pos().x()) ,
qMin(_topLeftCircle->pos().y(), _bottomLeftCircle->pos().y()),
distX, distY);
}
void MoveItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->drawImage(boundingRect(), qimage_);
painter->setPen(QPen(QColor(0, 160, 230),2));
painter->drawRect(boundingRect());
Q_UNUSED(widget);
}
void MoveItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
this->setPos(mapToScene(event->pos()+ shiftMouseCoords_));
}
void MoveItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
setZValue(++zCounter_);
shiftMouseCoords_ = (this->pos() - mapToScene(event->pos()))/scale();
if (event->button() == Qt::LeftButton) {
if (event->modifiers() == Qt::ShiftModifier) {
} else {
QGraphicsItem::mousePressEvent(event);
}
}
}
void MoveItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
if (event->modifiers() == Qt::ShiftModifier) {
} else {
QGraphicsItem::mousePressEvent(event);
}
}
}
I found a solution using vector math.(thanks to my colleague Dima Chernikov)
ABCD - our picture.
K' - cursor point.
D2 - the point we are looking for(new position of D)
gif example: https://media.giphy.com/media/uffXKjNNy5ykzpvsR2/giphy.gif
(circlePos_ == eBottomLeft) in code
code: (I will most likely redo it later using templates. but now it is more clear for understanding)
void MovableCircle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
auto pos = mapToScene(event->pos() + _shiftMouseCoords);
qreal xl = pos.x();
qreal yl = pos.y();
auto rect = parentItem()->boundingRect();
QPointF a(rect.x(), rect.y());
QPointF b(rect.x() + rect.width(), rect.y());
QPointF c(rect.x() + rect.width(), rect.y() + rect.height());
QPointF d(rect.x(), rect.y() + rect.height());
if (circlePos_ == eTopRight) {
Vec2d dc(c.x()-d.x(), c.y()-d.y());
Vec2d cb(b.x()-c.x(), b.y()-c.y());
Vec2d db(b.x()-d.x(), b.y()-d.y());
Vec2d dk(pos.x()-d.x(), pos.y()-d.y());
auto dc_len = dc.length();
auto cb_len = cb.length();
auto db_len = db.length();
auto dk_len = dk.length();
auto dkdb_dot = Vec2d<qreal>::dot(db, dk);
auto cos_kdb = dkdb_dot/(db_len*dk_len);
auto dd2_len = dk_len * cos_kdb;
auto x =(dd2_len * dc_len) / (std::sqrt(cb_len * cb_len + dc_len * dc_len));
auto y = std::sqrt(dd2_len * dd2_len - x * x);
if (x < 10 || y < 10) return;
pos.setX(d.x()+x);
pos.setY(d.y()-y);
}
if (circlePos_ == eBottomRight) {
Vec2d ad(d.x()-a.x(), d.y()-a.y());
Vec2d dc(c.x()-d.x(), c.y()-d.y());
Vec2d ac(c.x()-a.x(), c.y()-a.y());
Vec2d ak(pos.x()-a.x(), pos.y()-a.y());
auto ad_len = ad.length();
auto dc_len = dc.length();
auto ac_len = ac.length();
auto ak_len = ak.length();
auto akac_dot = Vec2d<qreal>::dot(ac, ak);
auto cos_kac = akac_dot/(ac_len*ak_len);
auto ad2_len = ak_len * cos_kac;
auto x =(ad2_len * dc_len) / (std::sqrt(ad_len * ad_len + dc_len * dc_len));
auto y = std::sqrt(ad2_len * ad2_len - x * x);
if (x < 10 || y < 10) return;
pos.setX(a.x()+x);
pos.setY(a.y()+y);
}
if (circlePos_ == eTopLeft) {
qDebug()<<this->parentItem()->boundingRect();
Vec2d cb(b.x()-c.x(), b.y()-c.y());
Vec2d ba(a.x()-b.x(), a.y()-b.y());
Vec2d ca(a.x()-c.x(), a.y()-c.y());
Vec2d ck(pos.x()-c.x(), pos.y()-c.y());
auto cb_len = cb.length();
auto ba_len = ba.length();
auto ca_len = ca.length();
auto ck_len = ck.length();
auto ckca_dot = Vec2d<qreal>::dot(ca, ck);
auto cos_kca = ckca_dot/(ca_len*ck_len);
auto cd2_len = ck_len * cos_kca;
auto y =(cd2_len * cb_len) / (std::sqrt(ba_len * ba_len + cb_len * cb_len));
auto x = std::sqrt(cd2_len * cd2_len - y * y);
if (x < 10 || y < 10) return;
pos.setX(c.x()-x);
pos.setY(c.y()-y);
}
if (circlePos_ == eBottomLeft) {
qDebug()<<this->parentItem()->boundingRect();
Vec2d ba(a.x()-b.x(), a.y()-b.y());
Vec2d ad(d.x()-a.x(), d.y()-a.y());
Vec2d bd(d.x()-b.x(), d.y()-b.y());
Vec2d bk(pos.x()-b.x(), pos.y()-b.y());
auto ba_len = ba.length();
auto ad_len = ad.length();
auto bd_len = bd.length();
auto bk_len = bk.length();
auto bkbd_dot = Vec2d<qreal>::dot(bd, bk);
auto cos_kdb = bkbd_dot/(bd_len*bk_len);
auto bd2_len = bk_len * cos_kdb;
auto x =(bd2_len * ba_len) / (std::sqrt(ad_len * ad_len + ba_len * ba_len));
auto y = std::sqrt(bd2_len * bd2_len - x * x);
if (x < 10 || y < 10) return;
pos.setX(b.x()-x);
pos.setY(b.y()+y);
}
setPos(pos);
emit circleMoved();
}
I have downloaded the demo program for Nucklear in LWJGL, i've managed to compile it and have it to succesfully work. Then i've tried to implement the same code into my game engine and nothing shows up, unless i disable glClear(GL_COLOR_BUFFER_BIT). At that point i can see the little Nuklear window flickering.
This is my Window class
package Engine.Renderer;
import Engine.Messages.AppMsg;
import Engine.IntApplication;
import Engine.Messages.Type;
import Simulator.Application;
import org.lwjgl.nuklear.NkColorf;
import org.lwjgl.nuklear.NkMouse;
import org.lwjgl.opengl.*;
import org.lwjgl.system.Callback;
import org.lwjgl.system.MemoryStack;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.nuklear.Nuklear.*;
import static org.lwjgl.opengl.ARBDebugOutput.*;
import static org.lwjgl.opengl.ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB;
import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;
public class Window
{
public Window(int width, int height, String title)
{
m_Width = width;
m_Height = height;
m_Title = title;
if(!glfwInit())
{
///TODO: LOG
Runtime.getRuntime().exit(1);
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
m_Window = glfwCreateWindow(m_Width, m_Height, m_Title, NULL, NULL);
if(m_Window == NULL)
{
///TODO: LOG
Runtime.getRuntime().exit(1);
}
glfwMakeContextCurrent(m_Window);
GLCapabilities caps = GL.createCapabilities();
glfwShowWindow(m_Window);
Callback debugProc = GLUtil.setupDebugMessageCallback();
if (caps.OpenGL43) {
GL43.glDebugMessageControl(GL43.GL_DEBUG_SOURCE_API, GL43.GL_DEBUG_TYPE_OTHER, GL43.GL_DEBUG_SEVERITY_NOTIFICATION, (IntBuffer)null, false);
} else if (caps.GL_KHR_debug) {
KHRDebug.glDebugMessageControl(
KHRDebug.GL_DEBUG_SOURCE_API,
KHRDebug.GL_DEBUG_TYPE_OTHER,
KHRDebug.GL_DEBUG_SEVERITY_NOTIFICATION,
(IntBuffer)null,
false
);
} else if (caps.GL_ARB_debug_output) {
glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_OTHER_ARB, GL_DEBUG_SEVERITY_LOW_ARB, (IntBuffer)null, false);
}
SetUpWindow();
renderer = new GUIRenderer();
}
public void Draw()
{
}
public void processEvents()
{
try (MemoryStack stack = stackPush()) {
IntBuffer w = stack.mallocInt(1);
IntBuffer h = stack.mallocInt(1);
glfwGetWindowSize(m_Window, w, h);
m_Width = w.get(0);
m_Height = h.get(0);
glfwGetFramebufferSize(m_Window, w, h);
m_DisplayWidth = w.get(0);
m_DisplayHeight = h.get(0);
}
nk_input_begin(NuklearContainer.ctx);
glfwPollEvents();
NkMouse mouse = NuklearContainer.ctx.input().mouse();
if (mouse.grab()) {
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
} else if (mouse.grabbed()) {
float prevX = mouse.prev().x();
float prevY = mouse.prev().y();
glfwSetCursorPos(m_Window, prevX, prevY);
mouse.pos().x(prevX);
mouse.pos().y(prevY);
} else if (mouse.ungrab()) {
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
nk_input_end(NuklearContainer.ctx);
try (MemoryStack stack = stackPush()) {
IntBuffer width = stack.mallocInt(1);
IntBuffer height = stack.mallocInt(1);
glfwGetWindowSize(m_Window, width, height);
glViewport(0, 0, width.get(0), height.get(0));
NkColorf bg = NkColorf.create().r(0.10f).g(0.18f).b(0.24f).a(1.0f);
glClearColor(bg.r(), bg.g(), bg.b(), bg.a());
}
//glClear(GL_COLOR_BUFFER_BIT);
renderer.Render();
glfwSwapBuffers(m_Window);
}
public void CleanUp()
{
glfwFreeCallbacks(m_Window);
glfwDestroyWindow(m_Window);
glfwTerminate();
}
private void SetUpWindow()
{
glfwSetKeyCallback(m_Window, (window, key, scancode, action, mods) ->
{
AppMsg msg = new AppMsg();
msg.key = key;
msg.scancode = scancode;
msg.mods = mods;
if(action == 0)
msg.type = Type.KEYUP;
if(action == 1)
msg.type = Type.KEYDOWN;
if(action == 2)
msg.type = Type.KEYREPEAT;
IntApplication.OnMsgProc(msg);
});
glfwSetMouseButtonCallback(m_Window, (window, button, action, mods) ->
{
AppMsg msg = new AppMsg();
msg.button = button;
msg.mods = mods;
if(action == 0)
msg.type = Type.MOUSEUP;
if(action == 1)
msg.type = Type.MOUSEDOWN;
Application.OnMsgProc(msg);
});
glfwSetCursorPosCallback(m_Window, (window, xpos, ypos) ->
{
AppMsg msg = new AppMsg();
msg.xpos = xpos;
msg.ypos = ypos;
msg.type = Type.MOUSEMOVE;
Application.OnMsgProc(msg);
});
glfwSetWindowCloseCallback(m_Window, (window) ->
IntApplication.OnClose());
nk_init(NuklearContainer.ctx, NuklearContainer.ALLOCATOR, null);
NuklearContainer.ctx.clip()
.copy((handle, text, len) -> {
if (len == 0) {
return;
}
try (MemoryStack stack = stackPush()) {
ByteBuffer str = stack.malloc(len + 1);
memCopy(text, memAddress(str), len);
str.put(len, (byte)0);
glfwSetClipboardString(m_Window, str);
}
})
.paste((handle, edit) -> {
long text = nglfwGetClipboardString(m_Window);
if (text != NULL) {
nnk_textedit_paste(edit, text, nnk_strlen(text));
}
});
}
private long m_Window;
static int m_Width, m_Height;
static int m_DisplayWidth, m_DisplayHeight;
private String m_Title;
GUIRenderer renderer;
}
And here is my GUIRender class
package Engine.Renderer;
import static org.lwjgl.nuklear.Nuklear.*;
import static org.lwjgl.opengl.GL20C.*;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
import static org.lwjgl.stb.STBTruetype.*;
import static org.lwjgl.stb.STBTruetype.stbtt_GetCodepointHMetrics;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.system.MemoryUtil.memAddress;
import Engine.IOUtil;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Objects;
import org.lwjgl.nuklear.*;
import org.lwjgl.stb.STBTTAlignedQuad;
import org.lwjgl.stb.STBTTFontinfo;
import org.lwjgl.stb.STBTTPackContext;
import org.lwjgl.stb.STBTTPackedchar;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.Platform;
public class GUIRenderer extends Renderer
{
public GUIRenderer()
{
super();
try
{
this.ttf = IOUtil.ioResourceToByteBuffer("C:/Windows/Fonts/Arial.ttf", 512 * 1024);
} catch (IOException e)
{
throw new RuntimeException(e);
}
if (!m_Initialized)
Initialize();
try (MemoryStack stack = stackPush()) {
NkRect rect = NkRect.mallocStack(stack);
if (nk_begin(
NuklearContainer.ctx,
"Hello World",
nk_rect(50, 50, 230, 250, rect),
NK_WINDOW_BORDER | NK_WINDOW_NO_INPUT | NK_WINDOW_NO_INPUT | NK_WINDOW_NO_INPUT | NK_WINDOW_TITLE
)) {
nk_layout_row_static(NuklearContainer.ctx, 20, 80, 1);
nk_label(NuklearContainer.ctx, "background:", NK_TEXT_LEFT);
}
}
nk_end(NuklearContainer.ctx);
}
private void Initialize()
{
String NK_SHADER_VERSION = Platform.get() == Platform.MACOSX ? "#version 150\n" : "#version 300 es\n";
String vertex_shader =
NK_SHADER_VERSION +
"uniform mat4 ProjMtx;\n" +
"in vec2 Position;\n" +
"in vec2 TexCoord;\n" +
"in vec4 Color;\n" +
"out vec2 Frag_UV;\n" +
"out vec4 Frag_Color;\n" +
"void main() {\n" +
" Frag_UV = TexCoord;\n" +
" Frag_Color = Color;\n" +
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" +
"}\n";
String fragment_shader =
NK_SHADER_VERSION +
"precision mediump float;\n" +
"uniform sampler2D Texture;\n" +
"in vec2 Frag_UV;\n" +
"in vec4 Frag_Color;\n" +
"out vec4 Out_Color;\n" +
"void main(){\n" +
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" +
"}\n";
nk_buffer_init(NuklearContainer.cmds, NuklearContainer.ALLOCATOR, BUFFER_INITIAL_SIZE);
m_Program = glCreateProgram();
m_Vertex_Shader = glCreateShader(GL_VERTEX_SHADER);
m_Fragment_Shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(m_Vertex_Shader, vertex_shader);
glShaderSource(m_Fragment_Shader, fragment_shader);
glCompileShader(m_Vertex_Shader);
glCompileShader(m_Fragment_Shader);
if (glGetShaderi(m_Vertex_Shader, GL_COMPILE_STATUS) != GL_TRUE)
{
throw new IllegalStateException();
}
if (glGetShaderi(m_Fragment_Shader, GL_COMPILE_STATUS) != GL_TRUE)
{
throw new IllegalStateException();
}
glAttachShader(m_Program, m_Vertex_Shader);
glAttachShader(m_Program, m_Fragment_Shader);
glLinkProgram(m_Program);
if (glGetProgrami(m_Program, GL_LINK_STATUS) != GL_TRUE)
{
throw new IllegalStateException();
}
m_Uniform_Texture = glGetUniformLocation(m_Program, "Texture");
m_Uniform_Proj = glGetUniformLocation(m_Program, "ProjMtx");
int attrib_pos = glGetAttribLocation(m_Program, "Position");
int attrib_uv = glGetAttribLocation(m_Program, "TexCoord");
int attrib_col = glGetAttribLocation(m_Program, "Color");
{
// buffer setup
m_Vbo = glGenBuffers();
m_Ebo = glGenBuffers();
m_Vao = glGenVertexArrays();
glBindVertexArray(m_Vao);
glBindBuffer(GL_ARRAY_BUFFER, m_Vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Ebo);
glEnableVertexAttribArray(attrib_pos);
glEnableVertexAttribArray(attrib_uv);
glEnableVertexAttribArray(attrib_col);
glVertexAttribPointer(attrib_pos, 2, GL_FLOAT, false, 20, 0);
glVertexAttribPointer(attrib_uv, 2, GL_FLOAT, false, 20, 8);
glVertexAttribPointer(attrib_col, 4, GL_UNSIGNED_BYTE, true, 20, 16);
}
{
// null texture setup
int nullTexID = glGenTextures();
NuklearContainer.null_texture.texture().id(nullTexID);
NuklearContainer.null_texture.uv().set(0.5f, 0.5f);
glBindTexture(GL_TEXTURE_2D, nullTexID);
try (MemoryStack stack = stackPush())
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, stack.ints(0xFFFFFFFF));
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
FontInit();
}
private void FontInit()
{
int BITMAP_W = 1024;
int BITMAP_H = 1024;
int FONT_HEIGHT = 18;
int fontTexID = glGenTextures();
STBTTFontinfo fontInfo = STBTTFontinfo.create();
STBTTPackedchar.Buffer cdata = STBTTPackedchar.create(95);
float scale;
float descent;
try (MemoryStack stack = stackPush()) {
stbtt_InitFont(fontInfo, ttf);
scale = stbtt_ScaleForPixelHeight(fontInfo, FONT_HEIGHT);
IntBuffer d = stack.mallocInt(1);
stbtt_GetFontVMetrics(fontInfo, null, d, null);
descent = d.get(0) * scale;
ByteBuffer bitmap = memAlloc(BITMAP_W * BITMAP_H);
STBTTPackContext pc = STBTTPackContext.mallocStack(stack);
stbtt_PackBegin(pc, bitmap, BITMAP_W, BITMAP_H, 0, 1, NULL);
stbtt_PackSetOversampling(pc, 4, 4);
stbtt_PackFontRange(pc, ttf, 0, FONT_HEIGHT, 32, cdata);
stbtt_PackEnd(pc);
// Convert R8 to RGBA8
ByteBuffer texture = memAlloc(BITMAP_W * BITMAP_H * 4);
for (int i = 0; i < bitmap.capacity(); i++) {
texture.putInt((bitmap.get(i) << 24) | 0x00FFFFFF);
}
texture.flip();
glBindTexture(GL_TEXTURE_2D, fontTexID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BITMAP_W, BITMAP_H, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
memFree(texture);
memFree(bitmap);
}
NuklearContainer.default_font
.width((handle, h, text, len) -> {
float text_width = 0;
try (MemoryStack stack = stackPush()) {
IntBuffer unicode = stack.mallocInt(1);
int glyph_len = nnk_utf_decode(text, memAddress(unicode), len);
int text_len = glyph_len;
if (glyph_len == 0) {
return 0;
}
IntBuffer advance = stack.mallocInt(1);
while (text_len <= len && glyph_len != 0) {
if (unicode.get(0) == NK_UTF_INVALID) {
break;
}
/* query currently drawn glyph information */
stbtt_GetCodepointHMetrics(fontInfo, unicode.get(0), advance, null);
text_width += advance.get(0) * scale;
/* offset next glyph */
glyph_len = nnk_utf_decode(text + text_len, memAddress(unicode), len - text_len);
text_len += glyph_len;
}
}
return text_width;
})
.height(FONT_HEIGHT)
.query((handle, font_height, glyph, codepoint, next_codepoint) -> {
try (MemoryStack stack = stackPush()) {
FloatBuffer x = stack.floats(0.0f);
FloatBuffer y = stack.floats(0.0f);
STBTTAlignedQuad q = STBTTAlignedQuad.mallocStack(stack);
IntBuffer advance = stack.mallocInt(1);
stbtt_GetPackedQuad(cdata, BITMAP_W, BITMAP_H, codepoint - 32, x, y, q, false);
stbtt_GetCodepointHMetrics(fontInfo, codepoint, advance, null);
NkUserFontGlyph ufg = NkUserFontGlyph.create(glyph);
ufg.width(q.x1() - q.x0());
ufg.height(q.y1() - q.y0());
ufg.offset().set(q.x0(), q.y0() + (FONT_HEIGHT + descent));
ufg.xadvance(advance.get(0) * scale);
ufg.uv(0).set(q.s0(), q.t0());
ufg.uv(1).set(q.s1(), q.t1());
}
})
.texture(it -> it
.id(fontTexID));
nk_style_set_font(NuklearContainer.ctx, NuklearContainer.default_font);
}
public void Render()
{
try (MemoryStack stack = stackPush())
{
// setup global state
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
// setup program
glUseProgram(m_Program);
glUniform1i(m_Uniform_Texture, 0);
glUniformMatrix4fv(m_Uniform_Proj, false, stack.floats(
2.0f / Window.m_Width, 0.0f, 0.0f, 0.0f,
0.0f, -2.0f / Window.m_Height, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f
));
glViewport(0, 0, Window.m_DisplayWidth, Window.m_DisplayHeight);
}
{
// convert from command queue into draw list and draw to screen
// allocate vertex and element buffer
glBindVertexArray(m_Vao);
glBindBuffer(GL_ARRAY_BUFFER, m_Vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Ebo);
glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, GL_STREAM_DRAW);
// load draw vertices & elements directly into vertex + element buffer
ByteBuffer vertices = Objects.requireNonNull(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY, max_vertex_buffer, null));
ByteBuffer elements = Objects.requireNonNull(glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY, max_element_buffer, null));
try (MemoryStack stack = stackPush())
{
// fill convert configuration
NkConvertConfig config = NkConvertConfig.callocStack(stack)
.vertex_layout(VERTEX_LAYOUT)
.vertex_size(20)
.vertex_alignment(4)
.null_texture(NuklearContainer.null_texture)
.circle_segment_count(22)
.curve_segment_count(22)
.arc_segment_count(22)
.global_alpha(1.0f)
.shape_AA(NK_ANTI_ALIASING_ON)
.line_AA(NK_ANTI_ALIASING_ON);
// setup buffers to load vertices and elements
NkBuffer vbuf = NkBuffer.mallocStack(stack);
NkBuffer ebuf = NkBuffer.mallocStack(stack);
nk_buffer_init_fixed(vbuf, vertices/*, max_vertex_buffer*/);
nk_buffer_init_fixed(ebuf, elements/*, max_element_buffer*/);
nk_convert(NuklearContainer.ctx, NuklearContainer.cmds, vbuf, ebuf, config);
}
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glUnmapBuffer(GL_ARRAY_BUFFER);
// iterate over and execute each draw command
float fb_scale_x = (float) Window.m_DisplayWidth / (float) Window.m_Width;
float fb_scale_y = (float) Window.m_DisplayHeight / (float) Window.m_Height;
long offset = NULL;
for (NkDrawCommand cmd = nk__draw_begin(NuklearContainer.ctx, NuklearContainer.cmds); cmd != null; cmd = nk__draw_next(cmd, NuklearContainer.cmds, NuklearContainer.ctx))
{
if (cmd.elem_count() == 0)
{
continue;
}
glBindTexture(GL_TEXTURE_2D, cmd.texture().id());
glScissor(
(int) (cmd.clip_rect().x() * fb_scale_x),
(int) ((Window.m_Height - (int) (cmd.clip_rect().y() + cmd.clip_rect().h())) * fb_scale_y),
(int) (cmd.clip_rect().w() * fb_scale_x),
(int) (cmd.clip_rect().h() * fb_scale_y)
);
glDrawElements(GL_TRIANGLES, cmd.elem_count(), GL_UNSIGNED_SHORT, offset);
offset += cmd.elem_count() * 2;
}
nk_clear(NuklearContainer.ctx);
}
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
}
private boolean m_Initialized;
public boolean IsInitialized() { return m_Initialized; }
private int BUFFER_INITIAL_SIZE = 4 * 1024;
long max_vertex_buffer = 512 * 1024;
long max_element_buffer = 128 * 1024;
private NkDrawVertexLayoutElement.Buffer VERTEX_LAYOUT = NkDrawVertexLayoutElement.create(4)
.position(0).attribute(NK_VERTEX_POSITION).format(NK_FORMAT_FLOAT).offset(0)
.position(1).attribute(NK_VERTEX_TEXCOORD).format(NK_FORMAT_FLOAT).offset(8)
.position(2).attribute(NK_VERTEX_COLOR).format(NK_FORMAT_R8G8B8A8).offset(16)
.position(3).attribute(NK_VERTEX_ATTRIBUTE_COUNT).format(NK_FORMAT_COUNT).offset(0)
.flip();
private ByteBuffer ttf;
}
I'm really sorry if the code is huge, but even just the GLFWDemo is 600+ lines long.
I'm trying to visualize migration data using particle systems. Each row of the dataset contains: source country, destination country, year, and various amounts.
Each row should be represented as a particle system representing that data.
QUESTION:
What will be the best way to create a list of countries or country objects, with x,y location attributes and maybe some other attributes that could be added later?
Entire code for reference:
// Based on Example Written by Casey Reas and Ben Fry
// Edited by Tom Bar-Gal
//particlesystem()
//addparticle()
//particle()
// ========== Table Data Stuff
Table table;
int k = 0;
String[] destCountryArray = new String[0];
String[] sourceCountryArray = new String[0];
String destCountry = "";
String prevDestCountry = "";
String sourceCountry;
// ========
int maxParticles = 12000;
ParticleSystem ps;
ParticleSystem ps2;
int n = 0, n2=0;
int emmitMultiplyer = 1;
int emmitFreq = 1;
float particleSpeed = 0.002;
float locationX = 250;
float locationY = 450;
int[] sourceX = {10, 40, 200, 400, 700};
int[] destX = {300, 600, 300, 600, 600};
int[] amount = {10, 100, 500, 800, 1000};
int highestAmount = max(amount);
// a,b,c... max*a/{a+b+c...}
ParticleSystem[] PSystems;
void setup() {
size(1200, 800);
//=============== load table and create an array of countries
table = loadTable("asylum_seekers.csv", "header");
destCountryArray = (String[]) append(destCountryArray, "Israel");
for (TableRow row : table.rows()) {
//println("going over row" + row.getString("Country / territory of asylum/residence"));
String tempCountryHolder = row.getString("Country / territory of asylum/residence");
//println("Got a temp country holder" + tempCountryHolder);
boolean exists = countryExists(tempCountryHolder);
if (exists==true) {
//println("exists, skipping");
continue;
}
println("Appending "+tempCountryHolder+" to list of length " +destCountryArray.length);
destCountryArray = (String[]) append(destCountryArray, tempCountryHolder);
println("destCountryArray length = "+ destCountryArray.length);
}
//============================
PSystems = new ParticleSystem[destCountryArray.length];
//frameRate(30);
//colorMode(RGB,255,255,255,255);
for (int i = 0; i<destCountryArray.length; i++) {
// Particle Systems syntax = multiplyer, source, destination, amount);
PSystems[i] = new ParticleSystem(1, new Vector3D(i*40+40, 100, 0), new Vector3D(i*40+40, 500, 0), 1/(i+1));
//println("PSystems " + i + " is " +PSystems[i]);
}
//ps = new ParticleSystem(1, new Vector3D(width/2, height/2, 0));
//ps2 = new ParticleSystem(1, new Vector3D(100, 200, 0));
smooth();
}
void draw() {
background(250);
//ellipse(locationX, locationY, 5, 5);
//ellipse(width/2, height/2, 5, 5);
//ellipse(100, 200, 5, 5);
//println(PSystems.length);
for (int i = 0; i<destCountryArray.length; i++) {
//println(PSystems[i]);
PSystems[i].run();
}
for (int i = 0; i<emmitMultiplyer; i++) {
for (int k = 0; k<destCountryArray.length; k++) {
if (frameCount % (k+1) == 0) {
PSystems[k].addParticle();
n++;
}
}
}
n2+=emmitMultiplyer;
fill(0);
text("Frame rate: "
+ int(frameRate), 10, 20);
println(n);
println(n);
}
// ==============================// A simple Particle class // ===============================================//
class Particle {
Vector3D loc;
Vector3D des;
Vector3D vel;
Vector3D acc;
Vector3D locHome, b, c;
float relativeSpeed;
float r;
float timer;
float t=0.0;
// Another constructor (the one we are using here)
Particle(Vector3D l, Vector3D m) {
//acc = new Vector3D(0,0.0005,0); // particle acceleration
acc = new Vector3D(0, 0, 0); // new Vector3D(random(-0.1, 0.1), random(-0.02, 0), 0);
loc = l.copy();
des = m.copy();
locHome = l.copy();
locHome.x = locHome.x+random(-2, 2);
locHome.y = locHome.y+random(-2, 2);
des.x = des.x+random(-2, 2);
des.y=des.y+random(-2, 2);
relativeSpeed = random(0.5, 1.2);
r = random(0.9, 2.3); // particle radius
timer = 10000.0; // particles lifespan
// * emmitMultiplyer = number of living
b=new Vector3D(locHome.x+random(-20, 20), locHome.y+random(120, 180), 0);
c=new Vector3D(des.x+random(-20, 30), des.y-random(120, 180), 0);
}
void run() {
update();
render();
}
// Method to update location
void update() {
if (t>=1)
return;
// https : // www.processing.org/reference/bezierPoint_.html
loc.x = bezierPoint(locHome.x, b.x, c.x, des.x, t);
loc.y = bezierPoint(locHome.y, b.y, c.y, des.y, t);
t = lerp(t, 1, particleSpeed*relativeSpeed);
//t+=particleSpeed*relativeSpeed;
// curvePoint(a, b, c, d, t)
// vel.add(acc);
// loc.add(vel);
//timer -= 1.0;
}
// Method to display
void render() {
ellipseMode(CENTER);
noStroke();
fill(70, 255);
ellipse(loc.x, loc.y, r, r);
}
// Is the particle still useful?
boolean dead() {
// if (timer <= 0.0||t>=1.0) {
if (t>=0.95) {
return true;
} else {
return false;
}
}
}
// ==============================// A ParticleSystem // ===============================================//
// A class to describe a group of Particles
// An ArrayList is used to manage the list of Particles
class ParticleSystem {
ArrayList particles; // An arraylist for all the particles
Vector3D origin; // An origin point for where particles are birthed
Vector3D dest;
int freq;
//ParticleSystem( number of particles / frame, source, destination, frequency);
ParticleSystem(int num, Vector3D v, Vector3D d, float f) {
particles = new ArrayList(); // Initialize the arraylist
origin = v.copy(); // Store the origin point
dest = d.copy();
//if (frameCount % (1/f) == 0){
for (int i = 0; i < num; i++) {
particles.add(new Particle(origin, dest)); // Add "num" amount of particles to the arraylist
}
//}
}
void run() {
// Cycle through the ArrayList backwards b/c we are deleting
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = (Particle) particles.get(i);
p.run();
if (p.dead()) {
particles.remove(i);
n--;
}
}
}
void addParticle() {
particles.add(new Particle(origin, dest));
}
//void addParticle(Particle p) {
// particles.add(p);
//}
// A method to test if the particle system still has particles
boolean dead() {
if (particles.isEmpty()) {
return true;
} else {
return false;
}
}
}
//=================================================== Class Country
public class Country {
public float countryIndex;
public float countryLocationX;
public float countryLocationY;
public float countryName;
}
// ================================================ Simple Vector3D Class
public class Vector3D {
public float x;
public float y;
public float z;
Vector3D(float x_, float y_, float z_) {
x = x_;
y = y_;
z = z_;
}
Vector3D(float x_, float y_) {
x = x_;
y = y_;
z = 0f;
}
Vector3D() {
x = 0f;
y = 0f;
z = 0f;
}
void setX(float x_) {
x = x_;
}
void setY(float y_) {
y = y_;
}
void setZ(float z_) {
z = z_;
}
void setXY(float x_, float y_) {
x = x_;
y = y_;
}
void setXYZ(float x_, float y_, float z_) {
x = x_;
y = y_;
z = z_;
}
void setXYZ(Vector3D v) {
x = v.x;
y = v.y;
z = v.z;
}
public float magnitude() {
return (float) Math.sqrt(x*x + y*y + z*z);
}
public Vector3D copy() {
return new Vector3D(x, y, z);
}
public Vector3D copy(Vector3D v) {
return new Vector3D(v.x, v.y, v.z);
}
public void add(Vector3D v) {
x += v.x;
y += v.y;
z += v.z;
}
public void sub(Vector3D v) {
x -= v.x;
y -= v.y;
z -= v.z;
}
public void mult(float n) {
x *= n;
y *= n;
z *= n;
}
public void div(float n) {
x /= n;
y /= n;
z /= n;
}
public void normalize() {
float m = magnitude();
if (m > 0) {
div(m);
}
}
public void limit(float max) {
if (magnitude() > max) {
normalize();
mult(max);
}
}
public float heading2D() {
float angle = (float) Math.atan2(-y, x);
return -1*angle;
}
public Vector3D add(Vector3D v1, Vector3D v2) {
Vector3D v = new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
return v;
}
public Vector3D sub(Vector3D v1, Vector3D v2) {
Vector3D v = new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
return v;
}
public Vector3D div(Vector3D v1, float n) {
Vector3D v = new Vector3D(v1.x/n, v1.y/n, v1.z/n);
return v;
}
public Vector3D mult(Vector3D v1, float n) {
Vector3D v = new Vector3D(v1.x*n, v1.y*n, v1.z*n);
return v;
}
public float distance (Vector3D v1, Vector3D v2) {
float dx = v1.x - v2.x;
float dy = v1.y - v2.y;
float dz = v1.z - v2.z;
return (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
}
}
boolean countryExists(String tempCountryHolder) {
for (int i = 0; i < destCountryArray.length; i++) {
//println("comparing '" +tempCountryHolder +"' with '"+destCountryArray[i] + "'");
if (tempCountryHolder.equals(destCountryArray[i]) == true) {
//println("found : "+ tempCountryHolder);
return true; // it exists
} //if
} //for
return false ; // not found
}//func
answer was: hashmap of hashmaps
HashMap<String, HashMap> countries = new HashMap<String, HashMap>();
for (int i=0; i<destCountryArray.length; i++) {
HashMap<String, Float> country = new HashMap<String, Float>();
countries.put(destCountryArray[i], country);
country.put("x", i*20.0);
country.put("y", i*40.0);
}
for (Map.Entry me : countries.entrySet()) {
print(me.getKey() + " is ");
println(me.getValue());
}
You probably don't want to use a nested HashMap like your answer suggests. You probably want to use your own class instead. Something like this:
HashMap<String, Point> countries = new HashMap<String, Point>();
void setup(){
countries.put("one", new Point(2, 3));
countries.put("four", new Point(5, 6));
}
void draw(){
Point pOne = countries.get("one");
point(pOne.x, pOne.y);
}
class Point{
float x;
float y;
public Point(float x, float y){
this.x = x;
this.y = y;
}
}
Or better yet, you could just use Processing's PVector class, which already represents points:
HashMap<String, PVector> countries = new HashMap<String, PVector>();
void setup(){
countries.put("one", new PVector(2, 3));
countries.put("four", new PVector(5, 6));
}
void draw(){
PVector pOne = countries.get("one");
point(pOne.x, pOne.y);
}
More info can be found in the reference. Shameless self-promotion: here is a tutorial on using classes, and here is a tutorial on creating your own classes.
Is it possible to perform blurring of a whole scene of AndEngine? I would like to blur a whole scene but not to blur a child scene. Da you have any suggestions?
public class MyScene extends Scene {
private Sprite backgroundSprite;
private Sprite playerSprite;
private Sprite enemySprite;
public void create() {
attachChild(backgroundSprite);
attachChild(playerSprite);
attachChild(enemySprite);
}
public void openChildScene() {
// PERFORM BLURRING of a scene
CameraScene childScene = new CameraScene(camera);
// attach children
.
.
.
childScene.setBackgroundEnabled(false);
setChildScene(childScene);
}
}
This is absolutely possible. Take a look at the Shader example in the AndEngineExamples project. You basically have to render the scene to an (empty) Texture and then use a shader on it.
RadialBlur Example:
package org.andengine.examples;
import org.andengine.engine.Engine;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.sprite.UncoloredSprite;
import org.andengine.entity.util.FPSLogger;
import org.andengine.input.touch.TouchEvent;
import org.andengine.input.touch.detector.ClickDetector;
import org.andengine.input.touch.detector.ClickDetector.IClickDetectorListener;
import org.andengine.opengl.shader.PositionTextureCoordinatesShaderProgram;
import org.andengine.opengl.shader.ShaderProgram;
import org.andengine.opengl.shader.constants.ShaderProgramConstants;
import org.andengine.opengl.shader.exception.ShaderProgramException;
import org.andengine.opengl.shader.exception.ShaderProgramLinkException;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegionFactory;
import org.andengine.opengl.texture.render.RenderTexture;
import org.andengine.opengl.util.GLState;
import org.andengine.opengl.vbo.attribute.VertexBufferObjectAttributes;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import android.opengl.GLES20;
/**
* (c) Zynga 2011
*
* #author Nicolas Gramlich <ngramlich#zynga.com>
* #since 16:55:18 - 06.11.2011
*/
public class RadialBlurExample extends SimpleBaseGameActivity implements IOnSceneTouchListener, IClickDetectorListener {
// ===========================================================
// Constants
// ===========================================================
private static final int CAMERA_WIDTH = 720;
private static final int CAMERA_HEIGHT = 480;
// ===========================================================
// Fields
// ===========================================================
private Camera mCamera;
private BitmapTextureAtlas mBitmapTextureAtlas;
private ITextureRegion mFaceTextureRegion;
private boolean mRadialBlurring = true;
private float mRadialBlurCenterX = 0.5f;
private float mRadialBlurCenterY = 0.5f;
private ClickDetector mClickDetector;
// ===========================================================
// Constructors
// ===========================================================
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
#Override
public EngineOptions onCreateEngineOptions() {
this.mCamera = new Camera(0, 0, RadialBlurExample.CAMERA_WIDTH, RadialBlurExample.CAMERA_HEIGHT);
return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(RadialBlurExample.CAMERA_WIDTH, RadialBlurExample.CAMERA_HEIGHT), this.mCamera);
}
#Override
public Engine onCreateEngine(EngineOptions pEngineOptions) {
return new Engine(pEngineOptions) {
private boolean mRenderTextureInitialized;
private RenderTexture mRenderTexture;
private UncoloredSprite mRenderTextureSprite;
#Override
public void onDrawFrame(final GLState pGLState) throws InterruptedException {
final boolean firstFrame = !this.mRenderTextureInitialized;
if(firstFrame) {
this.initRenderTextures(pGLState);
this.mRenderTextureInitialized = true;
}
final int surfaceWidth = this.mCamera.getSurfaceWidth();
final int surfaceHeight = this.mCamera.getSurfaceHeight();
this.mRenderTexture.begin(pGLState);
{
/* Draw current frame. */
super.onDrawFrame(pGLState);
}
this.mRenderTexture.end(pGLState);
/* Draw rendered texture with custom shader. */
{
pGLState.pushProjectionGLMatrix();
pGLState.orthoProjectionGLMatrixf(0, surfaceWidth, 0, surfaceHeight, -1, 1);
{
this.mRenderTextureSprite.onDraw(pGLState, this.mCamera);
}
pGLState.popProjectionGLMatrix();
}
}
private void initRenderTextures(final GLState pGLState) {
final int surfaceWidth = this.mCamera.getSurfaceWidth();
final int surfaceHeight = this.mCamera.getSurfaceHeight();
this.mRenderTexture = new RenderTexture(RadialBlurExample.this.getTextureManager(), surfaceWidth, surfaceHeight);
this.mRenderTexture.init(pGLState);
final ITextureRegion renderTextureTextureRegion = TextureRegionFactory.extractFromTexture(this.mRenderTexture);
this.mRenderTextureSprite = new UncoloredSprite(0, 0, renderTextureTextureRegion, this.getVertexBufferObjectManager()) {
#Override
protected void preDraw(final GLState pGLState, final Camera pCamera) {
if(RadialBlurExample.this.mRadialBlurring) {
this.setShaderProgram(RadialBlurShaderProgram.getInstance());
} else {
this.setShaderProgram(PositionTextureCoordinatesShaderProgram.getInstance());
}
super.preDraw(pGLState, pCamera);
GLES20.glUniform2f(RadialBlurShaderProgram.sUniformRadialBlurCenterLocation, RadialBlurExample.this.mRadialBlurCenterX, 1 - RadialBlurExample.this.mRadialBlurCenterY);
}
};
}
};
}
#Override
public void onCreateResources() {
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 512, 512);
this.mFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlas, this, "badge_large.png", 0, 0);
this.mBitmapTextureAtlas.load();
this.getShaderProgramManager().loadShaderProgram(RadialBlurShaderProgram.getInstance());
}
#Override
public Scene onCreateScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene();
/* Calculate the coordinates for the face, so its centered on the camera. */
final float centerX = (RadialBlurExample.CAMERA_WIDTH - this.mFaceTextureRegion.getWidth()) / 2;
final float centerY = (RadialBlurExample.CAMERA_HEIGHT - this.mFaceTextureRegion.getHeight()) / 2;
/* Create the face and add it to the scene. */
final Sprite face = new Sprite(centerX, centerY, this.mFaceTextureRegion, this.getVertexBufferObjectManager());
// face.setScale(3);
scene.attachChild(face);
/* TouchListener */
this.mClickDetector = new ClickDetector(this);
scene.setOnSceneTouchListener(this);
return scene;
}
#Override
public void onClick(final ClickDetector pClickDetector, final int pPointerID, final float pSceneX, final float pSceneY) {
this.mRadialBlurring = !this.mRadialBlurring;
}
#Override
public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
this.mClickDetector.onSceneTouchEvent(pScene, pSceneTouchEvent);
this.mRadialBlurCenterX = pSceneTouchEvent.getMotionEvent().getX() / this.mCamera.getSurfaceWidth();
this.mRadialBlurCenterY = pSceneTouchEvent.getMotionEvent().getY() / this.mCamera.getSurfaceHeight();
return true;
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public static class RadialBlurShaderProgram extends ShaderProgram {
// ===========================================================
// Constants
// ===========================================================
private static RadialBlurShaderProgram INSTANCE;
public static final String VERTEXSHADER =
"uniform mat4 " + ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX + ";\n" +
"attribute vec4 " + ShaderProgramConstants.ATTRIBUTE_POSITION + ";\n" +
"attribute vec2 " + ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES + ";\n" +
"varying vec2 " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n" +
"void main() {\n" +
" " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " = " + ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES + ";\n" +
" gl_Position = " + ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX + " * " + ShaderProgramConstants.ATTRIBUTE_POSITION + ";\n" +
"}";
private static final String UNIFORM_RADIALBLUR_CENTER = "u_radialblur_center";
public static final String FRAGMENTSHADER =
"precision lowp float;\n" +
"uniform sampler2D " + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ";\n" +
"varying mediump vec2 " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n" +
"uniform vec2 " + RadialBlurShaderProgram.UNIFORM_RADIALBLUR_CENTER + ";\n" +
"const float sampleShare = (1.0 / 11.0);\n" +
"const float sampleDist = 1.0;\n" +
"const float sampleStrength = 1.25;\n" +
"void main() {\n" +
/* The actual (unburred) sample. */
" vec4 color = texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ");\n" +
/* Calculate direction towards center of the blur. */
" vec2 direction = " + RadialBlurShaderProgram.UNIFORM_RADIALBLUR_CENTER + " - " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n" +
/* Calculate the distance to the center of the blur. */
" float distance = sqrt(direction.x * direction.x + direction.y * direction.y);\n" +
/* Normalize the direction (reuse the distance). */
" direction = direction / distance;\n" +
" vec4 sum = color * sampleShare;\n" +
/* Take 10 additional samples along the direction towards the center of the blur. */
" vec2 directionSampleDist = direction * sampleDist;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.08 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.05 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.03 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.02 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.01 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.01 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.02 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.03 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.05 * directionSampleDist) * sampleShare;\n" +
" sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.08 * directionSampleDist) * sampleShare;\n" +
/* Weighten the blur effect with the distance to the center of the blur (further out is blurred more). */
" float t = sqrt(distance) * sampleStrength;\n" +
" t = clamp(t, 0.0, 1.0);\n" + // 0 <= t >= 1
/* Blend the original color with the averaged pixels. */
" gl_FragColor = mix(color, sum, t);\n" +
"}";
// ===========================================================
// Fields
// ===========================================================
public static int sUniformModelViewPositionMatrixLocation = ShaderProgramConstants.LOCATION_INVALID;
public static int sUniformTexture0Location = ShaderProgramConstants.LOCATION_INVALID;
public static int sUniformRadialBlurCenterLocation = ShaderProgramConstants.LOCATION_INVALID;
// ===========================================================
// Constructors
// ===========================================================
private RadialBlurShaderProgram() {
super(RadialBlurShaderProgram.VERTEXSHADER, RadialBlurShaderProgram.FRAGMENTSHADER);
}
public static RadialBlurShaderProgram getInstance() {
if(RadialBlurShaderProgram.INSTANCE == null) {
RadialBlurShaderProgram.INSTANCE = new RadialBlurShaderProgram();
}
return RadialBlurShaderProgram.INSTANCE;
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
#Override
protected void link(final GLState pGLState) throws ShaderProgramLinkException {
GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_POSITION_LOCATION, ShaderProgramConstants.ATTRIBUTE_POSITION);
GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES_LOCATION, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES);
super.link(pGLState);
RadialBlurShaderProgram.sUniformModelViewPositionMatrixLocation = this.getUniformLocation(ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX);
RadialBlurShaderProgram.sUniformTexture0Location = this.getUniformLocation(ShaderProgramConstants.UNIFORM_TEXTURE_0);
RadialBlurShaderProgram.sUniformRadialBlurCenterLocation = this.getUniformLocation(RadialBlurShaderProgram.UNIFORM_RADIALBLUR_CENTER);
}
#Override
public void bind(final GLState pGLState, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
GLES20.glDisableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION);
super.bind(pGLState, pVertexBufferObjectAttributes);
GLES20.glUniformMatrix4fv(RadialBlurShaderProgram.sUniformModelViewPositionMatrixLocation, 1, false, pGLState.getModelViewProjectionGLMatrix(), 0);
GLES20.glUniform1i(RadialBlurShaderProgram.sUniformTexture0Location, 0);
}
#Override
public void unbind(final GLState pGLState) throws ShaderProgramException {
GLES20.glEnableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION);
super.unbind(pGLState);
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
}