diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llworld.cpp | 359 |
1 files changed, 281 insertions, 78 deletions
diff --git a/linden/indra/newview/llworld.cpp b/linden/indra/newview/llworld.cpp index 90ab49b..ca8ce2d 100644 --- a/linden/indra/newview/llworld.cpp +++ b/linden/indra/newview/llworld.cpp | |||
@@ -61,6 +61,12 @@ | |||
61 | #include "llappviewer.h" // for do_disconnect() | 61 | #include "llappviewer.h" // for do_disconnect() |
62 | 62 | ||
63 | #include "hippoLimits.h" | 63 | #include "hippoLimits.h" |
64 | |||
65 | #include <deque> | ||
66 | #include <queue> | ||
67 | #include <map> | ||
68 | #include <cstring> | ||
69 | |||
64 | // | 70 | // |
65 | // Globals | 71 | // Globals |
66 | // | 72 | // |
@@ -661,7 +667,8 @@ void LLWorld::updateParticles() | |||
661 | 667 | ||
662 | void LLWorld::updateClouds(const F32 dt) | 668 | void LLWorld::updateClouds(const F32 dt) |
663 | { | 669 | { |
664 | if (gSavedSettings.getBOOL("FreezeTime") || | 670 | static BOOL* sFreezeTime = rebind_llcontrol<BOOL>("FreezeTime", &gSavedSettings, true); |
671 | if ((*sFreezeTime) || | ||
665 | !gSavedSettings.getBOOL("SkyUseClassicClouds")) | 672 | !gSavedSettings.getBOOL("SkyUseClassicClouds")) |
666 | { | 673 | { |
667 | // don't move clouds in snapshot mode | 674 | // don't move clouds in snapshot mode |
@@ -810,10 +817,69 @@ F32 LLWorld::getLandFarClip() const | |||
810 | 817 | ||
811 | void LLWorld::setLandFarClip(const F32 far_clip) | 818 | void LLWorld::setLandFarClip(const F32 far_clip) |
812 | { | 819 | { |
820 | static S32 const rwidth = (S32)REGION_WIDTH_U32; | ||
821 | S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth; | ||
822 | S32 const n2 = (llceil(far_clip) - 1) / rwidth; | ||
823 | bool need_water_objects_update = n1 != n2; | ||
824 | |||
813 | mLandFarClip = far_clip; | 825 | mLandFarClip = far_clip; |
826 | |||
827 | if (need_water_objects_update) | ||
828 | { | ||
829 | updateWaterObjects(); | ||
830 | } | ||
814 | } | 831 | } |
815 | 832 | ||
833 | // Some region that we're connected to, but not the one we're in, gave us | ||
834 | // a (possibly) new water height. Update it in our local copy. | ||
835 | void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_height) | ||
836 | { | ||
837 | for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter) | ||
838 | { | ||
839 | if ((*iter)->getName() == sim_name) | ||
840 | { | ||
841 | (*iter)->setWaterHeight(water_height); | ||
842 | break; | ||
843 | } | ||
844 | } | ||
845 | } | ||
816 | 846 | ||
847 | // There are three types of water objects: | ||
848 | // Region water objects: the water in a region. | ||
849 | // Hole water objects: water in the void but within current draw distance. | ||
850 | // Edge water objects: the water outside the draw distance, up till the horizon. | ||
851 | // | ||
852 | // For example: | ||
853 | // | ||
854 | // -----------------------horizon------------------------- | ||
855 | // | | | | | ||
856 | // | Edge Water | | | | ||
857 | // | | | | | ||
858 | // | | | | | ||
859 | // | | | | | ||
860 | // | | | | | ||
861 | // | | rwidth | | | ||
862 | // | | <-----> | | | ||
863 | // ------------------------------------------------------- | ||
864 | // | |Hole |other| | | | ||
865 | // | |Water|reg. | | | | ||
866 | // | |-----------------| | | ||
867 | // | |other|cur. |<--> | | | ||
868 | // | |reg. | reg.| \__|_ draw distance | | ||
869 | // | |-----------------| | | ||
870 | // | | | |<--->| | | ||
871 | // | | | | \__|_ range | | ||
872 | // ------------------------------------------------------- | ||
873 | // | |<----width------>|<--horizon ext.->| | ||
874 | // | | | | | ||
875 | // | | | | | ||
876 | // | | | | | ||
877 | // | | | | | ||
878 | // | | | | | ||
879 | // | | | | | ||
880 | // | | | | | ||
881 | // ------------------------------------------------------- | ||
882 | // | ||
817 | void LLWorld::updateWaterObjects() | 883 | void LLWorld::updateWaterObjects() |
818 | { | 884 | { |
819 | if (!gAgent.getRegion()) | 885 | if (!gAgent.getRegion()) |
@@ -826,128 +892,265 @@ void LLWorld::updateWaterObjects() | |||
826 | return; | 892 | return; |
827 | } | 893 | } |
828 | 894 | ||
829 | // First, determine the min and max "box" of water objects | 895 | // Region width in meters. |
830 | S32 min_x = 0; | 896 | S32 const rwidth = (S32)REGION_WIDTH_U32; |
831 | S32 min_y = 0; | 897 | |
832 | S32 max_x = 0; | 898 | // The distance we might see into the void |
833 | S32 max_y = 0; | 899 | // when standing on the edge of a region, in meters. |
900 | S32 const draw_distance = llceil(mLandFarClip); | ||
901 | |||
902 | // We can only have "holes" in the water (where there no region) if we | ||
903 | // can have existing regions around it. Taking into account that this | ||
904 | // code is only executed when we enter a region, and not when we walk | ||
905 | // around in it, we (only) need to take into account regions that fall | ||
906 | // within the draw_distance. | ||
907 | // | ||
908 | // Set 'range' to draw_distance, rounded up to the nearest multiple of rwidth. | ||
909 | S32 const nsims = (draw_distance + rwidth - 1) / rwidth; | ||
910 | S32 const range = nsims * rwidth; | ||
911 | |||
912 | // Get South-West corner of current region. | ||
913 | LLViewerRegion const* regionp = gAgent.getRegion(); | ||
834 | U32 region_x, region_y; | 914 | U32 region_x, region_y; |
835 | |||
836 | S32 rwidth = 256; | ||
837 | |||
838 | // We only want to fill in water for stuff that's near us, say, within 256 or 512m | ||
839 | S32 range = LLViewerCamera::getInstance()->getFar() > 256.f ? 512 : 256; | ||
840 | |||
841 | LLViewerRegion* regionp = gAgent.getRegion(); | ||
842 | from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); | 915 | from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); |
843 | 916 | ||
844 | min_x = (S32)region_x - range; | 917 | // The min. and max. coordinates of the South-West corners of the Hole water objects. |
845 | min_y = (S32)region_y - range; | 918 | S32 const min_x = (S32)region_x - range; |
846 | max_x = (S32)region_x + range; | 919 | S32 const min_y = (S32)region_y - range; |
847 | max_y = (S32)region_y + range; | 920 | S32 const max_x = (S32)region_x + range; |
921 | S32 const max_y = (S32)region_y + range; | ||
922 | |||
923 | // Attempt to determine a sensible water height for all the | ||
924 | // Hole Water objects. | ||
925 | // | ||
926 | // It make little sense to try to guess what the best water | ||
927 | // height should be when that isn't completely obvious: if it's | ||
928 | // impossible to satisfy every region's water height without | ||
929 | // getting a jump in the water height. | ||
930 | // | ||
931 | // In order to keep the reasoning simple, we assume something | ||
932 | // logical as a group of connected regions, where the coastline | ||
933 | // is at the outer edge. Anything more complex that would "break" | ||
934 | // under such an assumption would probably break anyway (would | ||
935 | // depend on terrain editing and existing mega prims, say, if | ||
936 | // anything would make sense at all). | ||
937 | // | ||
938 | // So, what we do is find all connected regions within the | ||
939 | // draw distance that border void, and then pick the lowest | ||
940 | // water height of those (coast) regions. | ||
941 | S32 const n = 2 * nsims + 1; | ||
942 | S32 const origin = nsims + nsims * n; | ||
943 | std::vector<F32> water_heights(n * n); | ||
944 | std::vector<U8> checked(n * n, 0); // index = nx + ny * n + origin; | ||
945 | U8 const region_bit = 1; | ||
946 | U8 const hole_bit = 2; | ||
947 | U8 const bordering_hole_bit = 4; | ||
948 | U8 const bordering_edge_bit = 8; | ||
949 | // Use the legacy waterheight for the Edge water in the case | ||
950 | // that we don't find any Hole water at all. | ||
951 | F32 water_height = DEFAULT_WATER_HEIGHT; | ||
952 | int max_count = 0; | ||
953 | LL_DEBUGS("WaterHeight") << "Current region: " << regionp->getName() << "; water height: " << regionp->getWaterHeight() << " m." << LL_ENDL; | ||
954 | std::map<S32, int> water_height_counts; | ||
955 | typedef std::queue<std::pair<S32, S32>, std::deque<std::pair<S32, S32> > > nxny_pairs_type; | ||
956 | nxny_pairs_type nxny_pairs; | ||
957 | nxny_pairs.push(nxny_pairs_type::value_type(0, 0)); | ||
958 | water_heights[origin] = regionp->getWaterHeight(); | ||
959 | checked[origin] = region_bit; | ||
960 | // For debugging purposes. | ||
961 | int number_of_connected_regions = 1; | ||
962 | int uninitialized_regions = 0; | ||
963 | int bordering_hole = 0; | ||
964 | int bordering_edge = 0; | ||
965 | while(!nxny_pairs.empty()) | ||
966 | { | ||
967 | S32 const nx = nxny_pairs.front().first; | ||
968 | S32 const ny = nxny_pairs.front().second; | ||
969 | LL_DEBUGS("WaterHeight") << "nx,ny = " << nx << "," << ny << LL_ENDL; | ||
970 | S32 const index = nx + ny * n + origin; | ||
971 | nxny_pairs.pop(); | ||
972 | for (S32 dir = 0; dir < 4; ++dir) | ||
973 | { | ||
974 | S32 const cnx = nx + gDirAxes[dir][0]; | ||
975 | S32 const cny = ny + gDirAxes[dir][1]; | ||
976 | LL_DEBUGS("WaterHeight") << "dir = " << dir << "; cnx,cny = " << cnx << "," << cny << LL_ENDL; | ||
977 | S32 const cindex = cnx + cny * n + origin; | ||
978 | bool is_hole = false; | ||
979 | bool is_edge = false; | ||
980 | LLViewerRegion* new_region_found = NULL; | ||
981 | if (cnx < -nsims || cnx > nsims || | ||
982 | cny < -nsims || cny > nsims) | ||
983 | { | ||
984 | LL_DEBUGS("WaterHeight") << " Edge Water!" << LL_ENDL; | ||
985 | // Bumped into Edge water object. | ||
986 | is_edge = true; | ||
987 | } | ||
988 | else if (checked[cindex]) | ||
989 | { | ||
990 | LL_DEBUGS("WaterHeight") << " Already checked before!" << LL_ENDL; | ||
991 | // Already checked. | ||
992 | is_hole = (checked[cindex] & hole_bit); | ||
993 | } | ||
994 | else | ||
995 | { | ||
996 | S32 x = (S32)region_x + cnx * rwidth; | ||
997 | S32 y = (S32)region_y + cny * rwidth; | ||
998 | U64 region_handle = to_region_handle(x, y); | ||
999 | new_region_found = getRegionFromHandle(region_handle); | ||
1000 | is_hole = !new_region_found; | ||
1001 | checked[cindex] = is_hole ? hole_bit : region_bit; | ||
1002 | } | ||
1003 | if (is_hole) | ||
1004 | { | ||
1005 | // This was a region that borders at least one 'hole'. | ||
1006 | // Count the found coastline. | ||
1007 | F32 new_water_height = water_heights[index]; | ||
1008 | LL_DEBUGS("WaterHeight") << " This is void; counting coastline with water height of " << new_water_height << LL_ENDL; | ||
1009 | S32 new_water_height_cm = llround(new_water_height * 100); | ||
1010 | int count = (water_height_counts[new_water_height_cm] += 1); | ||
1011 | // Just use the lowest water height: this is mainly about the horizon water, | ||
1012 | // and whatever we do, we don't want it to be possible to look under the water | ||
1013 | // when looking in the distance: it is better to make a step downwards in water | ||
1014 | // height when going away from the avie than a step upwards. However, since | ||
1015 | // everyone is used to DEFAULT_WATER_HEIGHT, don't allow a single region | ||
1016 | // to drag the water level below DEFAULT_WATER_HEIGHT on it's own. | ||
1017 | if (bordering_hole == 0 || // First time we get here. | ||
1018 | (new_water_height >= DEFAULT_WATER_HEIGHT && | ||
1019 | new_water_height < water_height) || | ||
1020 | (new_water_height < DEFAULT_WATER_HEIGHT && | ||
1021 | count > max_count) | ||
1022 | ) | ||
1023 | { | ||
1024 | water_height = new_water_height; | ||
1025 | } | ||
1026 | if (count > max_count) | ||
1027 | { | ||
1028 | max_count = count; | ||
1029 | } | ||
1030 | if (!(checked[index] & bordering_hole_bit)) | ||
1031 | { | ||
1032 | checked[index] |= bordering_hole_bit; | ||
1033 | ++bordering_hole; | ||
1034 | } | ||
1035 | } | ||
1036 | else if (is_edge && !(checked[index] & bordering_edge_bit)) | ||
1037 | { | ||
1038 | checked[index] |= bordering_edge_bit; | ||
1039 | ++bordering_edge; | ||
1040 | } | ||
1041 | if (!new_region_found) | ||
1042 | { | ||
1043 | // Dead end, there is no region here. | ||
1044 | continue; | ||
1045 | } | ||
1046 | // Found a new connected region. | ||
1047 | ++number_of_connected_regions; | ||
1048 | if (new_region_found->getName().empty()) | ||
1049 | { | ||
1050 | // Uninitialized LLViewerRegion, don't use it's water height. | ||
1051 | LL_DEBUGS("WaterHeight") << " Uninitialized region." << LL_ENDL; | ||
1052 | ++uninitialized_regions; | ||
1053 | continue; | ||
1054 | } | ||
1055 | nxny_pairs.push(nxny_pairs_type::value_type(cnx, cny)); | ||
1056 | water_heights[cindex] = new_region_found->getWaterHeight(); | ||
1057 | LL_DEBUGS("WaterHeight") << " Found a new region (name: " << new_region_found->getName() << "; water height: " << water_heights[cindex] << " m)!" << LL_ENDL; | ||
1058 | } | ||
1059 | } | ||
1060 | llinfos << "Number of connected regions: " << number_of_connected_regions << " (" << uninitialized_regions << | ||
1061 | " uninitialized); number of regions bordering Hole water: " << bordering_hole << | ||
1062 | "; number of regions bordering Edge water: " << bordering_edge << llendl; | ||
1063 | llinfos << "Coastline count (height, count): "; | ||
1064 | bool first = true; | ||
1065 | for (std::map<S32, int>::iterator iter = water_height_counts.begin(); iter != water_height_counts.end(); ++iter) | ||
1066 | { | ||
1067 | if (!first) llcont << ", "; | ||
1068 | llcont << "(" << (iter->first / 100.f) << ", " << iter->second << ")"; | ||
1069 | first = false; | ||
1070 | } | ||
1071 | llcont << llendl; | ||
1072 | llinfos << "Water height used for Hole and Edge water objects: " << water_height << llendl; | ||
848 | 1073 | ||
849 | F32 height = 0.f; | 1074 | // Update all Region water objects. |
850 | 1075 | for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter) | |
851 | for (region_list_t::iterator iter = mRegionList.begin(); | ||
852 | iter != mRegionList.end(); ++iter) | ||
853 | { | 1076 | { |
854 | LLViewerRegion* regionp = *iter; | 1077 | LLViewerRegion* regionp = *iter; |
855 | LLVOWater* waterp = regionp->getLand().getWaterObj(); | 1078 | LLVOWater* waterp = regionp->getLand().getWaterObj(); |
856 | height += regionp->getWaterHeight(); | ||
857 | if (waterp) | 1079 | if (waterp) |
858 | { | 1080 | { |
859 | gObjectList.updateActive(waterp); | 1081 | gObjectList.updateActive(waterp); |
860 | } | 1082 | } |
861 | } | 1083 | } |
862 | 1084 | ||
1085 | // Clean up all existing Hole water objects. | ||
863 | for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin(); | 1086 | for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin(); |
864 | iter != mHoleWaterObjects.end(); ++ iter) | 1087 | iter != mHoleWaterObjects.end(); ++iter) |
865 | { | 1088 | { |
866 | LLVOWater* waterp = *iter; | 1089 | LLVOWater* waterp = *iter; |
867 | gObjectList.killObject(waterp); | 1090 | gObjectList.killObject(waterp); |
868 | } | 1091 | } |
869 | mHoleWaterObjects.clear(); | 1092 | mHoleWaterObjects.clear(); |
870 | 1093 | ||
871 | // Now, get a list of the holes | 1094 | // Let the Edge and Hole water boxes be 1024 meter high so that they |
872 | S32 x, y; | 1095 | // are never too small to be drawn (A LL_VO_*_WATER box has water |
873 | for (x = min_x; x <= max_x; x += rwidth) | 1096 | // rendered on it's bottom surface only), and put their bottom at |
1097 | // the current regions water height. | ||
1098 | F32 const box_height = 1024; | ||
1099 | F32 const water_center_z = water_height + box_height / 2; | ||
1100 | |||
1101 | // Create new Hole water objects within 'range' where there is no region. | ||
1102 | for (S32 x = min_x; x <= max_x; x += rwidth) | ||
874 | { | 1103 | { |
875 | for (y = min_y; y <= max_y; y += rwidth) | 1104 | for (S32 y = min_y; y <= max_y; y += rwidth) |
876 | { | 1105 | { |
877 | U64 region_handle = to_region_handle(x, y); | 1106 | U64 region_handle = to_region_handle(x, y); |
878 | if (!getRegionFromHandle(region_handle)) | 1107 | if (!getRegionFromHandle(region_handle)) |
879 | { | 1108 | { |
880 | LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion()); | 1109 | LLVOWater* waterp = (LLVOWater*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion()); |
881 | waterp->setUseTexture(FALSE); | 1110 | waterp->setUseTexture(FALSE); |
882 | waterp->setPositionGlobal(LLVector3d(x + rwidth/2, | 1111 | waterp->setPositionGlobal(LLVector3d(x + rwidth / 2, y + rwidth / 2, water_center_z)); |
883 | y + rwidth/2, | 1112 | waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, box_height)); |
884 | 256.f+DEFAULT_WATER_HEIGHT)); | ||
885 | waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f)); | ||
886 | gPipeline.createObject(waterp); | 1113 | gPipeline.createObject(waterp); |
887 | mHoleWaterObjects.push_back(waterp); | 1114 | mHoleWaterObjects.push_back(waterp); |
888 | } | 1115 | } |
889 | } | 1116 | } |
890 | } | 1117 | } |
891 | 1118 | ||
892 | // Update edge water objects | 1119 | // Center of the region. |
893 | S32 wx, wy; | 1120 | S32 const center_x = region_x + rwidth / 2; |
894 | S32 center_x, center_y; | 1121 | S32 const center_y = region_y + rwidth / 2; |
895 | wx = (max_x - min_x) + rwidth; | 1122 | // Width of the area with Hole water objects. |
896 | wy = (max_y - min_y) + rwidth; | 1123 | S32 const width = rwidth + 2 * range; |
897 | center_x = min_x + (wx >> 1); | 1124 | S32 const horizon_extend = 2048 + 512 - range; // Legacy value. |
898 | center_y = min_y + (wy >> 1); | 1125 | // The overlap is needed to get rid of sky pixels being visible between the |
899 | 1126 | // Edge and Hole water object at greater distances (due to floating point | |
900 | S32 add_boundary[4] = { | 1127 | // round off errors). |
901 | 512 - (max_x - region_x), | 1128 | S32 const edge_hole_overlap = 1; // Twice the actual overlap. |
902 | 512 - (max_y - region_y), | 1129 | |
903 | 512 - (region_x - min_x), | 1130 | for (S32 dir = 0; dir < 8; ++dir) |
904 | 512 - (region_y - min_y) }; | ||
905 | |||
906 | S32 dir; | ||
907 | for (dir = 0; dir < 8; dir++) | ||
908 | { | 1131 | { |
909 | S32 dim[2] = { 0 }; | 1132 | // Size of the Edge water objects. |
910 | switch (gDirAxes[dir][0]) | 1133 | S32 const dim_x = (gDirAxes[dir][0] == 0) ? width : (horizon_extend + edge_hole_overlap); |
911 | { | 1134 | S32 const dim_y = (gDirAxes[dir][1] == 0) ? width : (horizon_extend + edge_hole_overlap); |
912 | case -1: dim[0] = add_boundary[2]; break; | 1135 | // And their position. |
913 | case 0: dim[0] = wx; break; | 1136 | S32 const water_center_x = center_x + (width + horizon_extend) / 2 * gDirAxes[dir][0]; |
914 | default: dim[0] = add_boundary[0]; break; | 1137 | S32 const water_center_y = center_y + (width + horizon_extend) / 2 * gDirAxes[dir][1]; |
915 | } | ||
916 | switch (gDirAxes[dir][1]) | ||
917 | { | ||
918 | case -1: dim[1] = add_boundary[3]; break; | ||
919 | case 0: dim[1] = wy; break; | ||
920 | default: dim[1] = add_boundary[1]; break; | ||
921 | } | ||
922 | 1138 | ||
923 | // Resize and reshape the water objects | ||
924 | const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]); | ||
925 | const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]); | ||
926 | |||
927 | LLVOWater* waterp = mEdgeWaterObjects[dir]; | 1139 | LLVOWater* waterp = mEdgeWaterObjects[dir]; |
928 | if (!waterp || waterp->isDead()) | 1140 | if (!waterp || waterp->isDead()) |
929 | { | 1141 | { |
930 | // The edge water objects can be dead because they're attached to the region that the | 1142 | // The edge water objects can be dead because they're attached to the region that the |
931 | // agent was in when they were originally created. | 1143 | // agent was in when they were originally created. |
932 | mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, | 1144 | mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion()); |
933 | gAgent.getRegion()); | ||
934 | waterp = mEdgeWaterObjects[dir]; | 1145 | waterp = mEdgeWaterObjects[dir]; |
935 | waterp->setUseTexture(FALSE); | 1146 | waterp->setUseTexture(FALSE); |
936 | waterp->setIsEdgePatch(TRUE); | 1147 | waterp->setIsEdgePatch(TRUE); // Mark that this is edge water and not hole water. |
937 | gPipeline.createObject(waterp); | 1148 | gPipeline.createObject(waterp); |
938 | } | 1149 | } |
939 | 1150 | ||
940 | waterp->setRegion(gAgent.getRegion()); | 1151 | waterp->setRegion(gAgent.getRegion()); |
941 | LLVector3d water_pos(water_center_x, water_center_y, | 1152 | LLVector3d water_pos(water_center_x, water_center_y, water_center_z); |
942 | DEFAULT_WATER_HEIGHT+256.f); | 1153 | LLVector3 water_scale((F32) dim_x, (F32) dim_y, box_height); |
943 | LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f); | ||
944 | |||
945 | //stretch out to horizon | ||
946 | water_scale.mV[0] += fabsf(2048.f * gDirAxes[dir][0]); | ||
947 | water_scale.mV[1] += fabsf(2048.f * gDirAxes[dir][1]); | ||
948 | |||
949 | water_pos.mdV[0] += 1024.f * gDirAxes[dir][0]; | ||
950 | water_pos.mdV[1] += 1024.f * gDirAxes[dir][1]; | ||
951 | 1154 | ||
952 | waterp->setPositionGlobal(water_pos); | 1155 | waterp->setPositionGlobal(water_pos); |
953 | waterp->setScale(water_scale); | 1156 | waterp->setScale(water_scale); |