home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / shareware / crystalppc / polytext.cpp < prev    next >
C/C++ Source or Header  |  1998-06-08  |  13KB  |  525 lines

  1. #include <math.h>
  2. #include <time.h>
  3. #include "system.h"
  4.  
  5. #ifndef DEF_H
  6. #include "def.h"
  7. #endif
  8.  
  9. #ifndef POLYTEXT_H
  10. #include "polytext.h"
  11. #endif
  12.  
  13. #ifndef POLYPLANE_H
  14. #include "polyplan.h"
  15. #endif
  16.  
  17. #ifndef TEXTURE_H
  18. #include "texture.h"
  19. #endif
  20.  
  21. #ifndef POLYGON_H
  22. #include "polygon.h"
  23. #endif
  24.  
  25. #ifndef LIGHT_H
  26. #include "light.h"
  27. #endif
  28.  
  29. #ifndef SECTOR_H
  30. #include "sector.h"
  31. #endif
  32.  
  33. #ifndef LIGHTMAP_H
  34. #include "lightmap.h"
  35. #endif
  36.  
  37. extern TextureCache cache;
  38.  
  39. //---------------------------------------------------------------------------
  40.  
  41. PolyTexture::PolyTexture ()
  42. {
  43.   next = prev = NULL;
  44.   in_cache = FALSE;
  45.   tmap = NULL;
  46.  
  47.   light_u = -1;
  48.   light_v = -1;
  49.   sq_rad = 0;
  50. }
  51.  
  52. PolyTexture::~PolyTexture ()
  53. {
  54.   if (tmap) delete [] tmap;
  55. }
  56.  
  57. void PolyTexture::set_texnr (Textures* textures, int texnr)
  58. {
  59.   PolyTexture::texnr = texnr;
  60.   texture = textures->get_texture (texnr);
  61. }
  62.  
  63. void PolyTexture::create_bounding_texture_box ()
  64. {
  65.  
  66.   // First we compute the bounding box in 2D texture space (uv-space).
  67.   float min_u = 1000000000.;
  68.   float min_v = 1000000000.;
  69.   float max_u = -1000000000.;
  70.   float max_v = -1000000000.;
  71.  
  72.   PolyPlane* pl = polygon->get_plane ();
  73.  
  74.   int i;
  75.   Vector3 v1, v2;
  76.   for (i = 0 ; i < polygon->get_num_vertices () ; i++)
  77.   {
  78.     v1 = polygon->vtex (i).get_v ();     // Coordinates of vertex in world space.
  79.     v1 -= pl->v_world2tex;
  80.     pl->m_world2tex.transform (v1, v2);    // Coordinates of vertex in texture space.
  81.     if (v2.x < min_u) min_u = v2.x;
  82.     if (v2.x > max_u) max_u = v2.x;
  83.     if (v2.y < min_v) min_v = v2.y;
  84.     if (v2.y > max_v) max_v = v2.y;
  85.   }
  86.  
  87.   int ww = texture->get_width ();
  88.   int hh = texture->get_height ();
  89.   Imin_u = QRound (min_u*ww);
  90.   Imin_v = QRound (min_v*hh);
  91.   Imax_u = QRound (max_u*ww);
  92.   Imax_v = QRound (max_v*hh);
  93.  
  94.   h = Imax_v-Imin_v;
  95.   int w2 = Imax_u-Imin_u;
  96.   w = 1;
  97.   shf_u = 0;
  98.   and_u = 0;
  99.   while (TRUE)
  100.   {
  101.     if (w2 <= w) break;
  102.     w <<= 1;
  103.     shf_u++;
  104.     and_u = (and_u<<1)+1;
  105.   }
  106.  
  107.   fdu = min_u*ww;
  108.   fdv = min_v*hh;
  109.   du = QInt16 (min_u*ww);
  110.   dv = QInt16 (min_v*hh);
  111.  
  112.   size = w*h;
  113. }
  114.  
  115. void PolyTexture::create_lighted_texture (Textures* textures)
  116. {
  117.   if (tmap)
  118.   {
  119.     delete [] tmap;
  120.     tmap = NULL;
  121.   }
  122.  
  123.   if (!lm) return;
  124.  
  125.   unsigned char* light_map = lm->get_light_map ();
  126.   unsigned char* red_light_map = lm->get_red_light_map ();
  127.   unsigned char* blue_light_map = lm->get_blue_light_map ();
  128.  
  129.   unsigned char* otmap = texture->get_bitmap ();
  130.  
  131.   int shf_w = texture->get_w_shift ();
  132.   int and_w = texture->get_w_mask ();
  133.   int and_h = texture->get_h_mask ();
  134.   and_h <<= shf_w;
  135.  
  136.   tmap = new unsigned char [size];
  137.   unsigned char* tm = tmap;
  138.   int u, v, old_w;
  139.   old_w = Imax_u-Imin_u;
  140.   unsigned char* light, * red_light, * blue_light;
  141.   int lu, lv, lw, lh;
  142.   lw = w/mipmap_size+2;
  143.   lh = h/mipmap_size+2;
  144.   int luv, du, dv;
  145.  
  146.   int whi_00, red_00, blu_00;
  147.   int whi_10, red_10, blu_10;
  148.   int whi_01, red_01, blu_01;
  149.   int whi_11, red_11, blu_11;
  150.   int whi_0, whi_1, whi_d, whi_0d, whi_1d;
  151.   int red_0, red_1, red_d, red_0d, red_1d;
  152.   int blu_0, blu_1, blu_d, blu_0d, blu_1d;
  153.   int whi, red, blu;
  154.   int o_idx, ov_idx;
  155.  
  156.   luv = 0;
  157.   for (lv = 0 ; lv < lh ; lv++)
  158.   {
  159.     for (lu = 0 ; lu < lw ; lu++)
  160.     {
  161.       whi_00 = light_map[luv];
  162.       whi_10 = light_map[luv+1];
  163.       whi_01 = light_map[luv+lw];
  164.       whi_11 = light_map[luv+lw+1];
  165.       red_00 = red_light_map[luv];
  166.       red_10 = red_light_map[luv+1];
  167.       red_01 = red_light_map[luv+lw];
  168.       red_11 = red_light_map[luv+lw+1];
  169.       blu_00 = blue_light_map[luv];
  170.       blu_10 = blue_light_map[luv+1];
  171.       blu_01 = blue_light_map[luv+lw];
  172.       blu_11 = blue_light_map[luv+lw+1];
  173.  
  174.       u = lu*mipmap_size;
  175.       v = lv*mipmap_size;
  176.       tm = &tmap[w*v+u];
  177.  
  178.       if (blu_00 == 0 && blu_10 == 0 && blu_01 == 0 && blu_11 == 0)
  179.       {
  180.     // No blue lighting
  181.  
  182.     if (red_00 == 0 && red_10 == 0 && red_01 == 0 && red_11 == 0)
  183.     {
  184.       // No colored lighting
  185.  
  186.       if (whi_00 == whi_10 && whi_00 == whi_01 && whi_00 == whi_11)
  187.       {
  188.         //*****
  189.         // Constant level of white light and no colored light.
  190.         //*****
  191.  
  192.         light = textures->get_light_table (whi_00);
  193.  
  194.         for (dv = 0 ; dv < mipmap_size ; dv++, tm += w-mipmap_size)
  195.           if (v+dv < h)
  196.           {
  197.         ov_idx = ((v+dv+Imin_v)<<shf_w) & and_h;
  198.  
  199.         for (du = 0 ; du < mipmap_size ; du++)
  200.           if (u+du < w)
  201.           {
  202.             o_idx = ov_idx + ((u+du+Imin_u) & and_w);
  203.             *tm++ = light[otmap[o_idx]];
  204.           }
  205.           else { tm += mipmap_size-du; break; }
  206.           }
  207.           else break;
  208.       }
  209.       else
  210.       {
  211.         //*****
  212.         // No colored light and a varying level of white light.
  213.         //*****
  214.  
  215.         whi_0 = whi_00 << 16; whi_0d = ((whi_01-whi_00)<<16) / mipmap_size;
  216.         whi_1 = whi_10 << 16; whi_1d = ((whi_11-whi_10)<<16) / mipmap_size;
  217.  
  218.         for (dv = 0 ; dv < mipmap_size ; dv++, tm += w-mipmap_size)
  219.           if (v+dv < h)
  220.           {
  221.         ov_idx = ((v+dv+Imin_v)<<shf_w) & and_h;
  222.         whi = whi_0; whi_d = (whi_1-whi_0)/mipmap_size;
  223.  
  224.         for (du = 0 ; du < mipmap_size ; du++)
  225.           if (u+du < w)
  226.           {
  227.             light = textures->get_light_table (whi >> 16);
  228.             o_idx = ov_idx + ((u+du+Imin_u) & and_w);
  229.             *tm++ = light[otmap[o_idx]];
  230.             whi += whi_d;
  231.           }
  232.           else { tm += mipmap_size-du; break; }
  233.  
  234.         whi_0 += whi_0d;
  235.         whi_1 += whi_1d;
  236.           }
  237.           else break;
  238.       }
  239.     }
  240.     else
  241.     {
  242.       //*****
  243.       // No blue lighting but with red lighting
  244.       //*****
  245.  
  246.       whi_0 = whi_00 << 16; whi_0d = ((whi_01-whi_00)<<16) / mipmap_size;
  247.       whi_1 = whi_10 << 16; whi_1d = ((whi_11-whi_10)<<16) / mipmap_size;
  248.       red_0 = red_00 << 16; red_0d = ((red_01-red_00)<<16) / mipmap_size;
  249.       red_1 = red_10 << 16; red_1d = ((red_11-red_10)<<16) / mipmap_size;
  250.  
  251.       for (dv = 0 ; dv < mipmap_size ; dv++, tm += w-mipmap_size)
  252.         if (v+dv < h)
  253.         {
  254.           ov_idx = ((v+dv+Imin_v)<<shf_w) & and_h;
  255.  
  256.           whi = whi_0; whi_d = (whi_1-whi_0)/mipmap_size;
  257.           red = red_0; red_d = (red_1-red_0)/mipmap_size;
  258.  
  259.           for (du = 0 ; du < mipmap_size ; du++)
  260.         if (u+du < w)
  261.         {
  262.           light = textures->get_light_table (whi >> 16);
  263.           red_light = textures->get_red_light_table (red >> 16);
  264.  
  265.           o_idx = ov_idx + ((u+du+Imin_u) & and_w);
  266.           *tm++ = red_light[light[otmap[o_idx]]];
  267.  
  268.           whi += whi_d;
  269.           red += red_d;
  270.         }
  271.         else { tm += mipmap_size-du; break; }
  272.  
  273.           whi_0 += whi_0d;
  274.           whi_1 += whi_1d;
  275.           red_0 += red_0d;
  276.           red_1 += red_1d;
  277.         }
  278.         else break;
  279.     }
  280.  
  281. //u = lu*mipmap_size; v = lv*mipmap_size;
  282. //if (u < w && v < h) { tm = &tmap[w*v+u]; *tm = textures->get_light_table (255)[*tm]; }
  283.  
  284.     luv++;
  285.     continue;
  286.       }
  287.       else if (red_00 == 0 && red_10 == 0 && red_01 == 0 && red_11 == 0)
  288.       {
  289.     //*****
  290.     // No red lighting but with blue lighting
  291.     //*****
  292.  
  293.     whi_0 = whi_00 << 16; whi_0d = ((whi_01-whi_00)<<16) / mipmap_size;
  294.     whi_1 = whi_10 << 16; whi_1d = ((whi_11-whi_10)<<16) / mipmap_size;
  295.     blu_0 = blu_00 << 16; blu_0d = ((blu_01-blu_00)<<16) / mipmap_size;
  296.     blu_1 = blu_10 << 16; blu_1d = ((blu_11-blu_10)<<16) / mipmap_size;
  297.  
  298.     for (dv = 0 ; dv < mipmap_size ; dv++, tm += w-mipmap_size)
  299.       if (v+dv < h)
  300.       {
  301.         ov_idx = ((v+dv+Imin_v)<<shf_w) & and_h;
  302.  
  303.         whi = whi_0; whi_d = (whi_1-whi_0)/mipmap_size;
  304.         blu = blu_0; blu_d = (blu_1-blu_0)/mipmap_size;
  305.  
  306.         for (du = 0 ; du < mipmap_size ; du++)
  307.           if (u+du < w)
  308.           {
  309.         light = textures->get_light_table (whi >> 16);
  310.         blue_light = textures->get_blue_light_table (blu >> 16);
  311.  
  312.         o_idx = ov_idx + ((u+du+Imin_u) & and_w);
  313.         *tm++ = blue_light[light[otmap[o_idx]]];
  314.  
  315.         whi += whi_d;
  316.         blu += blu_d;
  317.           }
  318.           else { tm += mipmap_size-du; break; }
  319.  
  320.         whi_0 += whi_0d;
  321.         whi_1 += whi_1d;
  322.         blu_0 += blu_0d;
  323.         blu_1 += blu_1d;
  324.       }
  325.       else break;
  326.  
  327. //u = lu*mipmap_size; v = lv*mipmap_size;
  328. //if (u < w && v < h) { tm = &tmap[w*v+u]; *tm = textures->get_light_table (255)[*tm]; }
  329.  
  330.     luv++;
  331.     continue;
  332.       }
  333.  
  334.       //*****
  335.       // Most general case: varying levels of white, red, and blue light.
  336.       //*****
  337.  
  338.       whi_0 = whi_00 << 16; whi_0d = ((whi_01-whi_00)<<16) / mipmap_size;
  339.       whi_1 = whi_10 << 16; whi_1d = ((whi_11-whi_10)<<16) / mipmap_size;
  340.       red_0 = red_00 << 16; red_0d = ((red_01-red_00)<<16) / mipmap_size;
  341.       red_1 = red_10 << 16; red_1d = ((red_11-red_10)<<16) / mipmap_size;
  342.       blu_0 = blu_00 << 16; blu_0d = ((blu_01-blu_00)<<16) / mipmap_size;
  343.       blu_1 = blu_10 << 16; blu_1d = ((blu_11-blu_10)<<16) / mipmap_size;
  344.  
  345.       for (dv = 0 ; dv < mipmap_size ; dv++, tm += w-mipmap_size)
  346.     if (v+dv < h)
  347.         {
  348.       ov_idx = ((v+dv+Imin_v)<<shf_w) & and_h;
  349.  
  350.       whi = whi_0; whi_d = (whi_1-whi_0)/mipmap_size;
  351.       red = red_0; red_d = (red_1-red_0)/mipmap_size;
  352.       blu = blu_0; blu_d = (blu_1-blu_0)/mipmap_size;
  353.  
  354.       for (du = 0 ; du < mipmap_size ; du++)
  355.         if (u+du < w)
  356.         {
  357.           light = textures->get_light_table (whi >> 16);
  358.           red_light = textures->get_red_light_table (red >> 16);
  359.           blue_light = textures->get_blue_light_table (blu >> 16);
  360.  
  361.           o_idx = ov_idx + ((u+du+Imin_u) & and_w);
  362.           *tm++ = blue_light[red_light[light[otmap[o_idx]]]];
  363.  
  364.           whi += whi_d;
  365.           red += red_d;
  366.           blu += blu_d;
  367.         }
  368.         else { tm += mipmap_size-du; break; }
  369.  
  370.       whi_0 += whi_0d;
  371.       whi_1 += whi_1d;
  372.       red_0 += red_0d;
  373.       red_1 += red_1d;
  374.       blu_0 += blu_0d;
  375.       blu_1 += blu_1d;
  376.     }
  377.     else break;
  378.  
  379. //u = lu*mipmap_size; v = lv*mipmap_size;
  380. //if (u < w && v < h) { tm = &tmap[w*v+u]; *tm = textures->get_light_table (255)[*tm]; }
  381.  
  382.       luv++;
  383.     }
  384.   }
  385. }
  386.  
  387. void PolyTexture::shine (Light* light)
  388. {
  389.   if (!lm) return;
  390.  
  391.   int lw = w/mipmap_size+2;
  392.   int lh = h/mipmap_size+2;
  393.  
  394.   unsigned char* light_map = lm->get_light_map ();
  395.   unsigned char* red_light_map = lm->get_red_light_map ();
  396.   unsigned char* blue_light_map = lm->get_blue_light_map ();
  397.  
  398.   int u, v, uv;
  399.   float cx, cy, cz;
  400.   int l, red_l, blue_l;
  401.   float x, y, z, d, dl;
  402.  
  403.   int ww = texture->get_width ();
  404.   int hh = texture->get_height ();
  405.  
  406.   PolyPlane* pl = polygon->get_plane ();
  407.  
  408.   // From: T = Mwt * (W - Vwt)
  409.   // ===>
  410.   // Mtw * T = W - Vwt
  411.   // Mtw * T + Vwt = W
  412.   Matrix3 m_t2w = pl->m_world2tex;
  413.   m_t2w.inverse ();
  414.   Vector3 vv = pl->v_world2tex;
  415.  
  416.   Vector3 v1, v2;
  417.  
  418.   int ru, rv;
  419.  
  420.   for (v = 0 ; v < lh ; v++)
  421.     for (u = 0 ; u < lw ; u++)
  422.     {
  423.       uv = v*lw+u;
  424.  
  425.       ru = u*mipmap_size;
  426.       rv = v*mipmap_size;
  427.       if (ru > w || rv > h)
  428.       {
  429.         // Special case. The beam hit some part that is
  430.     // in fact not on the polygon. In that case there
  431.     // is the posibility that our hit_beam will not work
  432.     // correctly. Therefore we currently solve this problem
  433.     // by just taking the light values of the closest hit
  434.     // on the polygon. This is not an ideal solution but
  435.     // it is the first thing I came up with.@@@
  436.     if (ru > w)
  437.     {
  438.       light_map[uv] = light_map[uv-1];
  439.       red_light_map[uv] = red_light_map[uv-1];
  440.       blue_light_map[uv] = blue_light_map[uv-1];
  441.     }
  442.     else if (rv > h)
  443.     {
  444.       light_map[uv] = light_map[uv-lw];
  445.       red_light_map[uv] = red_light_map[uv-lw];
  446.       blue_light_map[uv] = blue_light_map[uv-lw];
  447.     }
  448.     continue;
  449.       }
  450.  
  451.       v1.x = (float)(ru+Imin_u)/(float)ww;
  452.       v1.y = (float)(rv+Imin_v)/(float)hh;
  453.       v1.z = 0;
  454.       m_t2w.transform (v1, v2);
  455.       v2 += vv;
  456.       x = v2.x;
  457.       y = v2.y;
  458.       z = v2.z;
  459.  
  460.       // @@@ Due to floating point rounding errors it is possible
  461.       // that the resulting vector 'v2' will not lie on the polygon.
  462.       // This can happen when either 'ru' or 'rv' is 0 (this is at
  463.       // one of the top or left borders of the uv bounding box).
  464.       // In this case our hit routine will most likely not reach the polygon
  465.       // and the point will be unlit (shadowed).
  466.       // I don't currently have a good solution for this problem but I
  467.       // do solve most occurences of it by modifying 'hit_beam' so that
  468.       // it considers hits with a polygon on the same plane as good hits.
  469.       // This only solves the problem in some cases.
  470.       
  471.       l = light_map[uv];
  472.       red_l = red_light_map[uv];
  473.       blue_l = blue_light_map[uv];
  474.  
  475.       cx = light->get_center ().x;
  476.       cy = light->get_center ().y;
  477.       cz = light->get_center ().z;
  478.       d = sqrt ((cx-x)*(cx-x)+(cy-y)*(cy-y)+(cz-z)*(cz-z));
  479.       if (d < light->get_dist ())
  480.       {
  481.     if (!light->hit_beam (light->get_center (), v2, polygon)) continue;
  482.  
  483.     dl = (light->get_strength ()*200)/light->get_dist ();
  484.     l = l + QRound (light->get_strength ()*200 - d*dl);
  485.     if (light->get_red_strength () > 0)
  486.     {
  487.       dl = (light->get_red_strength ()*200)/light->get_dist ();
  488.       red_l = red_l + QRound (light->get_red_strength ()*200 - d*dl);
  489.     }
  490.     if (light->get_blue_strength () > 0)
  491.     {
  492.       dl = (light->get_blue_strength ()*200)/light->get_dist ();
  493.       blue_l = blue_l + QRound (light->get_blue_strength ()*200 - d*dl);
  494.     }
  495.  
  496.     if (l > 255) l = 255;
  497.     light_map[uv] = l;
  498.     if (red_l > 255) red_l = 255;
  499.     red_light_map[uv] = red_l;
  500.     if (blue_l > 255) blue_l = 255;
  501.     blue_light_map[uv] = blue_l;
  502.       }
  503.     }
  504. }
  505.  
  506. void PolyTexture::setup_dyn_light (DynLight* light, float sq_dist)
  507. {
  508.   Vector3 isect, luv;
  509.   polygon->closest_point (light->get_center (), isect);
  510.   PolyPlane* pl = polygon->get_plane ();
  511.  
  512.   // From: T = Mwt * (W - Vwt)
  513.   isect -= pl->v_world2tex;
  514.   pl->m_world2tex.transform (isect, luv);
  515.  
  516.   int ww = texture->get_width ();
  517.   int hh = texture->get_height ();
  518.  
  519.   light_u = QRound (luv.x*ww);
  520.   light_v = QRound (luv.y*hh);
  521.   sq_rad = QRound (light->get_sq_dist () - sq_dist) * ww * ww;
  522. }
  523.  
  524. //---------------------------------------------------------------------------
  525.