1 /*
2 * Copyright (C) 1997-2005, R3vis Corporation.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18 *
19 * Original Contributor:
20 * Wes Bethel, R3vis Corporation, Marin County, California
21 * Additional Contributor(s):
22 *
23 * The OpenRM project is located at http://openrm.sourceforge.net/.
24 */
25 /*
26 * $Id: rmpick.c,v 1.10 2005/06/06 02:04:29 wes Exp $
27 * Version: $Name: OpenRM-1-6-0-2-RC2 $
28 * $Revision: 1.10 $
29 * $Log: rmpick.c,v $
30 * Revision 1.10 2005/06/06 02:04:29 wes
31 * Lots of small additions to clean up compiler warnings.
32 *
33 * Revision 1.9 2005/02/19 16:22:50 wes
34 * Distro sync and consolidation.
35 *
36 * Revision 1.8 2005/01/23 17:00:22 wes
37 * Copyright updated to 2005.
38 *
39 * Revision 1.7 2004/09/28 00:46:56 wes
40 * Use calloc to clear out the pick buffer before doing the pick.
41 *
42 * Revision 1.6 2004/03/30 14:13:31 wes
43 * Fixed declarations and man page docs for several routines.
44 *
45 * Revision 1.5 2004/01/16 16:46:35 wes
46 * Updated copyright line for 2004.
47 *
48 * Revision 1.4 2003/12/12 00:33:47 wes
49 * Removed a bunch of dead code, commented out diagnostic messages.
50 *
51 * Revision 1.3 2003/11/16 16:19:40 wes
52 * Removed "serial table" from picking operations. rmserial.c can probably
53 * be removed from the source tree, and rmpick.c needs to have a bunch
54 * of dead code surrounded by if 0's removed.
55 *
56 * Revision 1.2 2003/02/02 02:07:15 wes
57 * Updated copyright to 2003.
58 *
59 * Revision 1.1.1.1 2003/01/28 02:15:23 wes
60 * Manual rebuild of rm150 repository.
61 *
62 * Revision 1.13 2003/01/16 22:21:17 wes
63 * Updated all source files to reflect new organization of header files:
64 * all header files formerly located in include/rmaux, include/rmi, include/rmv
65 * are now located in include/rm.
66 *
67 * Revision 1.12 2002/09/23 13:42:36 wes
68 *
69 * Established minimum size for feedback buffer; one user reported problems
70 * when picking with a very small number of objects. Establishing a
71 * minimum feedback buffer size appears to have fixed the problem. There
72 * may still be a linger problem.
73 *
74 * Revision 1.11 2002/06/17 01:01:39 wes
75 * Replaced fixed-size pick table with one that is completely dynamic -
76 * no more realloc error messages. Replaced wonky #if DEBUG statements
77 * with those that are consistent with the rest of the distribution.
78 *
79 * Revision 1.10 2002/04/30 19:33:05 wes
80 * Updated copyright dates.
81 *
82 * Revision 1.9 2001/06/03 20:50:04 wes
83 * Removed dead code.
84 *
85 * Revision 1.8 2001/05/26 14:37:49 wes
86 * Added RMnode parameter to serialization code used in picking - this
87 * will permit picking of scene graph subtrees that are disconnected
88 * from rmRootNode().
89 *
90 * Revision 1.7 2001/03/31 17:12:39 wes
91 * v1.4.0-alpha-2 checkin.
92 *
93 * Revision 1.6 2000/12/03 22:35:38 wes
94 * Mods for thread safety.
95 *
96 * Revision 1.5 2000/08/23 23:27:10 wes
97 * Added RM_TRUE as the default matrix stack initialization mode
98 * to all pick routines. This is a placeholder.
99 *
100 * Revision 1.4 2000/05/14 23:38:38 wes
101 * New param to private_rmSubTreeFrame() for OpenGL matrix stack
102 * initialization during rendering/picking frame operations.
103 *
104 * Revision 1.3 2000/04/20 16:29:47 wes
105 * Documentation additions/enhancements, some code rearragement.
106 *
107 * Revision 1.2 2000/02/29 23:43:53 wes
108 * Compile warning cleanups.
109 *
110 * Revision 1.1.1.1 2000/02/28 21:29:40 wes
111 * OpenRM 1.2 Checkin
112 *
113 * Revision 1.1.1.1 2000/02/28 17:18:48 wes
114 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
115 *
116 */
117
118 /*
119 * this file contains all the routines in RM that support picking.
120 */
121
122 #include <rm/rm.h>
123 #include "rmprivat.h"
124 #include <GL/glu.h>
125
126 /* PRIVATE declarations */
127 static int private_processHits (int nhits, GLuint *pick_buffer, RMpick *srmpick);
128 static int private_processHitsList (int nhits, GLuint *pick_buffer, RMpick *list);
129 void private_rmSetupPickMatrix (void);
130 void private_rmNodePrimPickName (RMnode *r, int primindex);
131 void private_rmNodeOnlyPickName (const RMnode *r);
132 static RMpick *private_rmPickListNew (int n);
133
134 /* pick coordinates */
135 static int xpick_location = 0, ypick_location = 0;
136 static GLdouble pick_width = 5.0, pick_height = 5.0;
137
138 /* tmp 11/9/03 until we move the following routine to somewhere
139 more permanent */
140 RMnode *
private_rmNodeFromIndex(int indx)141 private_rmNodeFromIndex(int indx)
142 {
143 extern RMcompMgrHdr *global_RMnodePool;
144 int pageNum, offset;
145 RMnode *t;
146
147 pageNum = indx / NUM_ITEMS_PER_PAGE;
148 offset = indx % NUM_ITEMS_PER_PAGE;
149
150 /* put sanity check here */
151
152 t = (RMnode *)(global_RMnodePool->objectPool[pageNum]) + offset;
153 return t;
154 }
155
156 /*
157 * ----------------------------------------------------
158 * @Name rmFramePick
159 @pstart
160 RMpick * rmFramePick (RMpipe *renderPipe,
161 RMnode *subTree,
162 int xpick,
163 int ypick)
164 @pend
165
166 @astart
167
168 RMpipe *renderPipe - the pipe upon which rendering and picking will occur.
169
170 RMnode *subTree- the subtree to be drawn, and picked.
171
172 int xpick, ypick - integer values indicating an (x,y) window
173 location.
174 @aend
175
176 @dstart
177
178 rmFramePick() performs object picking. A single RMpick object is
179 returned representing the object closest to the viewer at the pixel
180 location (xpick, ypick) in the display window. To obtain a list of
181 all objects that appear at (xpick, ypick), not just the frontmost,
182 use rmFramePickList().
183
184 If no objects were picked, NULL is returned.
185
186 Some scene parameters will generate pick hits. These include 2D and
187 3D cameras. When the pick occurs at some (x,y) location that is not
188 covered by any objects, a pick hit will be returned. In that case,
189 the returned RMpick object's RMnode attribute will point to the
190 RMnode that has a camera that generated the pick hit.
191
192 With the RMpick object returned by rmPickFrame or rmPickFrameList,
193 use the routine rmPickedNode to obtain a handle to the RMnode that
194 was picked; rmPickedPrimitive to obtain a handle to the RMprimitive
195 that was picked; rmPickedNodeName() to obtain the (character string)
196 name of the node that was picked; and rmPickedPrimitiveZval to obtain
197 the NDC z-coordinate of the primitive that was picked.
198
199 June 2002: the RMpick object returned by rmFramePick should be deleted
200 with rmPickDelete when it is no longer needed. (In versions of RM earlier
201 than 1.4.2, a pointer to static memory was returned, and apps were
202 prohibited from free'ing that memory. This has changed as of v1.4.2).
203
204 See the RM demo programs for example usage, particularly "trans2d.c",
205 which performs picking in 2D, and "pickTest.c", which performs
206 picking in 3D. The RM demo program "pickListTest.c" exercises
207 rmFramePickList() in 3D.
208
209 @dend
210 * ----------------------------------------------------
211 */
212 RMpick *
rmFramePick(RMpipe * renderPipe,RMnode * subTree,int xpick,int ypick)213 rmFramePick (RMpipe *renderPipe,
214 RMnode *subTree,
215 int xpick,
216 int ypick)
217 {
218 int i, hits = 0;
219 RMenum render3DOpaqueEnable = RM_TRUE;
220 RMenum render3DTransparentEnable = RM_TRUE;
221 RMenum render2DEnable = RM_TRUE;
222 RMpipe *usePipe;
223 RMpick *pickReturn=NULL;
224 int pickBufferSize;
225 int totalNodes, totalPrims;
226 unsigned int *pick_buffer;
227
228 int private_rmTrueFilterfunc(RMnode *r);
229
230 xpick_location = xpick;
231 ypick_location = ypick;
232
233
234 /* 11/9/03 wes - removed serial table from picking process */
235 {
236 extern RMcompMgrHdr *global_RMnodePool, *global_RMprimitivePool;
237 totalNodes = global_RMnodePool->numAlloc;
238 totalPrims = global_RMprimitivePool->numAlloc;
239 }
240
241
242 #if (DEBUG_LEVEL & DEBUG_TRACE)
243 printf(" rmFramePick: #nodes = %d, #prims = %d \n", totalNodes, totalPrims);
244 #endif
245
246 pickBufferSize = totalNodes + totalPrims;
247 pickBufferSize = RM_MAX(32, pickBufferSize+1);
248
249 pick_buffer = (unsigned int *)calloc(sizeof(unsigned int)*pickBufferSize, sizeof(unsigned int));
250
251 /* set the render mode to pick objects when the scene is rendered. */
252 glSelectBuffer(pickBufferSize, pick_buffer);
253 glRenderMode(GL_SELECT);
254
255 glInitNames();
256
257 glPushName(-1);
258
259 /* render stuff */
260 usePipe = renderPipe;
261 private_rmSubTreeFrame(usePipe, subTree, GL_SELECT, private_rmNodeOnlyPickName, private_rmNodePrimPickName, private_rmTrueFilterfunc, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DEnable, RM_TRUE); /* always initialize matrix stack here? */
262
263 /* get the hits back from OpenGL */
264 hits = glRenderMode(GL_RENDER);
265
266 glMatrixMode(GL_MODELVIEW);
267
268 #if (DEBUG_LEVEL & DEBUG_TRACE)
269 fprintf(stderr, " %d hits from pick operation. \n", hits);
270 #endif
271 /* process hits */
272 if (hits > 0)
273 {
274 pickReturn = private_rmPickListNew(1);
275 i = private_processHits(hits, pick_buffer, pickReturn);
276 pickReturn->node = private_rmNodeFromIndex(pickReturn->index);
277 }
278
279 free((void *)pick_buffer);
280
281 return(pickReturn);
282 }
283
284
285 /*
286 * ----------------------------------------------------
287 * @Name rmFramePickList
288 @pstart
289 int rmFramePickList (RMpipe *renderPipe,
290 RMnode *subTree,
291 int xpick,
292 int ypick,
293 RMpick **listReturn)
294 @pend
295
296 @astart
297
298 RMpipe *renderPipe - the pipe upon which rendering and picking will occur.
299
300 RMnode *subTree- the subtree to be drawn, and picked.
301
302 int xpick, ypick - integer values indicating an (x,y) pixel
303 coordinate within a window (input).
304
305 RMpick **listReturn - a handle to an RMpick pointer (modified,
306 return).
307 @aend
308
309 @dstart
310
311 Performs a pick operation, returning a list of all objects
312 encountered at the (x,y) pixel location in the render window through
313 the parameter listReturn. The number of objects in that list is
314 returned on the stack, or zero is returned if there were no objects
315 picked.
316
317 The list of objects that is returned to the caller is sorted in
318 ascending order of the z-coordinate of the picked object. Therefore,
319 listReturn[0] contains information about the object closest to the
320 viewer, and listReturn[nhits-1] contains info about the object
321 farthest from the viewer.
322
323 The RMpick objects returned through listReturn should be freed when
324 no longer needed by using rmPickListDelete().
325
326 @dend
327 * ----------------------------------------------------
328 */
329 int
rmFramePickList(RMpipe * renderPipe,RMnode * subTree,int xpick,int ypick,RMpick ** list_return)330 rmFramePickList (RMpipe *renderPipe,
331 RMnode *subTree,
332 int xpick,
333 int ypick,
334 RMpick **list_return)
335 {
336 int hits = 0;
337 RMpick *list;
338 RMenum render3DOpaqueEnable = RM_TRUE;
339 RMenum render3DTransparentEnable = RM_TRUE;
340 RMenum render2DEnable = RM_TRUE;
341 unsigned int *pick_buffer;
342 int totalNodes, totalPrims, pickBufSize;
343
344 xpick_location = xpick;
345 ypick_location = ypick;
346
347 {
348 extern RMcompMgrHdr *global_RMnodePool, *global_RMprimitivePool;
349 totalNodes = global_RMnodePool->numAlloc;
350 totalPrims = global_RMprimitivePool->numAlloc;
351 }
352
353 pickBufSize = totalNodes + totalPrims;
354 pickBufSize = RM_MAX(32, pickBufSize);
355
356 #if (DEBUG_LEVEL & DEBUG_TRACE)
357 printf(" rmFramePickList totalNodes = %d, totalPrims = %d \n", totalNodes, totalPrims);
358 #endif
359
360 pick_buffer = (unsigned int *)malloc((sizeof(unsigned int)*pickBufSize));
361
362 /* set the render mode to pick objects when the scene is rendered */
363 glSelectBuffer(pickBufSize, pick_buffer);
364
365 glRenderMode(GL_SELECT);
366
367 glInitNames();
368
369 glPushName(-1);
370
371 /* render stuff */
372 private_rmSubTreeFrame(renderPipe, subTree, GL_SELECT, private_rmNodeOnlyPickName, private_rmNodePrimPickName, private_rmTrueFilterfunc, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DEnable, RM_TRUE); /* always initialize matrix stack? */
373
374 /* get the hits back from OpenGL */
375 hits = glRenderMode(GL_RENDER);
376
377 /* pop off projection matrix */
378 glPopMatrix();
379 glMatrixMode(GL_MODELVIEW);
380
381 #if (DEBUG_LEVEL & DEBUG_TRACE)
382 fprintf(stderr, " %d hits from pick operation. \n", hits);
383 #endif
384
385 /* process hits */
386 if (hits > 0)
387 {
388 int i;
389
390 list = private_rmPickListNew(hits);
391 private_processHitsList(hits, pick_buffer, list);
392
393 #if (DEBUG_LEVEL & DEBUG_TRACE)
394 fprintf(stderr, " there were %d hits. \n", hits);
395 #endif
396 for (i = 0; i < hits; i++)
397 {
398 list[i].node = private_rmNodeFromIndex(list[i].index);
399
400 #if (DEBUG_LEVEL & DEBUG_TRACE)
401 fprintf(stderr, " %s %g \n", rmNodeGetName(list[i].node), list[i].zval);
402 #endif
403 }
404 }
405 else
406 list = NULL;
407
408 free((void *)pick_buffer);
409 *list_return = list;
410 return(hits);
411 }
412
413
414 /*
415 * ----------------------------------------------------
416 * @Name rmPickDelete
417 @pstart
418 RMenum rmPickDelete (RMpick *toDelete)
419 @pend
420
421 @astart
422 RMpick *toDelete - a handle to a single or flat array of RMpick
423 objects.
424 @aend
425
426 @dstart
427
428 Use this routine to free resources associated with an RMpick object
429 or flat array of RMpick objects.
430
431 When rmFramePick() and rmFramePickList() finish, each returns an RMpick *
432 object (rmFramePick) or flat array of RMpick objects (rmFramePickList).
433 When applications are finished with these RMpick objects, they should be
434 deleted using rmPickDelete().
435
436 @dend
437 * ----------------------------------------------------
438 */
439 RMenum
rmPickDelete(RMpick * list)440 rmPickDelete (RMpick *list)
441 {
442 if (RM_ASSERT(list, "rmPickDelete() error: the input RMpick list is NULL") == RM_WHACKED)
443 return(RM_WHACKED);
444
445 free((void *)list);
446 return(RM_CHILL);
447 }
448
449
450 /*
451 * ----------------------------------------------------
452 * @Name rmPickedNode
453 @pstart
454 RMnode * rmPickedNode (const RMpick *toQuery)
455 @pend
456
457 @astart
458 const RMpick *toQuery - a handle to an RMpick object (input).
459 @aend
460
461 @dstart
462
463 Returns to the caller the RMnode handle contained within an RMpick
464 object, or NULL upon failure.
465
466 The RMpick object returned from rmFramePick (or objects returned from
467 rmFramePickList) can be queried to determine the node, primitive,
468 node name or z-coordinate of the picked object.
469
470 @dend
471 * ----------------------------------------------------
472 */
473 RMnode *
rmPickedNode(const RMpick * p)474 rmPickedNode (const RMpick *p)
475 {
476 if (p == NULL)
477 return(NULL);
478
479 return(p->node);
480 }
481
482
483 /*
484 * ----------------------------------------------------
485 * @Name rmPickedPrimitive
486 @pstart
487 int rmPickedPrimitive (const RMpick *toQuery)
488 @pend
489
490 @astart
491 const RMpick *toQuery - a handle to an RMpick object (input).
492 @aend
493
494 @dstart
495
496 The RMpick object returned from rmFramePick (or objects returned from
497 rmFramePickList) can be queried to determine the node, primitive,
498 node name or z-coordinate of the picked object.
499
500 This routine returns the index of the primitive that was
501 picked. Combining the primitive index with the RMnode handle of the
502 picked object allows applications to determine which primitive was
503 picked.
504
505 Returns a non-negative integer upon success, or -1 upon failure.
506
507 @dend
508 * ----------------------------------------------------
509 */
510 int
rmPickedPrimitive(const RMpick * p)511 rmPickedPrimitive (const RMpick *p)
512 {
513 if (p == NULL)
514 return(-1);
515 else
516 return(p->prim_index);
517 }
518
519
520 /*
521 * ----------------------------------------------------
522 * @Name rmPickedNodeName
523 @pstart
524 char * rmPickedNodeName (const RMpick *toQuery)
525 @pend
526
527 @astart
528 const RMpick *toQuery - a handle to an RMpick object (input).
529 @aend
530
531 @dstart
532
533 Returns to the caller the node name of the RMnode handle contained
534 within an RMpick object, or NULL upon failure.
535
536 The RMpick object returned from rmFramePick (or objects returned from
537 rmFramePickList) can be queried to determine the node, primitive,
538 node name or z-coordinate of the picked object.
539
540 This routine is functionally equivalent to first obtaining the RMnode
541 handle using rmPickedNode() followed by rmNodeGetName().
542
543 @dend
544 * ----------------------------------------------------
545 */
546 char *
rmPickedNodeName(const RMpick * p)547 rmPickedNodeName (const RMpick *p)
548 {
549 if (p == NULL)
550 return(NULL);
551
552 return(rmNodeGetName(rmPickedNode(p)));
553
554 }
555
556
557 /*
558 * ----------------------------------------------------
559 * @Name rmPickedPrimitiveZval
560 @pstart
561 float rmPickedPrimitiveZval (const RMpick *toQuery)
562 @pend
563
564 @astart
565 const RMpick *toQuery - a handle to an RMpick object (input).
566 @aend
567
568 @dstart
569
570 Returns to the caller the NDC z-coordinate of the RMprimitive at the
571 (x,y) screen location where picking occured. A value of zero is
572 returned upon error, when no picking occurred (RMpick NULL).
573
574 The RMpick object returned from rmFramePick (or objects returned from
575 rmFramePickList) can be queried to determine the node, primitive,
576 node name or z-coordinate of the picked object.
577
578 @dend
579 * ----------------------------------------------------
580 */
581 float
rmPickedPrimitiveZval(const RMpick * p)582 rmPickedPrimitiveZval (const RMpick *p)
583 {
584 if (RM_ASSERT(p, "rmPrimPickedZval() error: the input RMpick object is NULL") == RM_WHACKED)
585 return(0.0);
586
587 return(p->zval);
588 }
589
590
591 /* PRIVATE
592 *
593 * this routine takes a pile of pick hits and returns the one with
594 * the smallest z-coordinate. nhits and pick_buffer are provided by
595 * the GL_FEEDBACK mechanism, srmpick is the destination RMpick object
596 * that is filled in by this routine.
597 */
598 static int
private_processHits(int nhits,GLuint * pick_buffer,RMpick * srmpick)599 private_processHits (int nhits,
600 GLuint *pick_buffer,
601 RMpick *srmpick)
602 {
603 int i, j;
604 int use_it;
605 float zval;
606 float zcur = RM_MAXFLOAT;
607 GLuint *ptr;
608 GLuint names;
609 GLuint zscale = (~0u);
610 GLuint ival = 0;
611
612 ptr = pick_buffer;
613 for (i = 0; i < nhits; i++)
614 {
615 use_it = 0;
616 names = *ptr;
617 #if (DEBUG_LEVEL & DEBUG_TRACE)
618 fprintf(stderr, " number of names for this hit = %d \n", names);
619 #endif
620 ptr++;
621
622 zval = *ptr;
623 zval = zval / (float)zscale;
624 #if (DEBUG_LEVEL & DEBUG_TRACE)
625 fprintf(stderr, "\tz1 = %g;", zval);
626 fprintf(stderr, "\tz1 = %u;", *ptr);
627 #endif
628 ptr++;
629
630 if (zval <= zcur) /* if they're the same, use the one that was drawn last */
631 {
632 use_it = 1;
633 zcur = zval;
634 }
635
636 zval = *ptr;
637 zval = zval / (float)zscale;
638 #if (DEBUG_LEVEL & DEBUG_TRACE)
639 fprintf(stderr, " z2 = %g \n", zval);
640 fprintf(stderr, " z2 = %u \n", *ptr);
641 #endif
642 ptr++;
643
644 /* i'm going to assume that we'll use the first name and
645 ignore the rest, and that if we got here, that "names" >= 1*/
646 #if (DEBUG_LEVEL & DEBUG_TRACE)
647 fprintf(stderr, "\tthe names are: \n");
648 #endif
649 if (use_it)
650 ival = *ptr;
651 for (j = 0; j < (int)(names); j++)
652 {
653 #if (DEBUG_LEVEL & DEBUG_TRACE)
654 fprintf(stderr," %d ", *ptr);
655 #endif
656 ptr++;
657 }
658 #if (DEBUG_LEVEL & DEBUG_TRACE)
659 fprintf(stderr," \n");
660 #endif
661 }
662
663 /* from ival, we need to extract the object index and the prim index */
664 {
665 int opcode = RMPASSTHRU_GET_OPCODE(ival);
666
667 if (opcode != RM_PASSTHRU_OPCODE_IDENTIFIER)
668 rmError(" expected an identifier opcode in a pick operation. \n");
669 }
670 srmpick->index = RMPASSTHRU_GET_OBJECT_ID(ival);
671 srmpick->prim_index = RMPASSTHRU_GET_PRIM_ID(ival);
672 srmpick->zval = zcur;
673
674 return(1);
675 }
676
677 /* PRIVATE */
678 static int
sortPickFunc(const void * p1,const void * p2)679 sortPickFunc( const void *p1, const void *p2)
680 {
681 RMpick *a, *b;
682 float z1, z2;
683
684 a = (RMpick *)p1;
685 b = (RMpick *)p2;
686
687 z1 = rmPickedPrimitiveZval(a);
688 z2 = rmPickedPrimitiveZval(b);
689
690 if (z1 < z2)
691 return -1;
692 else if (z1 > z2)
693 return 1;
694 else
695 return 0;
696 }
697
698 /* PRIVATE
699 *
700 * analagous to processHits, private_processHitsList will return in RMpick *list
701 * _all_ objects that were picked regardless of z-value. nhits and pick_buffer
702 * are supplied by the OpenGL feedback mechanism, and list[] must be
703 * "nhits" in size.
704 */
705 static int
private_processHitsList(int nhits,GLuint * pick_buffer,RMpick * list)706 private_processHitsList (int nhits,
707 GLuint *pick_buffer,
708 RMpick *list)
709 {
710 int i, j;
711 int ival, use_it;
712 float zval;
713 GLuint *ptr;
714 GLuint names;
715 GLuint zscale = (~0u);
716
717 ptr = pick_buffer;
718
719 for (i = 0; i < nhits; i++)
720 {
721 use_it = 0;
722 names = *ptr;
723 #if (DEBUG_LEVEL & DEBUG_TRACE)
724 fprintf(stderr, " number of names for this hit = %d \n", names);
725 #endif
726 ptr++;
727
728 zval = *ptr;
729 zval = zval / (float)zscale;
730 #if (DEBUG_LEVEL & DEBUG_TRACE)
731 fprintf(stderr, "\tz1 = %g;", zval);
732 fprintf(stderr, "\tz1 = %u;", *ptr);
733 #endif
734 ptr++;
735
736 #if (DEBUG_LEVEL & DEBUG_TRACE)
737 fprintf(stderr, " z2 = %g \n", zval);
738 fprintf(stderr, " z2 = %u \n", *ptr);
739 #endif
740 ptr++;
741
742 #if (DEBUG_LEVEL & DEBUG_TRACE)
743 fprintf(stderr, "\tthe names are: \n");
744 #endif
745 ival = *ptr;
746 {
747 int opcode = RMPASSTHRU_GET_OPCODE(ival);
748
749 if (opcode != RM_PASSTHRU_OPCODE_IDENTIFIER)
750 rmError(" expected an identifier opcode in a pick operation. \n");
751 }
752 list[i].index = RMPASSTHRU_GET_OBJECT_ID(ival);
753 list[i].prim_index = RMPASSTHRU_GET_PRIM_ID(ival);
754 list[i].zval = zval;
755
756 for (j = 0; j < (int)(names); j++)
757 {
758 #if (DEBUG_LEVEL & DEBUG_TRACE)
759 fprintf(stderr, " %d ", *ptr);
760 #endif
761 ptr++;
762 }
763 #if (DEBUG_LEVEL & DEBUG_TRACE)
764 fprintf(stderr, " \n");
765 #endif
766 }
767
768 /* OK. we now have the hits list. sort it in increasing Z */
769 qsort(list, nhits, sizeof(RMpick), sortPickFunc);
770
771 return(1);
772 }
773
774
775 /* PRIVATE */
776 void
private_rmComputePickMatrix(RMstate * s,RMmatrix * pickReturn)777 private_rmComputePickMatrix (RMstate *s,
778 RMmatrix *pickReturn)
779 {
780 float sx, sy, tx, ty;
781 RMmatrix m;
782
783 rmMatrixIdentity(&m);
784
785 sx = s->vp[2] / pick_width;
786 sy = s->vp[3] / pick_height;
787 tx = (s->vp[2] + (2.0F * (s->vp[0] - (float)xpick_location))) / pick_width;
788 ty = (s->vp[3] + (2.0F * (s->vp[1] - (s->h - (float)ypick_location)))) / pick_height;
789
790 m.m[0][0] = sx;
791 m.m[1][1] = sy;
792 m.m[3][0] = tx;
793 m.m[3][1] = ty;
794
795 *pickReturn = m;
796 }
797
798
799 /* PRIVATE
800 *
801 * private routine to set up the "pick matrix". see the man page
802 * for gluPickMatrix. the basic idea is that the projection matrix
803 * is tweaked so that only those objects that fall within a very
804 * small region are "rendered." rendering, in the case of picking,
805 * means that a GL_FEEDBACK token is generated, rather than pixels
806 * being painted.
807 */
808 void
private_rmSetupPickMatrix(void)809 private_rmSetupPickMatrix (void)
810 {
811 rmError(" private_rmSetupPickMatrix is deprecated!");
812 #if 0
813 int w, h;
814 GLint viewport[4];
815 RMpipe *pipe = private_rmPipeGetCurrent();
816
817 glGetIntegerv(GL_VIEWPORT, viewport);
818 rmPipeGetWindowSize(pipe, &w, &h);
819
820 glMatrixMode(GL_PROJECTION);
821 glLoadIdentity();
822
823 gluPickMatrix((GLdouble)xpick_location, (GLdouble)ypick_location, pick_width, pick_height, viewport);
824
825 /* while we're here before any rendering happens, set up the serialized list of objects */
826 glMatrixMode(GL_MODELVIEW);
827 #endif
828 }
829
830
831 /* PRIVATE
832 *
833 * the GL_FEEDBACK mechanism allows for applications to place
834 * application-specific information in the "feedback token."
835 * RM builds a serialized representation of the scene graph, then
836 * as each node & primitive is rendered, a "bread crumb" is
837 * encoded in the feedback token. the routine below will encode
838 * the node & prim info into a token (glLoadName).
839 *
840 * the current_lod parm is deprecated and needs to be removed.
841 */
842 void
private_rmNodePrimPickName(RMnode * r,int primindex)843 private_rmNodePrimPickName (RMnode *r,
844 int primindex)
845 {
846 int indx;
847 unsigned int token = 0;
848
849 indx = r->compListIndx;
850
851 RMPASSTHRU_ENCODE_OPCODE(token, RM_PASSTHRU_OPCODE_IDENTIFIER);
852 RMPASSTHRU_ENCODE_OBJECT_ID(token, indx);
853 RMPASSTHRU_ENCODE_PRIM_ID(token, primindex);
854
855 glLoadName((GLuint)token);
856 }
857
858
859 /* PRIVATE
860 *
861 * private_rmNodeOnlyPickName encodes ONLY the node name into the feedback token
862 */
863 void
private_rmNodeOnlyPickName(const RMnode * r)864 private_rmNodeOnlyPickName (const RMnode *r)
865 {
866 int indx;
867 unsigned int token = 0;
868
869 indx = r->compListIndx;
870
871 RMPASSTHRU_ENCODE_OPCODE(token, RM_PASSTHRU_OPCODE_IDENTIFIER);
872 RMPASSTHRU_ENCODE_OBJECT_ID(token, indx);
873
874 glLoadName((GLuint)token);
875 }
876
877
878 /* PRIVATE
879 *
880 * this routine, while public in appearance, is used at the present time
881 * only within RM itself to allocate space for RMpick objects. the routine
882 * rmFramePickList uses this routine. applications will probably never
883 * need to use this routine, as rmFramePickList() calls this routine on
884 * behalf of the application.
885 *
886 * January 2000, there is presently no scenario in which applications using
887 * RM will ever need to call private_rmPickListNew(). Because of this
888 * condition, this function is static to this file.
889 * There is no reason why it couldn't be moved to rmpublic.h if needed.
890 */
891 static RMpick *
private_rmPickListNew(int n)892 private_rmPickListNew (int n)
893 {
894 RMpick *t = (RMpick *)malloc(sizeof(RMpick) * n);
895 memset((void *)t, 0, sizeof(RMpick) * n);
896
897 return(t);
898 }
899 /* EOF */
900