1/**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include "util/u_memory.h"
29#include "util/u_math.h"
30#include "util/u_prim.h"
31#include "pipe/p_context.h"
32#include "draw/draw_context.h"
33#include "draw/draw_private.h"
34#include "draw/draw_pt.h"
35#include "draw/draw_vs.h"
36
37#define DO_CLIP_XY           0x1
38#define DO_CLIP_FULL_Z       0x2
39#define DO_CLIP_HALF_Z       0x4
40#define DO_CLIP_USER         0x8
41#define DO_VIEWPORT          0x10
42#define DO_EDGEFLAG          0x20
43#define DO_CLIP_XY_GUARD_BAND 0x40
44
45
46struct pt_post_vs {
47   struct draw_context *draw;
48
49   unsigned flags;
50
51   boolean (*run)( struct pt_post_vs *pvs,
52                   struct draw_vertex_info *info,
53                   const struct draw_prim_info *prim_info );
54};
55
56static inline void
57initialize_vertex_header(struct vertex_header *header)
58{
59   header->clipmask = 0;
60   header->edgeflag = 1;
61   header->pad = 0;
62   header->vertex_id = UNDEFINED_VERTEX_ID;
63}
64
65static inline float
66dot4(const float *a, const float *b)
67{
68   return (a[0]*b[0] +
69           a[1]*b[1] +
70           a[2]*b[2] +
71           a[3]*b[3]);
72}
73
74#define FLAGS (0)
75#define TAG(x) x##_none
76#include "draw_cliptest_tmp.h"
77
78#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_VIEWPORT)
79#define TAG(x) x##_xy_fullz_viewport
80#include "draw_cliptest_tmp.h"
81
82#define FLAGS (DO_CLIP_XY | DO_CLIP_HALF_Z | DO_VIEWPORT)
83#define TAG(x) x##_xy_halfz_viewport
84#include "draw_cliptest_tmp.h"
85
86#define FLAGS (DO_CLIP_XY_GUARD_BAND | DO_CLIP_HALF_Z | DO_VIEWPORT)
87#define TAG(x) x##_xy_gb_halfz_viewport
88#include "draw_cliptest_tmp.h"
89
90#define FLAGS (DO_CLIP_FULL_Z | DO_VIEWPORT)
91#define TAG(x) x##_fullz_viewport
92#include "draw_cliptest_tmp.h"
93
94#define FLAGS (DO_CLIP_HALF_Z | DO_VIEWPORT)
95#define TAG(x) x##_halfz_viewport
96#include "draw_cliptest_tmp.h"
97
98#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT)
99#define TAG(x) x##_xy_fullz_user_viewport
100#include "draw_cliptest_tmp.h"
101
102#define FLAGS (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT | DO_EDGEFLAG)
103#define TAG(x) x##_xy_fullz_user_viewport_edgeflag
104#include "draw_cliptest_tmp.h"
105
106
107
108/* Don't want to create 64 versions of this function, so catch the
109 * less common ones here.  This is looking like something which should
110 * be code-generated, perhaps appended to the end of the vertex
111 * shader.
112 */
113#define FLAGS (pvs->flags)
114#define TAG(x) x##_generic
115#include "draw_cliptest_tmp.h"
116
117
118
119boolean draw_pt_post_vs_run( struct pt_post_vs *pvs,
120                             struct draw_vertex_info *info,
121                             const struct draw_prim_info *prim_info )
122{
123   return pvs->run( pvs, info, prim_info );
124}
125
126
127void draw_pt_post_vs_prepare( struct pt_post_vs *pvs,
128			      boolean clip_xy,
129			      boolean clip_z,
130                              boolean clip_user,
131                              boolean guard_band,
132			      boolean bypass_viewport,
133                              boolean clip_halfz,
134			      boolean need_edgeflags )
135{
136   pvs->flags = 0;
137
138   /* This combination not currently tested/in use:
139    */
140   if (!clip_halfz)
141      guard_band = FALSE;
142
143   if (clip_xy && !guard_band) {
144      pvs->flags |= DO_CLIP_XY;
145      ASSIGN_4V( pvs->draw->plane[0], -1,  0,  0, 1 );
146      ASSIGN_4V( pvs->draw->plane[1],  1,  0,  0, 1 );
147      ASSIGN_4V( pvs->draw->plane[2],  0, -1,  0, 1 );
148      ASSIGN_4V( pvs->draw->plane[3],  0,  1,  0, 1 );
149   }
150   else if (clip_xy && guard_band) {
151      pvs->flags |= DO_CLIP_XY_GUARD_BAND;
152      ASSIGN_4V( pvs->draw->plane[0], -0.5,  0,  0, 1 );
153      ASSIGN_4V( pvs->draw->plane[1],  0.5,  0,  0, 1 );
154      ASSIGN_4V( pvs->draw->plane[2],  0, -0.5,  0, 1 );
155      ASSIGN_4V( pvs->draw->plane[3],  0,  0.5,  0, 1 );
156   }
157
158   if (clip_z) {
159      if (clip_halfz) {
160         pvs->flags |= DO_CLIP_HALF_Z;
161         ASSIGN_4V( pvs->draw->plane[4],  0,  0,  1, 0 );
162      } else {
163         pvs->flags |= DO_CLIP_FULL_Z;
164         ASSIGN_4V( pvs->draw->plane[4],  0,  0,  1, 1 );
165      }
166   }
167
168   if (clip_user)
169      pvs->flags |= DO_CLIP_USER;
170
171   if (!bypass_viewport)
172      pvs->flags |= DO_VIEWPORT;
173
174   if (need_edgeflags)
175      pvs->flags |= DO_EDGEFLAG;
176
177   /* Now select the relevant function:
178    */
179   switch (pvs->flags) {
180   case 0:
181      pvs->run = do_cliptest_none;
182      break;
183
184   case DO_CLIP_XY | DO_CLIP_FULL_Z | DO_VIEWPORT:
185      pvs->run = do_cliptest_xy_fullz_viewport;
186      break;
187
188   case DO_CLIP_XY | DO_CLIP_HALF_Z | DO_VIEWPORT:
189      pvs->run = do_cliptest_xy_halfz_viewport;
190      break;
191
192   case DO_CLIP_XY_GUARD_BAND | DO_CLIP_HALF_Z | DO_VIEWPORT:
193      pvs->run = do_cliptest_xy_gb_halfz_viewport;
194      break;
195
196   case DO_CLIP_FULL_Z | DO_VIEWPORT:
197      pvs->run = do_cliptest_fullz_viewport;
198      break;
199
200   case DO_CLIP_HALF_Z | DO_VIEWPORT:
201      pvs->run = do_cliptest_halfz_viewport;
202      break;
203
204   case DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER | DO_VIEWPORT:
205      pvs->run = do_cliptest_xy_fullz_user_viewport;
206      break;
207
208   case (DO_CLIP_XY | DO_CLIP_FULL_Z | DO_CLIP_USER |
209         DO_VIEWPORT | DO_EDGEFLAG):
210      pvs->run = do_cliptest_xy_fullz_user_viewport_edgeflag;
211      break;
212
213   default:
214      pvs->run = do_cliptest_generic;
215      break;
216   }
217}
218
219
220struct pt_post_vs *draw_pt_post_vs_create( struct draw_context *draw )
221{
222   struct pt_post_vs *pvs = CALLOC_STRUCT( pt_post_vs );
223   if (!pvs)
224      return NULL;
225
226   pvs->draw = draw;
227
228   return pvs;
229}
230
231void draw_pt_post_vs_destroy( struct pt_post_vs *pvs )
232{
233   FREE(pvs);
234}
235