1 /* $Id: draw.c,v 1.4 2002-07-17 21:55:19 bradleyb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
25 static char rcsid[] = "$Id: draw.c,v 1.4 2002-07-17 21:55:19 bradleyb Exp $";
35 void (*tmap_drawer_ptr)(grs_bitmap *bm,int nv,g3s_point **vertlist) = draw_tmap;
36 void (*flat_drawer_ptr)(int nv,int *vertlist) = gr_upoly_tmap;
37 int (*line_drawer_ptr)(fix x0,fix y0,fix x1,fix y1) = gr_line;
39 //specifies 2d drawing routines to use instead of defaults. Passing
40 //NULL for either or both restores defaults
41 void g3_set_special_render(void (*tmap_drawer)(),void (*flat_drawer)(),int (*line_drawer)(fix, fix, fix, fix))
43 tmap_drawer_ptr = (tmap_drawer)?tmap_drawer:draw_tmap;
44 flat_drawer_ptr = (flat_drawer)?flat_drawer:gr_upoly_tmap;
45 line_drawer_ptr = (line_drawer)?line_drawer:gr_line;
48 //deal with a clipped line
49 bool must_clip_line(g3s_point *p0,g3s_point *p1,ubyte codes_or)
53 if ((p0->p3_flags&PF_TEMP_POINT) || (p1->p3_flags&PF_TEMP_POINT))
55 ret = 0; //line has already been clipped, so give up
59 clip_line(&p0,&p1,codes_or);
61 ret = g3_draw_line(p0,p1);
66 if (p0->p3_flags & PF_TEMP_POINT)
69 if (p1->p3_flags & PF_TEMP_POINT)
75 //draws a line. takes two points. returns true if drew
76 bool g3_draw_line(g3s_point *p0,g3s_point *p1)
80 if (p0->p3_codes & p1->p3_codes)
83 codes_or = p0->p3_codes | p1->p3_codes;
85 if (codes_or & CC_BEHIND)
86 return must_clip_line(p0,p1,codes_or);
88 if (!(p0->p3_flags&PF_PROJECTED))
91 if (p0->p3_flags&PF_OVERFLOW)
92 return must_clip_line(p0,p1,codes_or);
95 if (!(p1->p3_flags&PF_PROJECTED))
98 if (p1->p3_flags&PF_OVERFLOW)
99 return must_clip_line(p0,p1,codes_or);
101 return (bool) (*line_drawer_ptr)(p0->p3_sx,p0->p3_sy,p1->p3_sx,p1->p3_sy);
105 //returns true if a plane is facing the viewer. takes the unrotated surface
106 //normal of the plane, and a point on it. The normal need not be normalized
107 bool g3_check_normal_facing(vms_vector *v,vms_vector *norm)
111 vm_vec_sub(&tempv,&View_position,v);
113 return (vm_vec_dot(&tempv,norm) > 0);
116 bool do_facing_check(vms_vector *norm,g3s_point **vertlist,vms_vector *p)
118 if (norm) { //have normal
120 Assert(norm->x || norm->y || norm->z);
122 return g3_check_normal_facing(p,norm);
124 else { //normal not specified, so must compute
128 //get three points (rotated) and compute normal
130 vm_vec_perp(&tempv,&vertlist[0]->p3_vec,&vertlist[1]->p3_vec,&vertlist[2]->p3_vec);
132 return (vm_vec_dot(&tempv,&vertlist[1]->p3_vec) < 0);
136 //like g3_draw_poly(), but checks to see if facing. If surface normal is
137 //NULL, this routine must compute it, which will be slow. It is better to
138 //pre-compute the normal, and pass it to this function. When the normal
139 //is passed, this function works like g3_check_normal_facing() plus
141 //returns -1 if not facing, 1 if off screen, 0 if drew
142 bool g3_check_and_draw_poly(int nv,g3s_point **pointlist,vms_vector *norm,vms_vector *pnt)
144 if (do_facing_check(norm,pointlist,pnt))
145 return g3_draw_poly(nv,pointlist);
150 bool g3_check_and_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm,vms_vector *norm,vms_vector *pnt)
152 if (do_facing_check(norm,pointlist,pnt))
153 return g3_draw_tmap(nv,pointlist,uvl_list,bm);
158 //deal with face that must be clipped
159 bool must_clip_flat_face(int nv,g3s_codes cc)
165 bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc);
167 if (nv>0 && !(cc.or&CC_BEHIND) && !cc.and) {
170 g3s_point *p = bufptr[i];
172 if (!(p->p3_flags&PF_PROJECTED))
175 if (p->p3_flags&PF_OVERFLOW) {
180 Vertex_list[i*2] = p->p3_sx;
181 Vertex_list[i*2+1] = p->p3_sy;
184 (*flat_drawer_ptr)(nv,(int *)Vertex_list);
194 if (Vbuf1[i]->p3_flags & PF_TEMP_POINT)
195 free_temp_point(Vbuf1[i]);
197 // Assert(free_point_num==0);
202 #if (!(defined(D1XD3D) || defined(OGL)))
203 //draw a flat-shaded face.
204 //returns 1 if off screen, 0 if drew
205 bool g3_draw_poly(int nv,g3s_point **pointlist)
211 cc.or = 0; cc.and = 0xff;
217 bufptr[i] = pointlist[i];
219 cc.and &= bufptr[i]->p3_codes;
220 cc.or |= bufptr[i]->p3_codes;
224 return 1; //all points off screen
227 return must_clip_flat_face(nv,cc);
229 //now make list of 2d coords (& check for overflow)
232 g3s_point *p = bufptr[i];
234 if (!(p->p3_flags&PF_PROJECTED))
237 if (p->p3_flags&PF_OVERFLOW)
238 return must_clip_flat_face(nv,cc);
240 Vertex_list[i*2] = p->p3_sx;
241 Vertex_list[i*2+1] = p->p3_sy;
244 (*flat_drawer_ptr)(nv,(int *)Vertex_list);
246 return 0; //say it drew
249 bool must_clip_tmap_face(int nv,g3s_codes cc,grs_bitmap *bm);
251 //draw a texture-mapped face.
252 //returns 1 if off screen, 0 if drew
253 bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm)
259 cc.or = 0; cc.and = 0xff;
266 p = bufptr[i] = pointlist[i];
268 cc.and &= p->p3_codes;
269 cc.or |= p->p3_codes;
271 p->p3_u = uvl_list[i].u;
272 p->p3_v = uvl_list[i].v;
273 p->p3_l = uvl_list[i].l;
275 p->p3_flags |= PF_UVS + PF_LS;
280 return 1; //all points off screen
283 return must_clip_tmap_face(nv,cc,bm);
285 //now make list of 2d coords (& check for overflow)
288 g3s_point *p = bufptr[i];
290 if (!(p->p3_flags&PF_PROJECTED))
293 if (p->p3_flags&PF_OVERFLOW) {
294 Int3(); //should not overflow after clip
299 (*tmap_drawer_ptr)(bm,nv,bufptr);
301 return 0; //say it drew
305 bool must_clip_tmap_face(int nv,g3s_codes cc,grs_bitmap *bm)
310 bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc);
312 if (nv && !(cc.or&CC_BEHIND) && !cc.and) {
315 g3s_point *p = bufptr[i];
317 if (!(p->p3_flags&PF_PROJECTED))
320 if (p->p3_flags&PF_OVERFLOW) {
321 Int3(); //should not overflow after clip
326 (*tmap_drawer_ptr)(bm,nv,bufptr);
333 if (bufptr[i]->p3_flags & PF_TEMP_POINT)
334 free_temp_point(bufptr[i]);
336 // Assert(free_point_num==0);
343 int checkmuldiv(fix *r,fix a,fix b,fix c);
347 //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
348 //radius, but not to the distance from the eye
349 int g3_draw_sphere(g3s_point *pnt,fix rad)
351 if (! (pnt->p3_codes & CC_BEHIND)) {
353 if (! (pnt->p3_flags & PF_PROJECTED))
354 g3_project_point(pnt);
356 if (! (pnt->p3_codes & PF_OVERFLOW)) {
359 r2 = fixmul(rad,Matrix_scale.x);
361 if (checkmuldiv(&t,r2,Canv_w2,pnt->p3_z))
362 return gr_disk(pnt->p3_sx,pnt->p3_sy,t);
366 return gr_disk(pnt->p3_sx, pnt->p3_sy, fl2f(((f2fl(r2) * fCanv_w2) / f2fl(pnt->p3_z))));