Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  5.  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the "Software"),
  9.  * to deal in the Software without restriction, including without limitation
  10.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11.  * and/or sell copies of the Software, and to permit persons to whom the
  12.  * Software is furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included
  15.  * in all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23.  * OTHER DEALINGS IN THE SOFTWARE.
  24.  */
  25.  
  26. /**
  27.  * \file feedback.c
  28.  * Selection and feedback modes functions.
  29.  */
  30.  
  31.  
  32. #include "glheader.h"
  33. #include "context.h"
  34. #include "enums.h"
  35. #include "feedback.h"
  36. #include "macros.h"
  37. #include "mtypes.h"
  38. #include "main/dispatch.h"
  39.  
  40.  
  41. #define FB_3D           0x01
  42. #define FB_4D           0x02
  43. #define FB_COLOR        0x04
  44. #define FB_TEXTURE      0X08
  45.  
  46.  
  47.  
  48. void GLAPIENTRY
  49. _mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer )
  50. {
  51.    GET_CURRENT_CONTEXT(ctx);
  52.  
  53.    if (ctx->RenderMode==GL_FEEDBACK) {
  54.       _mesa_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" );
  55.       return;
  56.    }
  57.    if (size<0) {
  58.       _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" );
  59.       return;
  60.    }
  61.    if (!buffer && size > 0) {
  62.       _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" );
  63.       ctx->Feedback.BufferSize = 0;
  64.       return;
  65.    }
  66.  
  67.    switch (type) {
  68.       case GL_2D:
  69.          ctx->Feedback._Mask = 0;
  70.          break;
  71.       case GL_3D:
  72.          ctx->Feedback._Mask = FB_3D;
  73.          break;
  74.       case GL_3D_COLOR:
  75.          ctx->Feedback._Mask = (FB_3D | FB_COLOR);
  76.          break;
  77.       case GL_3D_COLOR_TEXTURE:
  78.          ctx->Feedback._Mask = (FB_3D | FB_COLOR | FB_TEXTURE);
  79.          break;
  80.       case GL_4D_COLOR_TEXTURE:
  81.          ctx->Feedback._Mask = (FB_3D | FB_4D | FB_COLOR | FB_TEXTURE);
  82.          break;
  83.       default:
  84.          _mesa_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" );
  85.          return;
  86.    }
  87.  
  88.    FLUSH_VERTICES(ctx, _NEW_RENDERMODE); /* Always flush */
  89.    ctx->Feedback.Type = type;
  90.    ctx->Feedback.BufferSize = size;
  91.    ctx->Feedback.Buffer = buffer;
  92.    ctx->Feedback.Count = 0;                   /* Because of this. */
  93. }
  94.  
  95.  
  96. void GLAPIENTRY
  97. _mesa_PassThrough( GLfloat token )
  98. {
  99.    GET_CURRENT_CONTEXT(ctx);
  100.  
  101.    if (ctx->RenderMode==GL_FEEDBACK) {
  102.       FLUSH_VERTICES(ctx, 0);
  103.       _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN );
  104.       _mesa_feedback_token( ctx, token );
  105.    }
  106. }
  107.  
  108.  
  109. /**
  110.  * Put a vertex into the feedback buffer.
  111.  */
  112. void
  113. _mesa_feedback_vertex(struct gl_context *ctx,
  114.                       const GLfloat win[4],
  115.                       const GLfloat color[4],
  116.                       const GLfloat texcoord[4])
  117. {
  118.    _mesa_feedback_token( ctx, win[0] );
  119.    _mesa_feedback_token( ctx, win[1] );
  120.    if (ctx->Feedback._Mask & FB_3D) {
  121.       _mesa_feedback_token( ctx, win[2] );
  122.    }
  123.    if (ctx->Feedback._Mask & FB_4D) {
  124.       _mesa_feedback_token( ctx, win[3] );
  125.    }
  126.    if (ctx->Feedback._Mask & FB_COLOR) {
  127.       _mesa_feedback_token( ctx, color[0] );
  128.       _mesa_feedback_token( ctx, color[1] );
  129.       _mesa_feedback_token( ctx, color[2] );
  130.       _mesa_feedback_token( ctx, color[3] );
  131.    }
  132.    if (ctx->Feedback._Mask & FB_TEXTURE) {
  133.       _mesa_feedback_token( ctx, texcoord[0] );
  134.       _mesa_feedback_token( ctx, texcoord[1] );
  135.       _mesa_feedback_token( ctx, texcoord[2] );
  136.       _mesa_feedback_token( ctx, texcoord[3] );
  137.    }
  138. }
  139.  
  140.  
  141. /**********************************************************************/
  142. /** \name Selection */
  143. /*@{*/
  144.  
  145. /**
  146.  * Establish a buffer for selection mode values.
  147.  *
  148.  * \param size buffer size.
  149.  * \param buffer buffer.
  150.  *
  151.  * \sa glSelectBuffer().
  152.  *
  153.  * \note this function can't be put in a display list.
  154.  *
  155.  * Verifies we're not in selection mode, flushes the vertices and initialize
  156.  * the fields in __struct gl_contextRec::Select with the given buffer.
  157.  */
  158. void GLAPIENTRY
  159. _mesa_SelectBuffer( GLsizei size, GLuint *buffer )
  160. {
  161.    GET_CURRENT_CONTEXT(ctx);
  162.  
  163.    if (size < 0) {
  164.       _mesa_error(ctx, GL_INVALID_VALUE, "glSelectBuffer(size)");
  165.       return;
  166.    }
  167.  
  168.    if (ctx->RenderMode==GL_SELECT) {
  169.       _mesa_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" );
  170.       return;                   /* KW: added return */
  171.    }
  172.  
  173.    FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
  174.    ctx->Select.Buffer = buffer;
  175.    ctx->Select.BufferSize = size;
  176.    ctx->Select.BufferCount = 0;
  177.    ctx->Select.HitFlag = GL_FALSE;
  178.    ctx->Select.HitMinZ = 1.0;
  179.    ctx->Select.HitMaxZ = 0.0;
  180. }
  181.  
  182.  
  183. /**
  184.  * Write a value of a record into the selection buffer.
  185.  *
  186.  * \param ctx GL context.
  187.  * \param value value.
  188.  *
  189.  * Verifies there is free space in the buffer to write the value and
  190.  * increments the pointer.
  191.  */
  192. static inline void
  193. write_record(struct gl_context *ctx, GLuint value)
  194. {
  195.    if (ctx->Select.BufferCount < ctx->Select.BufferSize) {
  196.       ctx->Select.Buffer[ctx->Select.BufferCount] = value;
  197.    }
  198.    ctx->Select.BufferCount++;
  199. }
  200.  
  201.  
  202. /**
  203.  * Update the hit flag and the maximum and minimum depth values.
  204.  *
  205.  * \param ctx GL context.
  206.  * \param z depth.
  207.  *
  208.  * Sets gl_selection::HitFlag and updates gl_selection::HitMinZ and
  209.  * gl_selection::HitMaxZ.
  210.  */
  211. void
  212. _mesa_update_hitflag(struct gl_context *ctx, GLfloat z)
  213. {
  214.    ctx->Select.HitFlag = GL_TRUE;
  215.    if (z < ctx->Select.HitMinZ) {
  216.       ctx->Select.HitMinZ = z;
  217.    }
  218.    if (z > ctx->Select.HitMaxZ) {
  219.       ctx->Select.HitMaxZ = z;
  220.    }
  221. }
  222.  
  223.  
  224. /**
  225.  * Write the hit record.
  226.  *
  227.  * \param ctx GL context.
  228.  *
  229.  * Write the hit record, i.e., the number of names in the stack, the minimum and
  230.  * maximum depth values and the number of names in the name stack at the time
  231.  * of the event. Resets the hit flag.
  232.  *
  233.  * \sa gl_selection.
  234.  */
  235. static void
  236. write_hit_record(struct gl_context *ctx)
  237. {
  238.    GLuint i;
  239.    GLuint zmin, zmax, zscale = (~0u);
  240.  
  241.    /* HitMinZ and HitMaxZ are in [0,1].  Multiply these values by */
  242.    /* 2^32-1 and round to nearest unsigned integer. */
  243.  
  244.    assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */
  245.    zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ);
  246.    zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ);
  247.  
  248.    write_record( ctx, ctx->Select.NameStackDepth );
  249.    write_record( ctx, zmin );
  250.    write_record( ctx, zmax );
  251.    for (i = 0; i < ctx->Select.NameStackDepth; i++) {
  252.       write_record( ctx, ctx->Select.NameStack[i] );
  253.    }
  254.  
  255.    ctx->Select.Hits++;
  256.    ctx->Select.HitFlag = GL_FALSE;
  257.    ctx->Select.HitMinZ = 1.0;
  258.    ctx->Select.HitMaxZ = -1.0;
  259. }
  260.  
  261.  
  262. /**
  263.  * Initialize the name stack.
  264.  *
  265.  * Verifies we are in select mode and resets the name stack depth and resets
  266.  * the hit record data in gl_selection. Marks new render mode in
  267.  * __struct gl_contextRec::NewState.
  268.  */
  269. void GLAPIENTRY
  270. _mesa_InitNames( void )
  271. {
  272.    GET_CURRENT_CONTEXT(ctx);
  273.    FLUSH_VERTICES(ctx, 0);
  274.  
  275.    /* Record the hit before the HitFlag is wiped out again. */
  276.    if (ctx->RenderMode == GL_SELECT) {
  277.       if (ctx->Select.HitFlag) {
  278.          write_hit_record( ctx );
  279.       }
  280.    }
  281.    ctx->Select.NameStackDepth = 0;
  282.    ctx->Select.HitFlag = GL_FALSE;
  283.    ctx->Select.HitMinZ = 1.0;
  284.    ctx->Select.HitMaxZ = 0.0;
  285.    ctx->NewState |= _NEW_RENDERMODE;
  286. }
  287.  
  288.  
  289. /**
  290.  * Load the top-most name of the name stack.
  291.  *
  292.  * \param name name.
  293.  *
  294.  * Verifies we are in selection mode and that the name stack is not empty.
  295.  * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
  296.  * and replace the top-most name in the stack.
  297.  *
  298.  * sa __struct gl_contextRec::Select.
  299.  */
  300. void GLAPIENTRY
  301. _mesa_LoadName( GLuint name )
  302. {
  303.    GET_CURRENT_CONTEXT(ctx);
  304.  
  305.    if (ctx->RenderMode != GL_SELECT) {
  306.       return;
  307.    }
  308.    if (ctx->Select.NameStackDepth == 0) {
  309.       _mesa_error( ctx, GL_INVALID_OPERATION, "glLoadName" );
  310.       return;
  311.    }
  312.  
  313.    FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
  314.  
  315.    if (ctx->Select.HitFlag) {
  316.       write_hit_record( ctx );
  317.    }
  318.    if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) {
  319.       ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name;
  320.    }
  321.    else {
  322.       ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name;
  323.    }
  324. }
  325.  
  326.  
  327. /**
  328.  * Push a name into the name stack.
  329.  *
  330.  * \param name name.
  331.  *
  332.  * Verifies we are in selection mode and that the name stack is not full.
  333.  * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
  334.  * and adds the name to the top of the name stack.
  335.  *
  336.  * sa __struct gl_contextRec::Select.
  337.  */
  338. void GLAPIENTRY
  339. _mesa_PushName( GLuint name )
  340. {
  341.    GET_CURRENT_CONTEXT(ctx);
  342.  
  343.    if (ctx->RenderMode != GL_SELECT) {
  344.       return;
  345.    }
  346.  
  347.    FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
  348.    if (ctx->Select.HitFlag) {
  349.       write_hit_record( ctx );
  350.    }
  351.    if (ctx->Select.NameStackDepth >= MAX_NAME_STACK_DEPTH) {
  352.       _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushName" );
  353.    }
  354.    else
  355.       ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name;
  356. }
  357.  
  358.  
  359. /**
  360.  * Pop a name into the name stack.
  361.  *
  362.  * Verifies we are in selection mode and that the name stack is not empty.
  363.  * Flushes vertices. If there is a hit flag writes it (via write_hit_record()),
  364.  * and removes top-most name in the name stack.
  365.  *
  366.  * sa __struct gl_contextRec::Select.
  367.  */
  368. void GLAPIENTRY
  369. _mesa_PopName( void )
  370. {
  371.    GET_CURRENT_CONTEXT(ctx);
  372.  
  373.    if (ctx->RenderMode != GL_SELECT) {
  374.       return;
  375.    }
  376.  
  377.    FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
  378.    if (ctx->Select.HitFlag) {
  379.       write_hit_record( ctx );
  380.    }
  381.    if (ctx->Select.NameStackDepth == 0) {
  382.       _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopName" );
  383.    }
  384.    else
  385.       ctx->Select.NameStackDepth--;
  386. }
  387.  
  388. /*@}*/
  389.  
  390.  
  391. /**********************************************************************/
  392. /** \name Render Mode */
  393. /*@{*/
  394.  
  395. /**
  396.  * Set rasterization mode.
  397.  *
  398.  * \param mode rasterization mode.
  399.  *
  400.  * \note this function can't be put in a display list.
  401.  *
  402.  * \sa glRenderMode().
  403.  *
  404.  * Flushes the vertices and do the necessary cleanup according to the previous
  405.  * rasterization mode, such as writing the hit record or resent the select
  406.  * buffer index when exiting the select mode. Updates
  407.  * __struct gl_contextRec::RenderMode and notifies the driver via the
  408.  * dd_function_table::RenderMode callback.
  409.  */
  410. GLint GLAPIENTRY
  411. _mesa_RenderMode( GLenum mode )
  412. {
  413.    GET_CURRENT_CONTEXT(ctx);
  414.    GLint result;
  415.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
  416.  
  417.    if (MESA_VERBOSE & VERBOSE_API)
  418.       _mesa_debug(ctx, "glRenderMode %s\n", _mesa_lookup_enum_by_nr(mode));
  419.  
  420.    FLUSH_VERTICES(ctx, _NEW_RENDERMODE);
  421.  
  422.    switch (ctx->RenderMode) {
  423.       case GL_RENDER:
  424.          result = 0;
  425.          break;
  426.       case GL_SELECT:
  427.          if (ctx->Select.HitFlag) {
  428.             write_hit_record( ctx );
  429.          }
  430.          if (ctx->Select.BufferCount > ctx->Select.BufferSize) {
  431.             /* overflow */
  432. #ifdef DEBUG
  433.             _mesa_warning(ctx, "Feedback buffer overflow");
  434. #endif
  435.             result = -1;
  436.          }
  437.          else {
  438.             result = ctx->Select.Hits;
  439.          }
  440.          ctx->Select.BufferCount = 0;
  441.          ctx->Select.Hits = 0;
  442.          ctx->Select.NameStackDepth = 0;
  443.          break;
  444.       case GL_FEEDBACK:
  445.          if (ctx->Feedback.Count > ctx->Feedback.BufferSize) {
  446.             /* overflow */
  447.             result = -1;
  448.          }
  449.          else {
  450.             result = ctx->Feedback.Count;
  451.          }
  452.          ctx->Feedback.Count = 0;
  453.          break;
  454.       default:
  455.          _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
  456.          return 0;
  457.    }
  458.  
  459.    switch (mode) {
  460.       case GL_RENDER:
  461.          break;
  462.       case GL_SELECT:
  463.          if (ctx->Select.BufferSize==0) {
  464.             /* haven't called glSelectBuffer yet */
  465.             _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
  466.          }
  467.          break;
  468.       case GL_FEEDBACK:
  469.          if (ctx->Feedback.BufferSize==0) {
  470.             /* haven't called glFeedbackBuffer yet */
  471.             _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
  472.          }
  473.          break;
  474.       default:
  475.          _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
  476.          return 0;
  477.    }
  478.  
  479.    ctx->RenderMode = mode;
  480.    if (ctx->Driver.RenderMode)
  481.       ctx->Driver.RenderMode( ctx, mode );
  482.  
  483.    return result;
  484. }
  485.  
  486. /*@}*/
  487.  
  488.  
  489. /**********************************************************************/
  490. /** \name Initialization */
  491. /*@{*/
  492.  
  493. /**
  494.  * Initialize context feedback data.
  495.  */
  496. void _mesa_init_feedback( struct gl_context * ctx )
  497. {
  498.    /* Feedback */
  499.    ctx->Feedback.Type = GL_2D;   /* TODO: verify */
  500.    ctx->Feedback.Buffer = NULL;
  501.    ctx->Feedback.BufferSize = 0;
  502.    ctx->Feedback.Count = 0;
  503.  
  504.    /* Selection/picking */
  505.    ctx->Select.Buffer = NULL;
  506.    ctx->Select.BufferSize = 0;
  507.    ctx->Select.BufferCount = 0;
  508.    ctx->Select.Hits = 0;
  509.    ctx->Select.NameStackDepth = 0;
  510.  
  511.    /* Miscellaneous */
  512.    ctx->RenderMode = GL_RENDER;
  513. }
  514.  
  515. /*@}*/
  516.