Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5098 | clevermous | 1 | #include "zgl.h" |
2 | |||
3 | /* fill triangle profile */ |
||
4 | /* #define PROFILE */ |
||
5 | |||
6 | #define CLIP_XMIN (1<<0) |
||
7 | #define CLIP_XMAX (1<<1) |
||
8 | #define CLIP_YMIN (1<<2) |
||
9 | #define CLIP_YMAX (1<<3) |
||
10 | #define CLIP_ZMIN (1<<4) |
||
11 | #define CLIP_ZMAX (1<<5) |
||
12 | |||
13 | void gl_transform_to_viewport(GLContext *c,GLVertex *v) |
||
14 | { |
||
15 | float winv; |
||
16 | |||
17 | /* coordinates */ |
||
18 | winv=1.0/v->pc.W; |
||
19 | v->zp.x= (int) ( v->pc.X * winv * c->viewport.scale.X |
||
20 | + c->viewport.trans.X ); |
||
21 | v->zp.y= (int) ( v->pc.Y * winv * c->viewport.scale.Y |
||
22 | + c->viewport.trans.Y ); |
||
23 | v->zp.z= (int) ( v->pc.Z * winv * c->viewport.scale.Z |
||
24 | + c->viewport.trans.Z ); |
||
25 | /* color */ |
||
26 | if (c->lighting_enabled) { |
||
27 | v->zp.r=(int)(v->color.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) |
||
28 | + ZB_POINT_RED_MIN); |
||
29 | v->zp.g=(int)(v->color.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) |
||
30 | + ZB_POINT_GREEN_MIN); |
||
31 | v->zp.b=(int)(v->color.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) |
||
32 | + ZB_POINT_BLUE_MIN); |
||
33 | } else { |
||
34 | /* no need to convert to integer if no lighting : take current color */ |
||
35 | v->zp.r = c->longcurrent_color[0]; |
||
36 | v->zp.g = c->longcurrent_color[1]; |
||
37 | v->zp.b = c->longcurrent_color[2]; |
||
38 | } |
||
39 | |||
40 | /* texture */ |
||
41 | |||
42 | if (c->texture_2d_enabled) { |
||
43 | v->zp.s=(int)(v->tex_coord.X * (ZB_POINT_S_MAX - ZB_POINT_S_MIN) |
||
44 | + ZB_POINT_S_MIN); |
||
45 | v->zp.t=(int)(v->tex_coord.Y * (ZB_POINT_T_MAX - ZB_POINT_T_MIN) |
||
46 | + ZB_POINT_T_MIN); |
||
47 | } |
||
48 | } |
||
49 | |||
50 | |||
51 | static void gl_add_select1(GLContext *c,int z1,int z2,int z3) |
||
52 | { |
||
53 | unsigned int min,max; |
||
54 | min=max=z1; |
||
55 | if (z2 |
||
56 | if (z3 |
||
57 | if (z2>max) max=z2; |
||
58 | if (z3>max) max=z3; |
||
59 | |||
60 | gl_add_select(c,0xffffffff-min,0xffffffff-max); |
||
61 | } |
||
62 | |||
63 | /* point */ |
||
64 | |||
65 | void gl_draw_point(GLContext *c,GLVertex *p0) |
||
66 | { |
||
67 | if (p0->clip_code == 0) { |
||
68 | if (c->render_mode == GL_SELECT) { |
||
69 | gl_add_select(c,p0->zp.z,p0->zp.z); |
||
70 | } else { |
||
71 | ZB_plot(c->zb,&p0->zp); |
||
72 | } |
||
73 | } |
||
74 | } |
||
75 | |||
76 | /* line */ |
||
77 | |||
78 | static inline void interpolate(GLVertex *q,GLVertex *p0,GLVertex *p1,float t) |
||
79 | { |
||
80 | q->pc.X=p0->pc.X+(p1->pc.X-p0->pc.X)*t; |
||
81 | q->pc.Y=p0->pc.Y+(p1->pc.Y-p0->pc.Y)*t; |
||
82 | q->pc.Z=p0->pc.Z+(p1->pc.Z-p0->pc.Z)*t; |
||
83 | q->pc.W=p0->pc.W+(p1->pc.W-p0->pc.W)*t; |
||
84 | |||
85 | q->color.v[0]=p0->color.v[0] + (p1->color.v[0]-p0->color.v[0])*t; |
||
86 | q->color.v[1]=p0->color.v[1] + (p1->color.v[1]-p0->color.v[1])*t; |
||
87 | q->color.v[2]=p0->color.v[2] + (p1->color.v[2]-p0->color.v[2])*t; |
||
88 | } |
||
89 | |||
90 | /* |
||
91 | * Line Clipping |
||
92 | */ |
||
93 | |||
94 | /* Line Clipping algorithm from 'Computer Graphics', Principles and |
||
95 | Practice */ |
||
96 | static inline int ClipLine1(float denom,float num,float *tmin,float *tmax) |
||
97 | { |
||
98 | float t; |
||
99 | |||
100 | if (denom>0) { |
||
101 | t=num/denom; |
||
102 | if (t>*tmax) return 0; |
||
103 | if (t>*tmin) *tmin=t; |
||
104 | } else if (denom<0) { |
||
105 | t=num/denom; |
||
106 | if (t<*tmin) return 0; |
||
107 | if (t<*tmax) *tmax=t; |
||
108 | } else if (num>0) return 0; |
||
109 | return 1; |
||
110 | } |
||
111 | |||
112 | void gl_draw_line(GLContext *c,GLVertex *p1,GLVertex *p2) |
||
113 | { |
||
114 | float dx,dy,dz,dw,x1,y1,z1,w1; |
||
115 | float tmin,tmax; |
||
116 | GLVertex q1,q2; |
||
117 | int cc1,cc2; |
||
118 | |||
119 | cc1=p1->clip_code; |
||
120 | cc2=p2->clip_code; |
||
121 | |||
122 | if ( (cc1 | cc2) == 0) { |
||
123 | if (c->render_mode == GL_SELECT) { |
||
124 | gl_add_select1(c,p1->zp.z,p2->zp.z,p2->zp.z); |
||
125 | } else { |
||
126 | if (c->depth_test) |
||
127 | ZB_line_z(c->zb,&p1->zp,&p2->zp); |
||
128 | else |
||
129 | ZB_line(c->zb,&p1->zp,&p2->zp); |
||
130 | } |
||
131 | } else if ( (cc1&cc2) != 0 ) { |
||
132 | return; |
||
133 | } else { |
||
134 | dx=p2->pc.X-p1->pc.X; |
||
135 | dy=p2->pc.Y-p1->pc.Y; |
||
136 | dz=p2->pc.Z-p1->pc.Z; |
||
137 | dw=p2->pc.W-p1->pc.W; |
||
138 | x1=p1->pc.X; |
||
139 | y1=p1->pc.Y; |
||
140 | z1=p1->pc.Z; |
||
141 | w1=p1->pc.W; |
||
142 | |||
143 | tmin=0; |
||
144 | tmax=1; |
||
145 | if (ClipLine1(dx+dw,-x1-w1,&tmin,&tmax) && |
||
146 | ClipLine1(-dx+dw,x1-w1,&tmin,&tmax) && |
||
147 | ClipLine1(dy+dw,-y1-w1,&tmin,&tmax) && |
||
148 | ClipLine1(-dy+dw,y1-w1,&tmin,&tmax) && |
||
149 | ClipLine1(dz+dw,-z1-w1,&tmin,&tmax) && |
||
150 | ClipLine1(-dz+dw,z1-w1,&tmin,&tmax)) { |
||
151 | |||
152 | interpolate(&q1,p1,p2,tmin); |
||
153 | interpolate(&q2,p1,p2,tmax); |
||
154 | gl_transform_to_viewport(c,&q1); |
||
155 | gl_transform_to_viewport(c,&q2); |
||
156 | |||
157 | RGBFtoRGBI(q1.color.v[0],q1.color.v[1],q1.color.v[2],q1.zp.r,q1.zp.g,q1.zp.b); |
||
158 | RGBFtoRGBI(q2.color.v[0],q2.color.v[1],q2.color.v[2],q2.zp.r,q2.zp.g,q2.zp.b); |
||
159 | |||
160 | if (c->depth_test) |
||
161 | ZB_line_z(c->zb,&q1.zp,&q2.zp); |
||
162 | else |
||
163 | ZB_line(c->zb,&q1.zp,&q2.zp); |
||
164 | } |
||
165 | } |
||
166 | } |
||
167 | |||
168 | |||
169 | /* triangle */ |
||
170 | |||
171 | /* |
||
172 | * Clipping |
||
173 | */ |
||
174 | |||
175 | /* We clip the segment [a,b] against the 6 planes of the normal volume. |
||
176 | * We compute the point 'c' of intersection and the value of the parameter 't' |
||
177 | * of the intersection if x=a+t(b-a). |
||
178 | */ |
||
179 | |||
180 | #define clip_func(name,sign,dir,dir1,dir2) \ |
||
181 | static float name(V4 *c,V4 *a,V4 *b) \ |
||
182 | {\ |
||
183 | float t,dX,dY,dZ,dW,den;\ |
||
184 | dX = (b->X - a->X);\ |
||
185 | dY = (b->Y - a->Y);\ |
||
186 | dZ = (b->Z - a->Z);\ |
||
187 | dW = (b->W - a->W);\ |
||
188 | den = -(sign d ## dir) + dW;\ |
||
189 | if (den == 0) t=0;\ |
||
190 | else t = ( sign a->dir - a->W) / den;\ |
||
191 | c->dir1 = a->dir1 + t * d ## dir1;\ |
||
192 | c->dir2 = a->dir2 + t * d ## dir2;\ |
||
193 | c->W = a->W + t * dW;\ |
||
194 | c->dir = sign c->W;\ |
||
195 | return t;\ |
||
196 | } |
||
197 | |||
198 | |||
199 | clip_func(clip_xmin,-,X,Y,Z) |
||
200 | |||
201 | clip_func(clip_xmax,+,X,Y,Z) |
||
202 | |||
203 | clip_func(clip_ymin,-,Y,X,Z) |
||
204 | |||
205 | clip_func(clip_ymax,+,Y,X,Z) |
||
206 | |||
207 | clip_func(clip_zmin,-,Z,X,Y) |
||
208 | |||
209 | clip_func(clip_zmax,+,Z,X,Y) |
||
210 | |||
211 | |||
212 | float (*clip_proc[6])(V4 *,V4 *,V4 *)= { |
||
213 | clip_xmin,clip_xmax, |
||
214 | clip_ymin,clip_ymax, |
||
215 | clip_zmin,clip_zmax |
||
216 | }; |
||
217 | |||
218 | static inline void updateTmp(GLContext *c, |
||
219 | GLVertex *q,GLVertex *p0,GLVertex *p1,float t) |
||
220 | { |
||
221 | if (c->current_shade_model == GL_SMOOTH) { |
||
222 | q->color.v[0]=p0->color.v[0] + (p1->color.v[0]-p0->color.v[0])*t; |
||
223 | q->color.v[1]=p0->color.v[1] + (p1->color.v[1]-p0->color.v[1])*t; |
||
224 | q->color.v[2]=p0->color.v[2] + (p1->color.v[2]-p0->color.v[2])*t; |
||
225 | } else { |
||
226 | q->color.v[0]=p0->color.v[0]; |
||
227 | q->color.v[1]=p0->color.v[1]; |
||
228 | q->color.v[2]=p0->color.v[2]; |
||
229 | } |
||
230 | |||
231 | if (c->texture_2d_enabled) { |
||
232 | q->tex_coord.X=p0->tex_coord.X + (p1->tex_coord.X-p0->tex_coord.X)*t; |
||
233 | q->tex_coord.Y=p0->tex_coord.Y + (p1->tex_coord.Y-p0->tex_coord.Y)*t; |
||
234 | } |
||
235 | |||
236 | q->clip_code=gl_clipcode(q->pc.X,q->pc.Y,q->pc.Z,q->pc.W); |
||
237 | if (q->clip_code==0){ |
||
238 | gl_transform_to_viewport(c,q); |
||
239 | RGBFtoRGBI(q->color.v[0],q->color.v[1],q->color.v[2],q->zp.r,q->zp.g,q->zp.b); |
||
240 | } |
||
241 | } |
||
242 | |||
243 | static void gl_draw_triangle_clip(GLContext *c, |
||
244 | GLVertex *p0,GLVertex *p1,GLVertex *p2,int clip_bit); |
||
245 | |||
246 | void gl_draw_triangle(GLContext *c, |
||
247 | GLVertex *p0,GLVertex *p1,GLVertex *p2) |
||
248 | { |
||
249 | int co,c_and,cc[3],front; |
||
250 | float norm; |
||
251 | |||
252 | cc[0]=p0->clip_code; |
||
253 | cc[1]=p1->clip_code; |
||
254 | cc[2]=p2->clip_code; |
||
255 | |||
256 | co=cc[0] | cc[1] | cc[2]; |
||
257 | |||
258 | /* we handle the non clipped case here to go faster */ |
||
259 | if (co==0) { |
||
260 | |||
261 | norm=(float)(p1->zp.x-p0->zp.x)*(float)(p2->zp.y-p0->zp.y)- |
||
262 | (float)(p2->zp.x-p0->zp.x)*(float)(p1->zp.y-p0->zp.y); |
||
263 | |||
264 | if (norm == 0) return; |
||
265 | |||
266 | front = norm < 0.0; |
||
267 | front = front ^ c->current_front_face; |
||
268 | |||
269 | /* back face culling */ |
||
270 | if (c->cull_face_enabled) { |
||
271 | /* most used case first */ |
||
272 | if (c->current_cull_face == GL_BACK) { |
||
273 | if (front == 0) return; |
||
274 | c->draw_triangle_front(c,p0,p1,p2); |
||
275 | } else if (c->current_cull_face == GL_FRONT) { |
||
276 | if (front != 0) return; |
||
277 | c->draw_triangle_back(c,p0,p1,p2); |
||
278 | } else { |
||
279 | return; |
||
280 | } |
||
281 | } else { |
||
282 | /* no culling */ |
||
283 | if (front) { |
||
284 | c->draw_triangle_front(c,p0,p1,p2); |
||
285 | } else { |
||
286 | c->draw_triangle_back(c,p0,p1,p2); |
||
287 | } |
||
288 | } |
||
289 | } else { |
||
290 | c_and=cc[0] & cc[1] & cc[2]; |
||
291 | if (c_and==0) { |
||
292 | gl_draw_triangle_clip(c,p0,p1,p2,0); |
||
293 | } |
||
294 | } |
||
295 | } |
||
296 | |||
297 | static void gl_draw_triangle_clip(GLContext *c, |
||
298 | GLVertex *p0,GLVertex *p1,GLVertex *p2,int clip_bit) |
||
299 | { |
||
300 | int co,c_and,co1,cc[3],edge_flag_tmp,clip_mask; |
||
301 | GLVertex tmp1,tmp2,*q[3]; |
||
302 | float tt; |
||
303 | |||
304 | cc[0]=p0->clip_code; |
||
305 | cc[1]=p1->clip_code; |
||
306 | cc[2]=p2->clip_code; |
||
307 | |||
308 | co=cc[0] | cc[1] | cc[2]; |
||
309 | if (co == 0) { |
||
310 | gl_draw_triangle(c,p0,p1,p2); |
||
311 | } else { |
||
312 | c_and=cc[0] & cc[1] & cc[2]; |
||
313 | /* the triangle is completely outside */ |
||
314 | if (c_and!=0) return; |
||
315 | |||
316 | /* find the next direction to clip */ |
||
317 | while (clip_bit < 6 && (co & (1 << clip_bit)) == 0) { |
||
318 | clip_bit++; |
||
319 | } |
||
320 | |||
321 | /* this test can be true only in case of rounding errors */ |
||
322 | if (clip_bit == 6) { |
||
323 | #if 0 |
||
324 | printf("Error:\n"); |
||
325 | printf("%f %f %f %f\n",p0->pc.X,p0->pc.Y,p0->pc.Z,p0->pc.W); |
||
326 | printf("%f %f %f %f\n",p1->pc.X,p1->pc.Y,p1->pc.Z,p1->pc.W); |
||
327 | printf("%f %f %f %f\n",p2->pc.X,p2->pc.Y,p2->pc.Z,p2->pc.W); |
||
328 | #endif |
||
329 | return; |
||
330 | } |
||
331 | |||
332 | clip_mask = 1 << clip_bit; |
||
333 | co1=(cc[0] ^ cc[1] ^ cc[2]) & clip_mask; |
||
334 | |||
335 | if (co1) { |
||
336 | /* one point outside */ |
||
337 | |||
338 | if (cc[0] & clip_mask) { q[0]=p0; q[1]=p1; q[2]=p2; } |
||
339 | else if (cc[1] & clip_mask) { q[0]=p1; q[1]=p2; q[2]=p0; } |
||
340 | else { q[0]=p2; q[1]=p0; q[2]=p1; } |
||
341 | |||
342 | tt=clip_proc[clip_bit](&tmp1.pc,&q[0]->pc,&q[1]->pc); |
||
343 | updateTmp(c,&tmp1,q[0],q[1],tt); |
||
344 | |||
345 | tt=clip_proc[clip_bit](&tmp2.pc,&q[0]->pc,&q[2]->pc); |
||
346 | updateTmp(c,&tmp2,q[0],q[2],tt); |
||
347 | |||
348 | tmp1.edge_flag=q[0]->edge_flag; |
||
349 | edge_flag_tmp=q[2]->edge_flag; |
||
350 | q[2]->edge_flag=0; |
||
351 | gl_draw_triangle_clip(c,&tmp1,q[1],q[2],clip_bit+1); |
||
352 | |||
353 | tmp2.edge_flag=0; |
||
354 | tmp1.edge_flag=0; |
||
355 | q[2]->edge_flag=edge_flag_tmp; |
||
356 | gl_draw_triangle_clip(c,&tmp2,&tmp1,q[2],clip_bit+1); |
||
357 | } else { |
||
358 | /* two points outside */ |
||
359 | |||
360 | if ((cc[0] & clip_mask)==0) { q[0]=p0; q[1]=p1; q[2]=p2; } |
||
361 | else if ((cc[1] & clip_mask)==0) { q[0]=p1; q[1]=p2; q[2]=p0; } |
||
362 | else { q[0]=p2; q[1]=p0; q[2]=p1; } |
||
363 | |||
364 | tt=clip_proc[clip_bit](&tmp1.pc,&q[0]->pc,&q[1]->pc); |
||
365 | updateTmp(c,&tmp1,q[0],q[1],tt); |
||
366 | |||
367 | tt=clip_proc[clip_bit](&tmp2.pc,&q[0]->pc,&q[2]->pc); |
||
368 | updateTmp(c,&tmp2,q[0],q[2],tt); |
||
369 | |||
370 | tmp1.edge_flag=1; |
||
371 | tmp2.edge_flag=q[2]->edge_flag; |
||
372 | gl_draw_triangle_clip(c,q[0],&tmp1,&tmp2,clip_bit+1); |
||
373 | } |
||
374 | } |
||
375 | } |
||
376 | |||
377 | |||
378 | void gl_draw_triangle_select(GLContext *c, |
||
379 | GLVertex *p0,GLVertex *p1,GLVertex *p2) |
||
380 | { |
||
381 | gl_add_select1(c,p0->zp.z,p1->zp.z,p2->zp.z); |
||
382 | } |
||
383 | |||
384 | #ifdef PROFILE |
||
385 | int count_triangles,count_triangles_textured,count_pixels; |
||
386 | #endif |
||
387 | |||
388 | void gl_draw_triangle_fill(GLContext *c, |
||
389 | GLVertex *p0,GLVertex *p1,GLVertex *p2) |
||
390 | { |
||
391 | #ifdef PROFILE |
||
392 | { |
||
393 | int norm; |
||
394 | assert(p0->zp.x >= 0 && p0->zp.x < c->zb->xsize); |
||
395 | assert(p0->zp.y >= 0 && p0->zp.y < c->zb->ysize); |
||
396 | assert(p1->zp.x >= 0 && p1->zp.x < c->zb->xsize); |
||
397 | assert(p1->zp.y >= 0 && p1->zp.y < c->zb->ysize); |
||
398 | assert(p2->zp.x >= 0 && p2->zp.x < c->zb->xsize); |
||
399 | assert(p2->zp.y >= 0 && p2->zp.y < c->zb->ysize); |
||
400 | |||
401 | norm=(p1->zp.x-p0->zp.x)*(p2->zp.y-p0->zp.y)- |
||
402 | (p2->zp.x-p0->zp.x)*(p1->zp.y-p0->zp.y); |
||
403 | count_pixels+=abs(norm)/2; |
||
404 | count_triangles++; |
||
405 | } |
||
406 | #endif |
||
407 | |||
408 | if (c->texture_2d_enabled) { |
||
409 | #ifdef PROFILE |
||
410 | count_triangles_textured++; |
||
411 | #endif |
||
412 | ZB_setTexture(c->zb,c->current_texture->images[0].pixmap); |
||
413 | ZB_fillTriangleMappingPerspective(c->zb,&p0->zp,&p1->zp,&p2->zp); |
||
414 | } else if (c->current_shade_model == GL_SMOOTH) { |
||
415 | ZB_fillTriangleSmooth(c->zb,&p0->zp,&p1->zp,&p2->zp); |
||
416 | } else { |
||
417 | ZB_fillTriangleFlat(c->zb,&p0->zp,&p1->zp,&p2->zp); |
||
418 | } |
||
419 | } |
||
420 | |||
421 | /* Render a clipped triangle in line mode */ |
||
422 | |||
423 | void gl_draw_triangle_line(GLContext *c, |
||
424 | GLVertex *p0,GLVertex *p1,GLVertex *p2) |
||
425 | { |
||
426 | if (c->depth_test) { |
||
427 | if (p0->edge_flag) ZB_line_z(c->zb,&p0->zp,&p1->zp); |
||
428 | if (p1->edge_flag) ZB_line_z(c->zb,&p1->zp,&p2->zp); |
||
429 | if (p2->edge_flag) ZB_line_z(c->zb,&p2->zp,&p0->zp); |
||
430 | } else { |
||
431 | if (p0->edge_flag) ZB_line(c->zb,&p0->zp,&p1->zp); |
||
432 | if (p1->edge_flag) ZB_line(c->zb,&p1->zp,&p2->zp); |
||
433 | if (p2->edge_flag) ZB_line(c->zb,&p2->zp,&p0->zp); |
||
434 | } |
||
435 | } |
||
436 | |||
437 | |||
438 | |||
439 | /* Render a clipped triangle in point mode */ |
||
440 | void gl_draw_triangle_point(GLContext *c, |
||
441 | GLVertex *p0,GLVertex *p1,GLVertex *p2) |
||
442 | { |
||
443 | if (p0->edge_flag) ZB_plot(c->zb,&p0->zp); |
||
444 | if (p1->edge_flag) ZB_plot(c->zb,&p1->zp); |
||
445 | if (p2->edge_flag) ZB_plot(c->zb,&p2->zp); |
||
446 | }>>>>>>><>><>>>*tmax)>*tmin)>0)>5) |
||
447 | |||
448 | |||
449 | |||
450 |