$25
CS 45500
For this assignment, you will write an event-driven program that responds to several kinds of mouse events.
In the zip file there is an executable jar file, hw3_demo.jar, that you can run. There is also a program file Hw3.java. You need to complete the program file Hw3.java so that it runs the same way the demo program runs.
The program hw3_demo.jar lets you click on geometric shapes and drag them around the window. If you click on a point that is inside of several (overlapping) shapes, then all of the shapes will drag around together. When you release the mouse, or if the mouse moves off of the program window, the shapes stop moving.
You will need to implement the MouseListener and MouseMotionListener interfaces (you may want to also implement the KeyListener interface). You will need to write code for (at least) the mousePressed(), mouseReleased(), mouseExited(), and mouseDragged() methods. You can write your event listeners in whichever style you prefer. Probably the easiest way is to either write an anonymous local class (in the body of the Hw3 constructor) for each event listener interface, or have the class Hw3 implement all the event listener interfaces (look at the examples InteractiveFrame_v3.java and InteractiveFrame_v9.java from event-examples.zip).
If you want to see more examples of event handlers, look at the programs that come with renderer_2.zip, like InteractiveCube_R2.java or InteractiveModelsAll_R2.java.
Here are some suggestions for writing your program. You have to write this program in several (many) stages. First, give the program very basic event handlers that just print the event objects to stdout. Then, use the MouseEvent api to print out just the information that is relevant (like the x and y coordinates of a mouse click). When you know the pixel coordinates of a mouse click, you need to transform the pixel coordinates into the corresponding (x, y, z) coordinates in camera space. The geometric objects are all in the z = -10 plane, so you need to transform the 2-dimensional pixel coordinates into the appropriate (x, y) coordinates of the z = -10 plane. Print this information to stdout and then click on several obvious points in the window and make sure your coordinate transformation is correct. When you can click on a point and get its correct camera space coordinates, then you are ready to determine if you are clicking on a geometric shape. You know the location and size of each shape in the z = -10 plane. So you should be able to tell if a mouse click is inside a shape. Write a boolean hit() method that determines if a mouse click "hits" a shape. Iterate through the scene.modelList and look for a shape that is hit and print the model's name to stdout (this code should could be in the mousePressed() method). Here is an important hint. You probably don't want to work directly with the 3D models themselves since they are meant for 3d rendering (all the vertices and line segments in the Circle object are not going to be of much use when you want to see if you clicked within the circle). It would be a good idea to create another representation of each shape that would be easier to work with when finding hits. For example, for the circle, all you need to know are its center and radius to determine a hit.
When you can determine if a mouse click is within a shape, you are ready to start working with the mouseDragged() method. A user will press down on the mouse button, drag the mouse, then release the mouse button. You get a call to mousePressed() when the user presses down on the mouse button and you get a call to mouseReleased() when the user releases the mouse button (or a call to mouseExited() if the dragged mouse leaves the window). Between the calls to mousePressed() and mouseReleased(), while the mouse is being dragged, you will get calls to mouseDragged(). Each call you receive to mouseDragged() represents some amount of movement of the mouse, sometimes its just one pixel worth of movement, sometimes it is dozens of pixels worth of movement. You need to begin with writing a simple combination of mousePressed(), mouseDragged(), and mouseReleased() methods that just keeps track of where the mouse is when its pressed, where the mouse is currently at each call to mouseDragged(), and where the mouse is when the mouse is released. Print all this information to stdout and get a feel for how mouse dragging works. Compute the "distance traveled" by the mouse between calls to mouseDragged() and print this to stdout (in both pixel coordinates and camera coordinates and in both the x-direction and the y-direction). The distance traveled by the mouse in camera coordinates is vital for being able to move a shape by the appropriate amount.
Now you know when a mouse press lands within a shape and how far a mouse drag moved. So now you can take the x and y distances traveled by the mouse (between calls to the mouseDragged() method) and use them to update the location of the shape that was hit. This part is similar to the last assignment. You need to update the x and y coordinates of each vertex in the model by the distance (in camera space) that the mouse moved. (Be sure to also update your alternative representation of each model.) After updating each model, the scene needs to be rendered. Your listener method should end with a block of code like this.
// Render again.
fb.clearFB(Color.black);
Pipeline.render(scene, fb.vp);
fbf.fbp.update();
fbf.repaint();
Here is one little detail that you will need to deal with. When you click on the mouse, the pixel coordinates that Java gives you are relative to the whole Java window, not to the framebuffer panel within the window. Another way to put this is that pixel (0, 0) is not the upper left hand corner of the framebuffer, it is the upper left hand corner of the title bar of the Java window. You will need to subtract a small offset from the coordinates that Java gives you in order to compensate for the title bar at the top of the window and the small border on the left edge of the window.
Here is another useful idea. The steps above tell you to print out a lot of information to stdout. All of that output is useful, so you probably don't want to delete the code that produces it. But you don't always want to see all of that output. You can create a keyboard command (or several keyboard commands) to turn on and off the "debugging" output.