Rotating 3D-Objects based on KeyEvents

Tutorials concerning the OpenGL® ES cross-platform API for full-function 2D and 3D graphics on the Google-Android platform.

Rotating 3D-Objects based on KeyEvents

Postby plusminus » Sat Nov 17, 2007 5:46 pm

Rotating 3D-Objects based on KeyEvents


This Tutorial is merged from TheChuckster's OpenGL KeyEvent-Question he posted here in the board and the Colored 3D Cube (the extended one)

What is this: This tutorial shows how to create colored 3D Objects using the OpenGL® ES cross-platform API.

What you learn: You will learn how easy it is, to create a Colored 3D Pyramid, using OpenGL® ES and How to rotate it using KeyEvents(This time the KeyPad).

Read before:
:?: Problems/Questions: Write it right below...

Difficulty: 1.75 of 5 :)

What it will look like:
Image


Most interesting:
There are only slight differences to the Colored 3D Cube.
Mainly there are just the following parts that changed:

We react on KeyEvents in the Activity by overwriting its onKeyDown(...)-Events.
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.     /*
  2.      * handles keypad input and send rotation-info to the 3D-Object
  3.      * @see android.view.View#onKeyDown(int, android.os.KeyEvent)
  4.      */
  5.     @Override
  6.     public boolean onKeyDown(int keyCode, KeyEvent msg) {
  7.         if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
  8.                 myGLView.rotateY(-ANGLE_DIFF);
  9.             return true;
  10.         } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
  11.                 myGLView.rotateY(ANGLE_DIFF);
  12.             return true;
  13.         } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
  14.                 myGLView.rotateZ(-ANGLE_DIFF);
  15.             return true;
  16.         } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
  17.                 myGLView.rotateZ(ANGLE_DIFF);
  18.             return true;
  19.         }
  20.         return false;
  21.     }
Parsed in 0.032 seconds, using GeSHi 1.0.8.4


We also added the following simple lines to our GLView-Class to accomplish rotation functionality:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. class GLView extends View {
  2.         // ...
  3.         private float mAngleY;
  4.         private float mAngleZ;
  5.         // ...
  6.  
  7.         public void rotateY(float f){
  8.                 this.mAngleY += f;
  9.         }
  10.        
  11.         public void rotateZ(float f){
  12.                 this.mAngleZ += f;
  13.         }
  14.         // ...
  15.         protected void onDraw(Canvas canvas) {
  16.         // ...
  17.         // New rotation based on two independent angles.
  18.                 gl.glRotatef(mAngleY,        1, 0, 0);
  19.                 gl.glRotatef(mAngleZ,        0, 1, 0);
  20.         // ...
  21.         }
  22. // ...
  23. }
Parsed in 0.032 seconds, using GeSHi 1.0.8.4


The full source:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package org.anddev.android.threedcolorobjects;
  2.  
  3. import java.nio.ByteBuffer;
  4. import java.nio.ByteOrder;
  5. import java.nio.IntBuffer;
  6.  
  7. import javax.microedition.khronos.opengles.GL10;
  8.  
  9. import android.app.Activity;
  10. import android.content.Context;
  11. import android.graphics.Canvas;
  12. import android.graphics.OpenGLContext;
  13. import android.os.Bundle;
  14. import android.os.Handler;
  15. import android.os.Message;
  16. import android.os.SystemClock;
  17. import android.view.KeyEvent;
  18. import android.view.View;
  19.  
  20. /**
  21.  * Example of how to use OpenGL|ES in a custom view
  22.  */
  23.  
  24. public class ThreeDColorObjects extends Activity {
  25.         /** Angle-Amount the object is turned, when hitting*/
  26.         private static final float ANGLE_DIFF = 2.0f;
  27.         protected GLView myGLView = null;
  28.  
  29.         @Override
  30.         protected void onCreate(Bundle icicle) {
  31.                 super.onCreate(icicle);
  32.                 myGLView = new GLView(getApplication());
  33.                 setContentView(myGLView);
  34.         }
  35.  
  36.         @Override
  37.         protected void onResume() {
  38.                 super.onResume();
  39.                 //android.os.Debug.startMethodTracing("/tmp/trace/GLView1.dmtrace",
  40.                 //  8 * 1024 * 1024);
  41.         }
  42.  
  43.         @Override
  44.         protected void onStop() {
  45.                 super.onStop();
  46.                 //android.os.Debug.stopMethodTracing();
  47.         }
  48.  
  49.     /*
  50.      * handles keypad input and send rotation-info to the 3D-Object
  51.      * @see android.view.View#onKeyDown(int, android.os.KeyEvent)
  52.      */
  53.     @Override
  54.     public boolean onKeyDown(int keyCode, KeyEvent msg) {
  55.         if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
  56.                 myGLView.rotateY(-ANGLE_DIFF);
  57.             return true;
  58.         } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
  59.                 myGLView.rotateY(ANGLE_DIFF);
  60.             return true;
  61.         } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
  62.                 myGLView.rotateZ(-ANGLE_DIFF);
  63.             return true;
  64.         } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
  65.                 myGLView.rotateZ(ANGLE_DIFF);
  66.             return true;
  67.         }
  68.         return false;
  69.     }
  70. }
  71.  
  72. class GLView extends View {
  73.        
  74.         private OpenGLContext mGLContext;
  75.         private ThreeDObject mThreeDObj;
  76.         private float mAngleY;
  77.         private float mAngleZ;
  78.         private long mNextTime;
  79.         private boolean mAnimate;
  80.        
  81.         public void rotateY(float f){
  82.                 this.mAngleY += f;
  83.         }
  84.        
  85.         public void rotateZ(float f){
  86.                 this.mAngleZ += f;
  87.         }
  88.  
  89.         /**
  90.          * The View constructor is a good place to allocate our OpenGL context
  91.          */
  92.         public GLView(Context context) {
  93.                 super(context);
  94.  
  95.                 /*
  96.                  * Create an OpenGL|ES context. This must be done only once, an
  97.                  * OpenGL contex is a somewhat heavy object.
  98.                  */
  99.                 mGLContext = new OpenGLContext(0);
  100.                 mThreeDObj = new Cube();
  101.                 mAnimate = false;
  102.         }
  103.  
  104.         /*
  105.          * Start the animation only once we're attached to a window
  106.          * @see android.view.View#onAttachedToWindow()
  107.          */
  108.         @Override
  109.         protected void onAttachedToWindow() {
  110.                 mAnimate = true;
  111.                 Message msg = mHandler.obtainMessage(INVALIDATE);
  112.                 mNextTime = SystemClock.uptimeMillis();
  113.                 mHandler.sendMessageAtTime(msg, mNextTime);
  114.                 super.onAttachedToWindow();
  115.         }
  116.  
  117.         /*
  118.          * Make sure to stop the animation when we're no longer on screen,
  119.          * failing to do so will cause most of the view hierarchy to be
  120.          * leaked until the current process dies.
  121.          * @see android.view.View#onDetachedFromWindow()
  122.          */
  123.         @Override
  124.         protected void onDetachedFromWindow() {
  125.                 mAnimate = false;
  126.                 super.onDetachedFromWindow();
  127.         }
  128.  
  129.         /**
  130.          * Draw the view content
  131.          *
  132.          * @see android.view.View#onDraw(android.graphics.Canvas)
  133.          */
  134.         @Override
  135.         protected void onDraw(Canvas canvas) {
  136.                 if (true) {
  137.                         /*
  138.                          * First, we need to get to the appropriate GL interface.
  139.                          * This is simply done by casting the GL context to either
  140.                          * GL10 or GL11.
  141.                          */
  142.                         GL10 gl = (GL10) (mGLContext.getGL());
  143.  
  144.                         /*
  145.                          * Before we can issue GL commands, we need to make sure all
  146.                          * native drawing commands are completed. Simply call
  147.                          * waitNative() to accomplish this. Once this is done, no native
  148.                          * calls should be issued.
  149.                          */
  150.                         mGLContext.waitNative(canvas, this);
  151.  
  152.                         int w = getWidth();
  153.                         int h = getHeight();
  154.  
  155.                         /*
  156.                          * Set the viewport. This doesn't have to be done each time
  157.                          * draw() is called. Typically this is called when the view
  158.                          * is resized.
  159.                          */
  160.  
  161.                         gl.glViewport(0, 0, w, h);
  162.  
  163.                         /*
  164.                          * Set our projection matrix. This doesn't have to be done
  165.                          * each time we draw, but usualy a new projection needs to be set
  166.                          * when the viewport is resized.
  167.                          */
  168.  
  169.                         float ratio = (float) w / h;
  170.                         gl.glMatrixMode(gl.GL_PROJECTION);
  171.                         gl.glLoadIdentity();
  172.                         gl.glFrustumf(-ratio, ratio, -1, 1, 2, 12);
  173.  
  174.                         /*
  175.                          * dithering is enabled by default in OpenGL, unfortunattely
  176.                          * it has a significant impact on performace in software
  177.                          * implementation. Often, it's better to just turn it off.
  178.                          */
  179.                         gl.glDisable(gl.GL_DITHER);
  180.  
  181.                         /*
  182.                          * Usually, the first thing one might want to do is to clear
  183.                          * the screen. The most efficient way of doing this is to use
  184.                          * glClear(). However we must make sure to set the scissor
  185.                          * correctly first. The scissor is always specified in window
  186.                          * coordinates:
  187.                          */
  188.  
  189.                         gl.glClearColor(1, 1, 1, 1);
  190.                         gl.glEnable(gl.GL_SCISSOR_TEST);
  191.                         gl.glScissor(0, 0, w, h);
  192.                         gl.glClear(gl.GL_COLOR_BUFFER_BIT);
  193.  
  194.                         /*
  195.                          * Now we're ready to draw some 3D object
  196.                          */
  197.  
  198.                         gl.glMatrixMode(gl.GL_MODELVIEW);
  199.                         gl.glLoadIdentity();
  200.                         gl.glTranslatef(0, 0, -3.0f);
  201.                         gl.glScalef(0.5f, 0.5f, 0.5f);
  202.                         gl.glRotatef(mAngleY,        1, 0, 0);
  203.                         gl.glRotatef(mAngleZ,        0, 1, 0);
  204.  
  205.                         gl.glColor4f(0.7f, 0.7f, 0.7f, 1.0f);
  206.                         gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
  207.                         gl.glEnableClientState(gl.GL_COLOR_ARRAY);
  208.                         gl.glEnable(gl.GL_CULL_FACE);
  209.  
  210.                         mThreeDObj.draw(gl);
  211.  
  212.                         /*
  213.                          * Once we're done with GL, we need to flush all GL commands and
  214.                          * make sure they complete before we can issue more native
  215.                          * drawing commands. This is done by calling waitGL().
  216.                          */
  217.                         mGLContext.waitGL();
  218.                 }
  219.         }
  220.  
  221.         // ------------------------------------------------------------------------
  222.  
  223.         private static final int INVALIDATE = 1;
  224.  
  225.         private final Handler mHandler = new Handler() {
  226.  
  227.                 @Override
  228.                 public void handleMessage(Message msg) {
  229.                         if (mAnimate && msg.what == INVALIDATE) {
  230.                                 invalidate();
  231.                                 msg = obtainMessage(INVALIDATE);
  232.                                 long current = SystemClock.uptimeMillis();
  233.                                 if (mNextTime < current) {
  234.                                         mNextTime = current + 20;
  235.                                 }
  236.                                 sendMessageAtTime(msg, mNextTime);
  237.                                 mNextTime += 20;
  238.                         }
  239.                 }
  240.         };
  241. }
  242.  
  243. abstract class ThreeDObject{
  244.         public abstract void draw(GL10 gl);
  245. }
  246.  
  247. class Cube extends ThreeDObject{
  248.        
  249.         private IntBuffer mVertexBuffer;
  250.         private IntBuffer mColorBuffer;
  251.         private ByteBuffer mIndexBuffer;
  252.  
  253.         public Cube() {
  254.                                
  255.                 int one = 0x10000;
  256.                 /* Every vertex got 3 values, for
  257.                 * x / y / z position in the kartesian space.
  258.                 */
  259.                 int vertices[] = { -one, -one, -one,
  260.                                                         one, -one, -one,
  261.                                                         one, one, -one,
  262.                                                         -one, one, -one,
  263.                                                         -one, -one, one,
  264.                                                         one, -one, one,
  265.                                                         one, one, one,
  266.                                                         -one, one, one, };
  267.  
  268.                 /* Every vertex has got its own color, described by 4 values
  269.                 * R(ed)
  270.                 * G(green)
  271.                 * B(blue)
  272.                 * A(lpha) <-- Opticacy
  273.                 */
  274.                 int colors[] = { 0, 0, 0, one,
  275.                                                 one, 0, 0, one,
  276.                                                 one, one, 0, one,
  277.                                                 0, one, 0, one,
  278.                                                 0, 0, one, one,
  279.                                                 one, 0, one, one,
  280.                                                 one, one, one, one,
  281.                                                 0, one, one, one, };
  282.  
  283.                  /* The last thing is that we need to describe some Triangles.
  284.                  * A triangle got 3 vertices.
  285.                  * The confusing thing is, that it is important in which order
  286.                  * the vertices of each triangle are described.
  287.                  * So describing a triangle through the vertices: "0, 3, 4"
  288.                  * will not result in the same triangle as: "0, 4, 3"
  289.                  * You probably ask: Why the hell isn't that the same ???
  290.                  * The reason for that is the call of: "gl.glFrontFace(gl.GL_CW);"
  291.                  * which means, that we have to describe the "visible" side of the
  292.                  * triangles by naming its vertices in a ClockWise order!
  293.                  * From the other side, the triangle will be 100% lookthru!
  294.                  * You can create a kind of magic mirror with that <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" />.
  295.                  */
  296.                 byte indices[] = { 0, 4, 5,
  297.                                                         0, 5, 1,
  298.                                                         1, 5, 6,
  299.                                                         1, 6, 2,
  300.                                                         2, 6, 7,
  301.                                                         2, 7, 3,
  302.                                                         3, 7, 4,
  303.                                                         3, 4, 0,
  304.                                                         4, 7, 6,
  305.                                                         4, 6, 5,
  306.                                                         3, 0, 1,
  307.                                                         3, 1, 2 };
  308.  
  309.                 // Buffers to be passed to gl*Pointer() functions
  310.                 // must be direct, i.e., they must be placed on the
  311.                 // native heap where the garbage collector cannot
  312.                 // move them.
  313.                 //
  314.                 // Buffers with multi-byte datatypes (e.g., short, int, float)
  315.                 // must have their byte order set to native order
  316.  
  317.                 ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);  // * 4 becuase of int
  318.                 vbb.order(ByteOrder.nativeOrder());
  319.                 mVertexBuffer = vbb.asIntBuffer();
  320.                 mVertexBuffer.put(vertices);
  321.                 mVertexBuffer.position(0);
  322.  
  323.                 ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4); // * 4 becuase of int
  324.                 cbb.order(ByteOrder.nativeOrder());
  325.                 mColorBuffer = cbb.asIntBuffer();
  326.                 mColorBuffer.put(colors);
  327.                 mColorBuffer.position(0);
  328.  
  329.                 mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
  330.                 mIndexBuffer.put(indices);
  331.                 mIndexBuffer.position(0);
  332.         }
  333.  
  334.         public void draw(GL10 gl) {
  335.                 gl.glFrontFace(gl.GL_CW);
  336.                 gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
  337.                 gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer);
  338.                 gl.glDrawElements(gl.GL_TRIANGLES, 36, gl.GL_UNSIGNED_BYTE,     mIndexBuffer);
  339.         }
  340.  
  341. }
  342.  
  343. class Pyramid  extends ThreeDObject{
  344.        
  345.         private IntBuffer mVertexBuffer;
  346.         private IntBuffer mColorBuffer;
  347.         private ByteBuffer mIndexBuffer;
  348.  
  349.         public Pyramid() {
  350.                                
  351.                 int one = 0x10000;
  352.                 int vertices[] = { -one, -one, -one, // The four floor vertices of the pyramid
  353.                                                         one, -one, -one,
  354.                                                         one, one, -one,
  355.                                                         -one, one, -one,
  356.                                                         0, 0, one, };  // The top of the pyramid
  357.  
  358.                 int colors[] = { 0, 0, one, one,
  359.                                                 one, 0, 0, one,
  360.                                                 one, one, 0, one,
  361.                                                 0, one, 0, one,
  362.                                                 one, 0, one, one, };
  363.  
  364.                 byte indices[] = { 0, 4, 1, // The four side-triangles
  365.                                                         1, 4, 2,
  366.                                                         2, 4, 3,
  367.                                                         3, 4, 0,
  368.                                                         1, 2, 0, // The two bottom-triangles
  369.                                                         0, 2, 3};
  370.  
  371.                 // Buffers to be passed to gl*Pointer() functions
  372.                 // must be direct, i.e., they must be placed on the
  373.                 // native heap where the garbage collector cannot
  374.                 // move them.
  375.                 //
  376.                 // Buffers with multi-byte datatypes (e.g., short, int, float)
  377.                 // must have their byte order set to native order
  378.  
  379.                 ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);  // * 4 because of int
  380.                 vbb.order(ByteOrder.nativeOrder());
  381.                 mVertexBuffer = vbb.asIntBuffer();
  382.                 mVertexBuffer.put(vertices);
  383.                 mVertexBuffer.position(0);
  384.  
  385.                 ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4); // * 4 because of int
  386.                 cbb.order(ByteOrder.nativeOrder());
  387.                 mColorBuffer = cbb.asIntBuffer();
  388.                 mColorBuffer.put(colors);
  389.                 mColorBuffer.position(0);
  390.  
  391.                 mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
  392.                 mIndexBuffer.put(indices);
  393.                 mIndexBuffer.position(0);
  394.         }
  395.  
  396.         public void draw(GL10 gl) {
  397.                 gl.glFrontFace(gl.GL_CW);
  398.                 gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
  399.                 gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer);
  400.                 gl.glDrawElements(gl.GL_TRIANGLES, 18, gl.GL_UNSIGNED_BYTE,     mIndexBuffer);
  401.         }
  402. }
Parsed in 0.068 seconds, using GeSHi 1.0.8.4


Regards,
plusminus
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

Top

Postby Patton » Sat Jan 19, 2008 6:04 pm

This is a nice example how to do simple drawing and how to intercept keys, but the rotation is extremely slow or should I say sluggish. The rotation is smooth when I increase the angles in every frame, but when I increase them on onKeyDown, it looks crappy. Is there a way to do smoother animation while holding keys? Has this sluggish thing anything to do with the message handling in Handler?
Patton
Junior Developer
Junior Developer
 
Posts: 23
Joined: Sat Jan 19, 2008 5:52 pm

Postby Ishtar » Tue Jan 29, 2008 9:45 am

Can we do this like "realtime" instead of posting invalidates around? Wouldn't it be nicer to have the rendering loop in a seperate thread? And what about double buffering?

Would solve Pattons problem, if we can just do real time rendering and poll the key states, we can rotate the cube every frame. But this won't fit in the api im afraid..

Ishtar
Ishtar
Experienced Developer
Experienced Developer
 
Posts: 50
Joined: Wed Jan 16, 2008 10:22 pm
Location: Netherlands

Postby ruiying » Mon Mar 31, 2008 10:30 am

Ishtar wrote:Can we do this like "realtime" instead of posting invalidates around? Wouldn't it be nicer to have the rendering loop in a seperate thread? And what about double buffering?

Would solve Pattons problem, if we can just do real time rendering and poll the key states, we can rotate the cube every frame. But this won't fit in the api im afraid..

Ishtar


GLSurfaceView.java
ruiying
Freshman
Freshman
 
Posts: 3
Joined: Mon Mar 31, 2008 10:24 am

Re: Rotating 3D-Objects based on KeyEvents

Postby takawan » Fri May 23, 2008 2:49 am

Hello plusminus,

This time I tried to change this m3 code to m5 but I cannot yet.
I wonder if is it possible using KeyEvents with OpenGL at m5.
If so, shall we see the fixed code?

Thank you,
Takawan
takawan
Freshman
Freshman
 
Posts: 4
Joined: Sat May 10, 2008 12:39 pm

Postby superj » Sun Oct 19, 2008 10:25 am

Dear plusminus!

Which version of ADT Plugin and SDK you wrote this code?
superj
Freshman
Freshman
 
Posts: 7
Joined: Thu Sep 11, 2008 3:22 pm

Top

Postby superj » Sun Oct 19, 2008 11:03 am

Oh, I found the problem! The Android SDK m3 is include the android.graphics.OpenGLContext...
superj
Freshman
Freshman
 
Posts: 7
Joined: Thu Sep 11, 2008 3:22 pm

Postby ratamovic » Fri Jan 23, 2009 3:29 am

Hello Everybody!

I have an issue with that onKeyDown event: it seems that it's triggered frequently even if the onKeyUp event has not been triggered (which means that Android keeps calling onKeyDown while the key is pressed). This is seems to be one of the reason why pressing keys is slow. Am I wrong?

Is it the same on a real phone (because I have only tested on the emulator)?
ratamovic
Freshman
Freshman
 
Posts: 6
Joined: Fri Jan 23, 2009 3:20 am

Postby SkyNet800 » Tue Feb 24, 2009 5:03 pm

Yes, this is the problem.

OpenGLContext has been removed from newer SDK versions, and this can´t be used anymore.

It´s a big problem for beginers because none example compiles. :cry:

Can anybody submit a version written using SDK 1.0 R1 or newer. (Today there is SDK 1.1 as newest)

Thx. :wink:
SkyNet800
Junior Developer
Junior Developer
 
Posts: 20
Joined: Tue Feb 24, 2009 11:44 am

Postby B_Thax » Mon Apr 13, 2009 11:25 am

Ishtar wrote:Can we do this like "realtime" instead of posting invalidates around? Wouldn't it be nicer to have the rendering loop in a seperate thread? And what about double buffering?

Would solve Pattons problem, if we can just do real time rendering and poll the key states, we can rotate the cube every frame. But this won't fit in the api im afraid..

Ishtar


To to realtime rendering you should use the current DeltaSeconds (Seconds passed from the last frame to the current) and multiply that value to every timebased value you got: rotation, speed, etc etc...

Cheers
Moss
Game Programmer at Tragnarion Studios - www.Tragnarion.com
User avatar
B_Thax
Junior Developer
Junior Developer
 
Posts: 13
Joined: Thu Jul 17, 2008 5:55 pm
Location: Palma de Mallorca

rotation by screen touch

Postby HoaiNguyen » Mon May 25, 2009 10:37 am

Hi everyone, thanks for this helpful tutorial. But I have a problem here.
I want to do the rotation by the screen touch event, not by the keypad event. And I want the rotation just be done only when I touch exactly on the Cube area. And my problem is when I touch on the screen, I cannot indentify the point I have touched is or ins't on the Cube area. I got no idea for the solution.
Anyone can help me? I'm stuck on it :cry: .

Sorry for my sucking English.
HoaiNguyen
Once Poster
Once Poster
 
Posts: 1
Joined: Mon May 25, 2009 10:27 am

Re: Rotating 3D-Objects based on KeyEvents

Postby lucy24 » Fri Dec 30, 2011 4:17 am

increasing in a surprising direction, today. No wonder people like to on this trend hat consideration of payment.Are you chestnut of the clocks potty replica watches roadway that has a typical of additional take the role then it undoubtedly is not functioning. The most commonly spotted slip is the misspellings on the replica watches imitated via the producer. Ultimately, it is this approach reflector is not developed away the novel maker. Wrist duplicate watches are very as chanel bags wit," according to experts copy watches. "Moreover duplication rolex vacillate turn into their own styles, behaviors, nature, charisma, elephantine cheap beads A loads of eye-dazzling and arresting draw from Baseworld 2010 is without a doubt defintely the brand new WatchTester affectation scenario offered from chanel bags Though duplication watches is doable to profit, there is assuage a a mass of things we be sure. Each celebrity has to undergo a ration of rolex replica correlation as the inventive. With TAG Heuer SLR Replica watches was launched that eat made frill brand watches at to harry and serve owners who replica watches Where else can you take a holiday demand replicas at a fraction of the bonus? In this holder, less than $ 150! Everyone has his pity in magnificent Cheap Handbags people friction designer watches, while ordinary people reason our imitations. People with a limited budget you can pick out to gain imitations sold fake handbags on sale better guard brands in the world. Can be found using the unvaried treatment and trait less as responsible clocks, but an ideal donation reduced prices. hermes handbags regardless of that, it is still a fake watch.Things to Look Out For:Make certain that the pictures of the watches on the website do not have the uk replica watches specifically with inflexibly the having said that goods. Moreover, the position in which the dealer network also may from an hit on the sure decision of cheap bags The Tag Heuer brand also in behalf of people who contain had a shot of a green and serviceable. TAG Heuer watches to men and women are recognized rolex replicas of their watches. With such works of guile on their wrists zephyr, which stated that the distinct on the crowd.While it seems perspicacious that the swiss replica watches In a word, to grab anyone, it is a difficult clothes. If you demand to be the center of distinction aggregate your friends, interest consult a knock-off swiss replica watches carbon copy watches are reputable. IWC reproduction watches are durable. You find out that imitation IWC has all things you need. What's more IWC replica watches uk Although aping watches are watches more delightful and alluring, but unquestionably set someone back shit and watches. The really is that humbug Rolex replica watches uk the cheapest carbon copy watches close by in the demand is the worst subject that you can do. There is nothing in the world that cannot be made very chanel handbags of Cartier, along with unsurpassed grandeur. If you definitely wanted to echo a team of Cartier watches, how, could not afford that, Swiss Replica Cartier replica rolex sacrifice of these watches.Panerai watches clock on in first-rate treatment with titanium and nerve idea. With calfskin and one watches rubber strap replica watches uk
lucy24
Junior Developer
Junior Developer
 
Posts: 20
Joined: Fri Dec 30, 2011 3:29 am

Top

Return to Android 2D/3D Graphics - OpenGL Tutorials

Who is online

Users browsing this forum: No registered users and 2 guests