Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. /*
  8.  *
  9.  * Drawing routines
  10.  *
  11.  */
  12.  
  13.  
  14. #include "dxxerror.h"
  15.  
  16. #include "3d.h"
  17. #include "globvars.h"
  18. #include "texmap.h"
  19. #include "clipper.h"
  20. #if !DXX_USE_OGL
  21. #include "gr.h"
  22. #endif
  23.  
  24. namespace dcx {
  25.  
  26. tmap_drawer_type tmap_drawer_ptr = draw_tmap;
  27.  
  28. //specifies 2d drawing routines to use instead of defaults.  Passing
  29. //NULL for either or both restores defaults
  30. void g3_set_special_render(tmap_drawer_type tmap_drawer)
  31. {
  32.         tmap_drawer_ptr = tmap_drawer;
  33. }
  34. #if !DXX_USE_OGL
  35. //deal with a clipped line
  36. static void must_clip_line(grs_canvas &canvas, g3s_point *p0, g3s_point *p1, const uint8_t codes_or, const uint8_t color, temporary_points_t &tp)
  37. {
  38.         if ((p0->p3_flags&PF_TEMP_POINT) || (p1->p3_flags&PF_TEMP_POINT))
  39.                 ;               //line has already been clipped, so give up
  40.         else {
  41.                 clip_line(p0,p1,codes_or,tp);
  42.                 g3_draw_line(canvas, *p0, *p1, color, tp);
  43.         }
  44.  
  45.         //free temp points
  46.  
  47.         if (p0->p3_flags & PF_TEMP_POINT)
  48.                 tp.free_temp_point(p0);
  49.  
  50.         if (p1->p3_flags & PF_TEMP_POINT)
  51.                 tp.free_temp_point(p1);
  52. }
  53.  
  54. //draws a line. takes two points.  returns true if drew
  55. void g3_draw_line(grs_canvas &canvas, g3s_point &p0, g3s_point &p1, const uint8_t color)
  56. {
  57.         temporary_points_t tp;
  58.         g3_draw_line(canvas, p0, p1, color, tp);
  59. }
  60.  
  61. void g3_draw_line(grs_canvas &canvas, g3s_point &p0, g3s_point &p1, const uint8_t color, temporary_points_t &tp)
  62. {
  63.         ubyte codes_or;
  64.  
  65.         if (p0.p3_codes & p1.p3_codes)
  66.                 return;
  67.  
  68.         codes_or = p0.p3_codes | p1.p3_codes;
  69.  
  70.         if (
  71.                 (codes_or & CC_BEHIND) ||
  72.                 (static_cast<void>((p0.p3_flags & PF_PROJECTED) || (g3_project_point(p0), 0)), p0.p3_flags & PF_OVERFLOW) ||
  73.                 (static_cast<void>((p1.p3_flags & PF_PROJECTED) || (g3_project_point(p1), 0)), p1.p3_flags & PF_OVERFLOW)
  74.         )
  75.                 return must_clip_line(canvas, &p0,&p1, codes_or, color, tp);
  76.         gr_line(canvas, p0.p3_sx, p0.p3_sy, p1.p3_sx, p1.p3_sy, color);
  77. }
  78. #endif
  79.  
  80. //returns true if a plane is facing the viewer. takes the unrotated surface
  81. //normal of the plane, and a point on it.  The normal need not be normalized
  82. bool g3_check_normal_facing(const vms_vector &v,const vms_vector &norm)
  83. {
  84.         return (vm_vec_dot(vm_vec_sub(View_position,v),norm) > 0);
  85. }
  86.  
  87. bool do_facing_check(const std::array<cg3s_point *, 3> &vertlist)
  88. {
  89.         //normal not specified, so must compute
  90.                 //get three points (rotated) and compute normal
  91.                 const auto tempv = vm_vec_perp(vertlist[0]->p3_vec,vertlist[1]->p3_vec,vertlist[2]->p3_vec);
  92.                 return (vm_vec_dot(tempv,vertlist[1]->p3_vec) < 0);
  93. }
  94.  
  95. #if !DXX_USE_OGL
  96. //deal with face that must be clipped
  97. static void must_clip_flat_face(grs_canvas &canvas, int nv, g3s_codes cc, polygon_clip_points &Vbuf0, polygon_clip_points &Vbuf1, const uint8_t color)
  98. {
  99.         temporary_points_t tp;
  100.         auto &bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tp);
  101.  
  102.         if (nv>0 && !(cc.uor&CC_BEHIND) && !cc.uand) {
  103.                 std::array<fix, MAX_POINTS_IN_POLY*2> Vertex_list;
  104.                 for (int i=0;i<nv;i++) {
  105.                         g3s_point *p = bufptr[i];
  106.        
  107.                         if (!(p->p3_flags&PF_PROJECTED))
  108.                                 g3_project_point(*p);
  109.        
  110.                         if (p->p3_flags&PF_OVERFLOW) {
  111.                                 goto free_points;
  112.                         }
  113.  
  114.                         Vertex_list[i*2]   = p->p3_sx;
  115.                         Vertex_list[i*2+1] = p->p3_sy;
  116.                 }
  117.                 gr_upoly_tmap(canvas, nv, Vertex_list, color);
  118.         }
  119.         //free temp points
  120. free_points:
  121.         ;
  122. }
  123.  
  124. //draw a flat-shaded face.
  125. //returns 1 if off screen, 0 if drew
  126. void _g3_draw_poly(grs_canvas &canvas, const uint_fast32_t nv, cg3s_point *const *const pointlist, const uint8_t color)
  127. {
  128.         g3s_codes cc;
  129.  
  130.         polygon_clip_points Vbuf0, Vbuf1;
  131.         auto bufptr = &Vbuf0[0];
  132.  
  133.         for (int i=0;i<nv;i++) {
  134.  
  135.                 bufptr[i] = pointlist[i];
  136.  
  137.                 cc.uand &= bufptr[i]->p3_codes;
  138.                 cc.uor  |= bufptr[i]->p3_codes;
  139.         }
  140.  
  141.         if (cc.uand)
  142.                 return; //all points off screen
  143.  
  144.         if (cc.uor)
  145.         {
  146.                 must_clip_flat_face(canvas, nv, cc, Vbuf0, Vbuf1, color);
  147.                 return;
  148.         }
  149.  
  150.         //now make list of 2d coords (& check for overflow)
  151.         std::array<fix, MAX_POINTS_IN_POLY*2> Vertex_list;
  152.         for (int i=0;i<nv;i++) {
  153.                 g3s_point *p = bufptr[i];
  154.  
  155.                 if (!(p->p3_flags&PF_PROJECTED))
  156.                         g3_project_point(*p);
  157.  
  158.                 if (p->p3_flags&PF_OVERFLOW)
  159.                 {
  160.                         must_clip_flat_face(canvas, nv, cc, Vbuf0, Vbuf1, color);
  161.                         return;
  162.                 }
  163.  
  164.                 Vertex_list[i*2]   = p->p3_sx;
  165.                 Vertex_list[i*2+1] = p->p3_sy;
  166.         }
  167.         gr_upoly_tmap(canvas, nv, Vertex_list, color);
  168.         //say it drew
  169. }
  170.  
  171. static void must_clip_tmap_face(grs_canvas &, int nv, g3s_codes cc, grs_bitmap &bm, polygon_clip_points &Vbuf0, polygon_clip_points &Vbuf1);
  172.  
  173. //draw a texture-mapped face.
  174. //returns 1 if off screen, 0 if drew
  175. void _g3_draw_tmap(grs_canvas &canvas, const unsigned nv, cg3s_point *const *const pointlist, const g3s_uvl *const uvl_list, const g3s_lrgb *const light_rgb, grs_bitmap &bm)
  176. {
  177.         g3s_codes cc;
  178.  
  179.         polygon_clip_points Vbuf0, Vbuf1;
  180.         auto bufptr = &Vbuf0[0];
  181.  
  182.         for (int i=0;i<nv;i++) {
  183.                 g3s_point *p;
  184.  
  185.                 p = bufptr[i] = pointlist[i];
  186.  
  187.                 cc.uand &= p->p3_codes;
  188.                 cc.uor  |= p->p3_codes;
  189.  
  190. #if !DXX_USE_OGL
  191.                 p->p3_u = uvl_list[i].u;
  192.                 p->p3_v = uvl_list[i].v;
  193.                 p->p3_l = (light_rgb[i].r+light_rgb[i].g+light_rgb[i].b)/3;
  194. #endif
  195.  
  196.                 p->p3_flags |= PF_UVS + PF_LS;
  197.  
  198.         }
  199.  
  200.         if (cc.uand)
  201.                 return; //all points off screen
  202.  
  203.         if (cc.uor)
  204.         {
  205.                 must_clip_tmap_face(canvas, nv, cc, bm, Vbuf0, Vbuf1);
  206.                 return;
  207.         }
  208.  
  209.         //now make list of 2d coords (& check for overflow)
  210.  
  211.         for (int i=0;i<nv;i++) {
  212.                 g3s_point *p = bufptr[i];
  213.  
  214.                 if (!(p->p3_flags&PF_PROJECTED))
  215.                         g3_project_point(*p);
  216.  
  217.                 if (p->p3_flags&PF_OVERFLOW) {
  218.                         Int3();         //should not overflow after clip
  219.                         return;
  220.                 }
  221.         }
  222.  
  223.         (*tmap_drawer_ptr)(canvas, bm, nv, bufptr);
  224. }
  225.  
  226. static void must_clip_tmap_face(grs_canvas &canvas, int nv, g3s_codes cc, grs_bitmap &bm, polygon_clip_points &Vbuf0, polygon_clip_points &Vbuf1)
  227. {
  228.         temporary_points_t tp;
  229.         auto &bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tp);
  230.         if (nv && !(cc.uor&CC_BEHIND) && !cc.uand) {
  231.  
  232.                 for (int i=0;i<nv;i++) {
  233.                         g3s_point *p = bufptr[i];
  234.  
  235.                         if (!(p->p3_flags&PF_PROJECTED))
  236.                                 g3_project_point(*p);
  237.        
  238.                         if (p->p3_flags&PF_OVERFLOW) {
  239.                                 Int3();         //should not overflow after clip
  240.                                 goto free_points;
  241.                         }
  242.                 }
  243.  
  244.                 (*tmap_drawer_ptr)(canvas, bm, nv, &bufptr[0]);
  245.         }
  246.  
  247. free_points:
  248.         ;
  249.  
  250. //      Assert(free_point_num==0);
  251. }
  252.  
  253. //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
  254. //radius, but not to the distance from the eye
  255. void g3_draw_sphere(grs_canvas &canvas, cg3s_point &pnt, const fix rad, const uint8_t color)
  256. {
  257.         if (! (pnt.p3_codes & CC_BEHIND)) {
  258.  
  259.                 if (! (pnt.p3_flags & PF_PROJECTED))
  260.                         g3_project_point(pnt);
  261.  
  262.                 if (! (pnt.p3_codes & PF_OVERFLOW)) {
  263.                         const auto r2 = fixmul(rad, Matrix_scale.x);
  264. #ifndef __powerc
  265.                         fix t;
  266.                         if (!checkmuldiv(&t, r2, Canv_w2, pnt.p3_z))
  267.                                 return;
  268. #else
  269.                         if (pnt.p3_z == 0)
  270.                                 return;
  271.                         const fix t = fl2f(((f2fl(r2) * fCanv_w2) / f2fl(pnt.p3_z)));
  272. #endif
  273.                         gr_disk(canvas, pnt.p3_sx, pnt.p3_sy, t, color);
  274.                 }
  275.         }
  276. }
  277. #endif
  278.  
  279. }
  280.