main.pp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. (*---------------------------------------------------------------------------------
  2. Demonstrates how to use 3D picking on the DS
  3. Author: Gabe Ghearing
  4. Created: Feb 2007
  5. This file is released into the public domain
  6. Basic idea behind picking;
  7. Draw the scene a second time with a projection matrix that only renders what is
  8. directly below the cursor. The GPU keeps track of how many polygons are drawn, so
  9. if a polygon is drawn in this limited view the polygon is directly below the cursor.
  10. Several polygons may be drawn under the cursor, so a position test is used for each
  11. object(a collection of polygons) to tell which object is closest to the camera.
  12. The object that is closest to the camera and under the cursor is the one that the
  13. user is clicking on.
  14. There are several optimizations that are not done in this example, such as:
  15. - Simplify models during the picking pass, the model needs to occupy the
  16. same area, but can usually use fewer polygons.
  17. - Save the projection matrix with glGetFixed() instead of recreating it
  18. every pass.
  19. *--------------------------------------------------------------------------------*)
  20. program main;
  21. {$L cone.o}
  22. {$L cylinder.o}
  23. {$L sphere.o}
  24. {$apptype arm9} //...or arm7
  25. {$define ARM9} //...or arm7, according to apptype
  26. {$mode objfpc} // required for some libc funcs implementation
  27. uses
  28. ctypes, nds9; // required by nds headers!
  29. type
  30. TClickable = ( clNothing, clCone, clCylinder, clSphere);
  31. var
  32. cone_bin_end: array [0..0] of u8; cvar; external;
  33. cone_bin: array [0..0] of u16; cvar; external;
  34. cone_bin_size: u32; cvar; external;
  35. cylinder_bin_end: array [0..0] of u8; cvar; external;
  36. cylinder_bin: array [0..0] of u16; cvar; external;
  37. cylinder_bin_size: u32; cvar; external;
  38. sphere_bin_end: array [0..0] of u8; cvar; external;
  39. sphere_bin: array [0..0] of u16; cvar; external;
  40. sphere_bin_size: u32; cvar; external;
  41. clicked: TClickable; // what is being clicked
  42. closeW: integer; // closest distace to camera
  43. polyCount: integer; // keeps track of the number of polygons drawn
  44. // run before starting to draw an object while picking
  45. procedure startCheck();
  46. begin
  47. while PosTestBusy() do; // wait for the position test to finish
  48. while GFX_BUSY do; // wait for all the polygons from the last object to be drawn
  49. PosTest_Asynch(0,0,0); // start a position test at the current translated position
  50. polyCount := GFX_POLYGON_RAM_USAGE^; // save the polygon count
  51. end;
  52. // run afer drawing an object while picking
  53. procedure endCheck(obj: TClickable);
  54. begin
  55. while GFX_BUSY do; // wait for all the polygons to get drawn
  56. while PosTestBusy() do; // wait for the position test to finish
  57. if (GFX_POLYGON_RAM_USAGE^ > polyCount) then // if a polygon was drawn
  58. begin
  59. if PosTestWresult() <= closeW then
  60. begin
  61. // this is currently the closest object under the cursor!
  62. closeW := PosTestWresult();
  63. clicked := obj;
  64. end;
  65. end;
  66. end;
  67. var
  68. rotateX: cuint32 = 0;
  69. rotateY: cuint32 = 0;
  70. touchXY: touchPosition;
  71. viewport: array [0..3] of integer = (0,0,255,191); // used later for gluPickMatrix()
  72. keys: u16;
  73. begin
  74. // power up everything; this a bit wasteful but this isn't a power management example
  75. powerON(POWER_ALL);
  76. //set mode 0, enable BG0 and set it to 3D
  77. videoSetMode(MODE_0_3D);
  78. //irqs are nice
  79. irqInit();
  80. irqSet(IRQ_VBLANK, nil);
  81. lcdMainOnBottom(); // we are going to be touching the 3D display
  82. // initialize gl
  83. glInit();
  84. // enable edge outlining, this will be used to show which object is selected
  85. glEnable(GL_OUTLINE);
  86. //set the first outline color to white
  87. glSetOutlineColor(0,RGB15(31,31,31));
  88. // setup the rear plane
  89. glClearColor(0,0,0,0); // set BG to black and clear
  90. glClearPolyID(0); // the BG and polygons will have the same ID unless a polygon is highlighted
  91. glClearDepth($7FFF);
  92. // setup the camera
  93. gluLookAt( 0.0, 0.0, 1.0, //camera possition
  94. 0.0, 0.0, 0.0, //look at
  95. 0.0, 1.0, 0.0); //up
  96. glLight(0, RGB15(31,31,31) , 0, floattov10(-1.0), 0); // setup the light
  97. while true do
  98. begin
  99. // handle key input
  100. scanKeys();
  101. keys := keysHeld();
  102. if ((keys and KEY_UP)) = 0 then rotateX := rotateX +3;
  103. if((keys and KEY_DOWN)) = 0 then rotateX := rotateX -3;
  104. if((keys and KEY_LEFT)) = 0 then rotateY := rotateY +3;
  105. if((keys and KEY_RIGHT)) = 0 then rotateY := rotateY -3;
  106. // get touchscreen position
  107. touchXY := touchReadXY();
  108. glViewPort(0,0,255,191); // set the viewport to fullscreen
  109. // setup the projection matrix for regular drawing
  110. glMatrixMode(GL_PROJECTION);
  111. glLoadIdentity();
  112. gluPerspective(30, 256.0 / 192.0, 0.1, 20);
  113. glMatrixMode(GL_MODELVIEW); // use the modelview matrix while drawing
  114. glPushMatrix(); // save the state of the current matrix(the modelview matrix)
  115. glTranslate3f32(0,0,floattof32(-6));
  116. glRotateXi(rotateX); // add X rotation to the modelview matrix
  117. glRotateYi(rotateY); // add Y rotation to the modelview matrix
  118. glPushMatrix(); // save the state of the modelview matrix while making the first pass
  119. // draw the scene for displaying
  120. glTranslate3f32(floattof32(2.9),floattof32(0),floattof32(0)); // translate the modelview matrix to the drawing location
  121. if (clicked = clCone) then
  122. glPolyFmt(POLY_ALPHA(31) or POLY_CULL_BACK or POLY_FORMAT_LIGHT0 or POLY_ID(1)) // set a poly ID for outlining
  123. else
  124. glPolyFmt(POLY_ALPHA(31) or POLY_CULL_BACK or POLY_FORMAT_LIGHT0 or POLY_ID(0)); // set a poly ID for no outlining (same as BG)
  125. glCallList((@cone_bin)); // draw a green cone from a predefined packed command list
  126. glTranslate3f32(floattof32(-3),floattof32(1.8),floattof32(2)); // translate the modelview matrix to the drawing location
  127. if (clicked = clCylinder) then
  128. glPolyFmt(POLY_ALPHA(31) or POLY_CULL_BACK or POLY_FORMAT_LIGHT0 or POLY_ID(1)) // set a poly ID for outlining
  129. else
  130. glPolyFmt(POLY_ALPHA(31) or POLY_CULL_BACK or POLY_FORMAT_LIGHT0 or POLY_ID(0)); // set a poly ID for no outlining (same as BG)
  131. glCallList((@cylinder_bin)); // draw a blue cylinder from a predefined packed command list
  132. glTranslate3f32(floattof32(0.5),floattof32(-2.6),floattof32(-4)); // translate the modelview matrix to the drawing location
  133. if(clicked = clSphere) then
  134. glPolyFmt(POLY_ALPHA(31) or POLY_CULL_BACK or POLY_FORMAT_LIGHT0 or POLY_ID(1)) // set a poly ID for outlining
  135. else
  136. glPolyFmt(POLY_ALPHA(31) or POLY_CULL_BACK or POLY_FORMAT_LIGHT0 or POLY_ID(0)); // set a poly ID for no outlining (same as BG)
  137. glCallList((@sphere_bin)); // draw a red sphere from a predefined packed command list
  138. glPopMatrix(1); // restores the modelview matrix to where it was just rotated
  139. // draw the scene again for picking
  140. clicked := clNothing; //reset what was clicked on
  141. closeW := $7FFFFFFF; //reset the distance
  142. //set the viewport to just off-screen, this hides all rendering that will be done during picking
  143. glViewPort(0,192,0,192);
  144. // setup the projection matrix for picking
  145. glMatrixMode(GL_PROJECTION);
  146. glLoadIdentity();
  147. gluPickMatrix((touchXY.px),(191-touchXY.py),4,4,viewport); // render only what is below the cursor
  148. gluPerspective(30, 256.0 / 192.0, 0.1, 20); // this must be the same as the original perspective matrix
  149. glMatrixMode(GL_MODELVIEW); // switch back to modifying the modelview matrix for drawing
  150. glTranslate3f32(floattof32(2.9),floattof32(0),floattof32(0)); // translate the modelview matrix to the drawing location
  151. startCheck();
  152. glCallList((@cone_bin)); // draw a cone from a predefined packed command list
  153. endCheck(clCone);
  154. glTranslate3f32(floattof32(-3),floattof32(1.8),floattof32(2)); // translate the modelview matrix to the drawing location
  155. startCheck();
  156. glCallList((@cylinder_bin)); // draw a cylinder from a predefined packed command list
  157. endCheck(clCylinder);
  158. glTranslate3f32(floattof32(0.5),floattof32(-2.6),floattof32(-4)); // translate the modelview matrix to the drawing location
  159. startCheck();
  160. glCallList((@sphere_bin)); // draw a sphere from a predefined packed command list
  161. endCheck(clSphere);
  162. glPopMatrix(1); // restores the modelview matrix to its original state
  163. glFlush(0); // wait for everything to be drawn before starting on the next frame
  164. end;
  165. end.