Subversion Repositories Games.Descent

Rev

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

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Texture map assignment.
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <stdarg.h>
  29. #include <math.h>
  30. #include <string.h>
  31. #include "inferno.h"
  32. #include "segment.h"
  33. #include "seguvs.h"
  34. #include "editor.h"
  35. #include "editor/esegment.h"
  36. #include "maths.h"
  37. #include "dxxerror.h"
  38. #include "kdefs.h"
  39.  
  40. #include "compiler-range_for.h"
  41.  
  42. static uvl compute_uv_side_center(const unique_segment &segp, sidenum_fast_t sidenum);
  43. static void rotate_uv_points_on_side(unique_segment &segp, sidenum_fast_t sidenum, const std::array<fix, 4> &rotmat, const uvl &uvcenter);
  44.  
  45. //      -----------------------------------------------------------
  46. int     TexFlipX()
  47. {
  48.         const auto uvcenter = compute_uv_side_center(Cursegp, Curside);
  49.         std::array<fix, 4> rotmat;
  50.         //      Create a rotation matrix
  51.         rotmat[0] = -0xffff;
  52.         rotmat[1] = 0;
  53.         rotmat[2] = 0;
  54.         rotmat[3] = 0xffff;
  55.  
  56.         rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter);
  57.  
  58.         Update_flags |= UF_WORLD_CHANGED;
  59.  
  60.         return  1;
  61. }
  62.  
  63. //      -----------------------------------------------------------
  64. int     TexFlipY()
  65. {
  66.         const auto uvcenter = compute_uv_side_center(Cursegp, Curside);
  67.         std::array<fix, 4> rotmat;
  68.         //      Create a rotation matrix
  69.         rotmat[0] = 0xffff;
  70.         rotmat[1] = 0;
  71.         rotmat[2] = 0;
  72.         rotmat[3] = -0xffff;
  73.  
  74.         rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter);
  75.  
  76.         Update_flags |= UF_WORLD_CHANGED;
  77.  
  78.         return  1;
  79. }
  80.  
  81. //      -----------------------------------------------------------
  82. static int DoTexSlideLeft(int value)
  83. {
  84.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  85.         auto &Vertices = LevelSharedVertexState.get_vertices();
  86.         uvl     duvl03;
  87.         fix     dist;
  88.         auto &vp = Side_to_verts[Curside];
  89.         auto &uvls = Cursegp->unique_segment::sides[Curside].uvls;
  90.  
  91.         auto &vcvertptr = Vertices.vcptr;
  92.         dist = vm_vec_dist(vcvertptr(Cursegp->verts[vp[3]]), vcvertptr(Cursegp->verts[vp[0]]));
  93.         dist *= value;
  94.         if (dist < F1_0/(64*value))
  95.                 dist = F1_0/(64*value);
  96.  
  97.         duvl03.u = fixdiv(uvls[3].u - uvls[0].u,dist);
  98.         duvl03.v = fixdiv(uvls[3].v - uvls[0].v,dist);
  99.  
  100.         range_for (auto &v, uvls)
  101.         {
  102.                 v.u -= duvl03.u;
  103.                 v.v -= duvl03.v;
  104.         }
  105.  
  106.         Update_flags |= UF_WORLD_CHANGED;
  107.  
  108.         return  1;
  109. }
  110.  
  111. int TexSlideLeft()
  112. {
  113.         return DoTexSlideLeft(3);
  114. }
  115.  
  116. int TexSlideLeftBig()
  117. {
  118.         return DoTexSlideLeft(1);
  119. }
  120.  
  121. //      -----------------------------------------------------------
  122. static int DoTexSlideUp(int value)
  123. {
  124.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  125.         auto &Vertices = LevelSharedVertexState.get_vertices();
  126.         uvl     duvl03;
  127.         fix     dist;
  128.         auto &vp = Side_to_verts[Curside];
  129.         auto &uvls = Cursegp->unique_segment::sides[Curside].uvls;
  130.  
  131.         auto &vcvertptr = Vertices.vcptr;
  132.         dist = vm_vec_dist(vcvertptr(Cursegp->verts[vp[1]]), vcvertptr(Cursegp->verts[vp[0]]));
  133.         dist *= value;
  134.  
  135.         if (dist < F1_0/(64*value))
  136.                 dist = F1_0/(64*value);
  137.  
  138.         duvl03.u = fixdiv(uvls[1].u - uvls[0].u,dist);
  139.         duvl03.v = fixdiv(uvls[1].v - uvls[0].v,dist);
  140.  
  141.         range_for (auto &v, uvls)
  142.         {
  143.                 v.u -= duvl03.u;
  144.                 v.v -= duvl03.v;
  145.         }
  146.  
  147.         Update_flags |= UF_WORLD_CHANGED;
  148.  
  149.         return  1;
  150. }
  151.  
  152. int TexSlideUp()
  153. {
  154.         return DoTexSlideUp(3);
  155. }
  156.  
  157. int TexSlideUpBig()
  158. {
  159.         return DoTexSlideUp(1);
  160. }
  161.  
  162.  
  163. //      -----------------------------------------------------------
  164. static int DoTexSlideDown(int value)
  165. {
  166.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  167.         auto &Vertices = LevelSharedVertexState.get_vertices();
  168.         uvl     duvl03;
  169.         fix     dist;
  170.         auto &vp = Side_to_verts[Curside];
  171.         auto &uvls = Cursegp->unique_segment::sides[Curside].uvls;
  172.  
  173.         auto &vcvertptr = Vertices.vcptr;
  174.         dist = vm_vec_dist(vcvertptr(Cursegp->verts[vp[1]]), vcvertptr(Cursegp->verts[vp[0]]));
  175.         dist *= value;
  176.         if (dist < F1_0/(64*value))
  177.                 dist = F1_0/(64*value);
  178.  
  179.         duvl03.u = fixdiv(uvls[1].u - uvls[0].u,dist);
  180.         duvl03.v = fixdiv(uvls[1].v - uvls[0].v,dist);
  181.  
  182.         range_for (auto &v, uvls)
  183.         {
  184.                 v.u += duvl03.u;
  185.                 v.v += duvl03.v;
  186.         }
  187.  
  188.         Update_flags |= UF_WORLD_CHANGED;
  189.  
  190.         return  1;
  191. }
  192.  
  193. int TexSlideDown()
  194. {
  195.         return DoTexSlideDown(3);
  196. }
  197.  
  198. int TexSlideDownBig()
  199. {
  200.         return DoTexSlideDown(1);
  201. }
  202.  
  203. //      -----------------------------------------------------------
  204. //      Compute the center of the side in u,v coordinates.
  205. static uvl compute_uv_side_center(const unique_segment &segp, const sidenum_fast_t sidenum)
  206. {
  207.         uvl uvcenter{};
  208.         range_for (auto &v, segp.sides[sidenum].uvls)
  209.         {
  210.                 uvcenter.u += v.u;
  211.                 uvcenter.v += v.v;
  212.         }
  213.         uvcenter.u /= 4;
  214.         uvcenter.v /= 4;
  215.         return uvcenter;
  216. }
  217.  
  218. //      -----------------------------------------------------------
  219. //      rotate point *uv by matrix rotmat, return *uvrot
  220. static uvl rotate_uv_point(const std::array<fix, 4> &rotmat, const uvl &uv, const uvl &uvcenter)
  221. {
  222.         const auto centered_u = uv.u - uvcenter.u;
  223.         const auto centered_v = uv.v - uvcenter.v;
  224.         return {
  225.                 fixmul(centered_u, rotmat[0]) + fixmul(centered_v, rotmat[1]) + uvcenter.u,
  226.                 fixmul(centered_u, rotmat[2]) + fixmul(centered_v, rotmat[3]) + uvcenter.v,
  227.                 0
  228.         };
  229. }
  230.  
  231. //      -----------------------------------------------------------
  232. //      Compute the center of the side in u,v coordinates.
  233. static void rotate_uv_points_on_side(unique_segment &segp, const sidenum_fast_t sidenum, const std::array<fix, 4> &rotmat, const uvl &uvcenter)
  234. {
  235.         range_for (auto &v, segp.sides[sidenum].uvls)
  236.         {
  237.                 v = rotate_uv_point(rotmat, v, uvcenter);
  238.         }
  239. }
  240.  
  241. //      -----------------------------------------------------------
  242. //      ang is in 0..ffff = 0..359.999 degrees
  243. //      rotmat is filled in with 4 fixes
  244. static std::array<fix, 4> create_2d_rotation_matrix(fix ang)
  245. {
  246.         const auto &&a = fix_sincos(ang);
  247.         const auto &sinang = a.sin;
  248.         const auto &cosang = a.cos;
  249.         return {{
  250.                 cosang,
  251.                 sinang,
  252.                 -sinang,
  253.                 cosang
  254.         }};
  255. }
  256.  
  257.  
  258. //      -----------------------------------------------------------
  259. static int DoTexRotateLeft(int value)
  260. {
  261.         const auto uvcenter = compute_uv_side_center(Cursegp, Curside);
  262.         //      Create a rotation matrix
  263.         const auto rotmat = create_2d_rotation_matrix(-F1_0/value);
  264.  
  265.         rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter);
  266.  
  267.         Update_flags |= UF_WORLD_CHANGED;
  268.  
  269.         return  1;
  270. }
  271.  
  272. int TexRotateLeft()
  273. {
  274.         return DoTexRotateLeft(192);
  275. }
  276.  
  277. int TexRotateLeftBig()
  278. {
  279.         return DoTexRotateLeft(64);
  280. }
  281.  
  282.  
  283. //      -----------------------------------------------------------
  284. static int DoTexSlideRight(int value)
  285. {
  286.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  287.         auto &Vertices = LevelSharedVertexState.get_vertices();
  288.         uvl     duvl03;
  289.         fix     dist;
  290.         auto &vp = Side_to_verts[Curside];
  291.         auto &uvls = Cursegp->unique_segment::sides[Curside].uvls;
  292.  
  293.         auto &vcvertptr = Vertices.vcptr;
  294.         dist = vm_vec_dist(vcvertptr(Cursegp->verts[vp[3]]), vcvertptr(Cursegp->verts[vp[0]]));
  295.         dist *= value;
  296.         if (dist < F1_0/(64*value))
  297.                 dist = F1_0/(64*value);
  298.  
  299.         duvl03.u = fixdiv(uvls[3].u - uvls[0].u,dist);
  300.         duvl03.v = fixdiv(uvls[3].v - uvls[0].v,dist);
  301.  
  302.         range_for (auto &v, uvls)
  303.         {
  304.                 v.u += duvl03.u;
  305.                 v.v += duvl03.v;
  306.         }
  307.  
  308.         Update_flags |= UF_WORLD_CHANGED;
  309.  
  310.         return  1;
  311. }
  312.  
  313. int TexSlideRight()
  314. {
  315.         return DoTexSlideRight(3);
  316. }
  317.  
  318. int TexSlideRightBig()
  319. {
  320.         return DoTexSlideRight(1);
  321. }
  322.  
  323. //      -----------------------------------------------------------
  324. static int DoTexRotateRight(int value)
  325. {
  326.         const auto uvcenter = compute_uv_side_center(Cursegp, Curside);
  327.  
  328.         //      Create a rotation matrix
  329.         const auto rotmat = create_2d_rotation_matrix(F1_0/value);
  330.  
  331.         rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter);
  332.  
  333.         Update_flags |= UF_WORLD_CHANGED;
  334.  
  335.         return  1;
  336. }
  337.  
  338. int TexRotateRight()
  339. {
  340.         return DoTexRotateRight(192);
  341. }
  342.  
  343. int TexRotateRightBig()
  344. {
  345.         return DoTexRotateRight(64);
  346. }
  347.  
  348. //      -----------------------------------------------------------
  349. int     TexSelectActiveEdge()
  350. {
  351.         return  1;
  352. }
  353.  
  354. //      -----------------------------------------------------------
  355. int     TexRotate90Degrees()
  356. {
  357.         const auto uvcenter = compute_uv_side_center(Cursegp, Curside);
  358.  
  359.         //      Create a rotation matrix
  360.         const auto rotmat = create_2d_rotation_matrix(F1_0/4);
  361.  
  362.         rotate_uv_points_on_side(Cursegp, Curside, rotmat, uvcenter);
  363.  
  364.         Update_flags |= UF_WORLD_CHANGED;
  365.  
  366.         return  1;
  367. }
  368.  
  369. //      -----------------------------------------------------------
  370. int     TexSetDefault()
  371. {
  372.         Num_tilings = 1;
  373.  
  374.         Stretch_scale_x = F1_0;
  375.         Stretch_scale_y = F1_0;
  376.  
  377.         assign_default_uvs_to_side(Cursegp,Curside);
  378.  
  379.         Update_flags |= UF_GAME_VIEW_CHANGED;
  380.         return  1;
  381. }
  382.  
  383. //      -----------------------------------------------------------
  384. int     TexIncreaseTiling()
  385. {
  386.  
  387.         Num_tilings++;
  388.         assign_default_uvs_to_side(Cursegp, Curside);
  389.         Update_flags |= UF_GAME_VIEW_CHANGED;
  390.  
  391.         return  1;
  392. }
  393.  
  394. //      -----------------------------------------------------------
  395. int     TexDecreaseTiling()
  396. {
  397.  
  398.         if (--Num_tilings < 1)
  399.                 Num_tilings = 1;
  400.  
  401.         assign_default_uvs_to_side(Cursegp, Curside);
  402.         Update_flags |= UF_GAME_VIEW_CHANGED;
  403.  
  404.         return  1;
  405. }
  406.  
  407.  
  408. //      direction = -1 or 1 depending on direction
  409. static int      TexStretchCommon(int direction)
  410. {
  411.         fix     *sptr;
  412.  
  413.         if ((Curedge == 0) || (Curedge == 2))
  414.                 sptr = &Stretch_scale_x;
  415.         else
  416.                 sptr = &Stretch_scale_y;
  417.  
  418.         *sptr += direction*F1_0/64;
  419.  
  420.         if (*sptr < F1_0/16)
  421.                 *sptr = F1_0/16;
  422.  
  423.         if (*sptr > 2*F1_0)
  424.                 *sptr = 2*F1_0;
  425.  
  426.         stretch_uvs_from_curedge(Cursegp, Curside);
  427.  
  428.         editor_status_fmt("Stretch scale = %7.4f, use Set Default to return to 1.0", f2fl(*sptr));
  429.  
  430.         Update_flags |= UF_GAME_VIEW_CHANGED;
  431.         return  1;
  432.  
  433. }
  434.  
  435. int     TexStretchDown(void)
  436. {
  437.         return TexStretchCommon(-1);
  438.  
  439. }
  440.  
  441. int     TexStretchUp(void)
  442. {
  443.         return TexStretchCommon(1);
  444.  
  445. }
  446.  
  447.