diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llvotree.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llvotree.cpp | 925 |
1 files changed, 925 insertions, 0 deletions
diff --git a/linden/indra/newview/llvotree.cpp b/linden/indra/newview/llvotree.cpp new file mode 100644 index 0000000..9808a02 --- /dev/null +++ b/linden/indra/newview/llvotree.cpp | |||
@@ -0,0 +1,925 @@ | |||
1 | /** | ||
2 | * @file llvotree.cpp | ||
3 | * @brief LLVOTree class implementation | ||
4 | * | ||
5 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "llviewerprecompiledheaders.h" | ||
29 | |||
30 | #include "llvotree.h" | ||
31 | |||
32 | #include "llviewercontrol.h" | ||
33 | #include "lldir.h" | ||
34 | #include "llprimitive.h" | ||
35 | #include "lltree_common.h" | ||
36 | #include "llxmltree.h" | ||
37 | #include "material_codes.h" | ||
38 | #include "object_flags.h" | ||
39 | |||
40 | #include "llagent.h" | ||
41 | #include "llagparray.h" | ||
42 | #include "llcylinder.h" | ||
43 | #include "lldrawable.h" | ||
44 | #include "llface.h" | ||
45 | #include "llviewercamera.h" | ||
46 | #include "llviewerimagelist.h" | ||
47 | #include "llviewerobjectlist.h" | ||
48 | #include "llviewerregion.h" | ||
49 | #include "llworld.h" | ||
50 | #include "noise.h" | ||
51 | #include "pipeline.h" | ||
52 | #include "llviewerwindow.h" | ||
53 | |||
54 | extern LLPipeline gPipeline; | ||
55 | |||
56 | LLGLuint mLeafDList; | ||
57 | |||
58 | S32 LLVOTree::sLODVertexOffset[4]; | ||
59 | S32 LLVOTree::sLODVertexCount[4]; | ||
60 | S32 LLVOTree::sLODIndexOffset[4]; | ||
61 | S32 LLVOTree::sLODIndexCount[4]; | ||
62 | S32 LLVOTree::sLODSlices[4] = {10, 5, 4, 3}; | ||
63 | F32 LLVOTree::sLODAngles[4] = {30.f, 20.f, 15.f, 0.f}; | ||
64 | |||
65 | F32 LLVOTree::sTreeFactor = 1.f; | ||
66 | |||
67 | LLVOTree::SpeciesMap LLVOTree::sSpeciesTable; | ||
68 | S32 LLVOTree::sMaxTreeSpecies = 0; | ||
69 | |||
70 | // Tree variables and functions | ||
71 | |||
72 | LLVOTree::LLVOTree(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp): | ||
73 | LLViewerObject(id, pcode, regionp) | ||
74 | { | ||
75 | mSpecies = 0; | ||
76 | mFrameCount = 0; | ||
77 | mWind = mRegionp->mWind.getVelocity(getPositionRegion()); | ||
78 | } | ||
79 | |||
80 | |||
81 | LLVOTree::~LLVOTree() | ||
82 | { | ||
83 | if (mData) | ||
84 | { | ||
85 | delete[] mData; | ||
86 | mData = NULL; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // static | ||
91 | void LLVOTree::initClass() | ||
92 | { | ||
93 | std::string xml_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"trees.xml"); | ||
94 | |||
95 | LLXmlTree tree_def_tree; | ||
96 | |||
97 | if (!tree_def_tree.parseFile(xml_filename)) | ||
98 | { | ||
99 | llerrs << "Failed to parse tree file." << llendl; | ||
100 | } | ||
101 | |||
102 | LLXmlTreeNode* rootp = tree_def_tree.getRoot(); | ||
103 | |||
104 | for (LLXmlTreeNode* tree_def = rootp->getFirstChild(); | ||
105 | tree_def; | ||
106 | tree_def = rootp->getNextChild()) | ||
107 | { | ||
108 | if (!tree_def->hasName("tree")) | ||
109 | { | ||
110 | llwarns << "Invalid tree definition node " << tree_def->getName() << llendl; | ||
111 | continue; | ||
112 | } | ||
113 | F32 F32_val; | ||
114 | LLUUID id; | ||
115 | S32 S32_val; | ||
116 | |||
117 | BOOL success = TRUE; | ||
118 | |||
119 | |||
120 | |||
121 | S32 species; | ||
122 | static LLStdStringHandle species_id_string = LLXmlTree::addAttributeString("species_id"); | ||
123 | if (!tree_def->getFastAttributeS32(species_id_string, species)) | ||
124 | { | ||
125 | llwarns << "No species id defined" << llendl; | ||
126 | continue; | ||
127 | } | ||
128 | |||
129 | if (species < 0) | ||
130 | { | ||
131 | llwarns << "Invalid species id " << species << llendl; | ||
132 | continue; | ||
133 | } | ||
134 | |||
135 | if (sSpeciesTable.count(species)) | ||
136 | { | ||
137 | llwarns << "Tree species " << species << " already defined! Duplicate discarded." << llendl; | ||
138 | continue; | ||
139 | } | ||
140 | |||
141 | TreeSpeciesData* newTree = new TreeSpeciesData(); | ||
142 | |||
143 | static LLStdStringHandle texture_id_string = LLXmlTree::addAttributeString("texture_id"); | ||
144 | success &= tree_def->getFastAttributeUUID(texture_id_string, id); | ||
145 | newTree->mTextureID = id; | ||
146 | |||
147 | static LLStdStringHandle droop_string = LLXmlTree::addAttributeString("droop"); | ||
148 | success &= tree_def->getFastAttributeF32(droop_string, F32_val); | ||
149 | newTree->mDroop = F32_val; | ||
150 | |||
151 | static LLStdStringHandle twist_string = LLXmlTree::addAttributeString("twist"); | ||
152 | success &= tree_def->getFastAttributeF32(twist_string, F32_val); | ||
153 | newTree->mTwist = F32_val; | ||
154 | |||
155 | static LLStdStringHandle branches_string = LLXmlTree::addAttributeString("branches"); | ||
156 | success &= tree_def->getFastAttributeF32(branches_string, F32_val); | ||
157 | newTree->mBranches = F32_val; | ||
158 | |||
159 | static LLStdStringHandle depth_string = LLXmlTree::addAttributeString("depth"); | ||
160 | success &= tree_def->getFastAttributeS32(depth_string, S32_val); | ||
161 | newTree->mDepth = S32_val; | ||
162 | |||
163 | static LLStdStringHandle scale_step_string = LLXmlTree::addAttributeString("scale_step"); | ||
164 | success &= tree_def->getFastAttributeF32(scale_step_string, F32_val); | ||
165 | newTree->mScaleStep = F32_val; | ||
166 | |||
167 | static LLStdStringHandle trunk_depth_string = LLXmlTree::addAttributeString("trunk_depth"); | ||
168 | success &= tree_def->getFastAttributeS32(trunk_depth_string, S32_val); | ||
169 | newTree->mTrunkDepth = S32_val; | ||
170 | |||
171 | static LLStdStringHandle branch_length_string = LLXmlTree::addAttributeString("branch_length"); | ||
172 | success &= tree_def->getFastAttributeF32(branch_length_string, F32_val); | ||
173 | newTree->mBranchLength = F32_val; | ||
174 | |||
175 | static LLStdStringHandle trunk_length_string = LLXmlTree::addAttributeString("trunk_length"); | ||
176 | success &= tree_def->getFastAttributeF32(trunk_length_string, F32_val); | ||
177 | newTree->mTrunkLength = F32_val; | ||
178 | |||
179 | static LLStdStringHandle leaf_scale_string = LLXmlTree::addAttributeString("leaf_scale"); | ||
180 | success &= tree_def->getFastAttributeF32(leaf_scale_string, F32_val); | ||
181 | newTree->mLeafScale = F32_val; | ||
182 | |||
183 | static LLStdStringHandle billboard_scale_string = LLXmlTree::addAttributeString("billboard_scale"); | ||
184 | success &= tree_def->getFastAttributeF32(billboard_scale_string, F32_val); | ||
185 | newTree->mBillboardScale = F32_val; | ||
186 | |||
187 | static LLStdStringHandle billboard_ratio_string = LLXmlTree::addAttributeString("billboard_ratio"); | ||
188 | success &= tree_def->getFastAttributeF32(billboard_ratio_string, F32_val); | ||
189 | newTree->mBillboardRatio = F32_val; | ||
190 | |||
191 | static LLStdStringHandle trunk_aspect_string = LLXmlTree::addAttributeString("trunk_aspect"); | ||
192 | success &= tree_def->getFastAttributeF32(trunk_aspect_string, F32_val); | ||
193 | newTree->mTrunkAspect = F32_val; | ||
194 | |||
195 | static LLStdStringHandle branch_aspect_string = LLXmlTree::addAttributeString("branch_aspect"); | ||
196 | success &= tree_def->getFastAttributeF32(branch_aspect_string, F32_val); | ||
197 | newTree->mBranchAspect = F32_val; | ||
198 | |||
199 | static LLStdStringHandle leaf_rotate_string = LLXmlTree::addAttributeString("leaf_rotate"); | ||
200 | success &= tree_def->getFastAttributeF32(leaf_rotate_string, F32_val); | ||
201 | newTree->mRandomLeafRotate = F32_val; | ||
202 | |||
203 | static LLStdStringHandle noise_mag_string = LLXmlTree::addAttributeString("noise_mag"); | ||
204 | success &= tree_def->getFastAttributeF32(noise_mag_string, F32_val); | ||
205 | newTree->mNoiseMag = F32_val; | ||
206 | |||
207 | static LLStdStringHandle noise_scale_string = LLXmlTree::addAttributeString("noise_scale"); | ||
208 | success &= tree_def->getFastAttributeF32(noise_scale_string, F32_val); | ||
209 | newTree->mNoiseScale = F32_val; | ||
210 | |||
211 | static LLStdStringHandle taper_string = LLXmlTree::addAttributeString("taper"); | ||
212 | success &= tree_def->getFastAttributeF32(taper_string, F32_val); | ||
213 | newTree->mTaper = F32_val; | ||
214 | |||
215 | static LLStdStringHandle repeat_z_string = LLXmlTree::addAttributeString("repeat_z"); | ||
216 | success &= tree_def->getFastAttributeF32(repeat_z_string, F32_val); | ||
217 | newTree->mRepeatTrunkZ = F32_val; | ||
218 | |||
219 | sSpeciesTable[species] = newTree; | ||
220 | |||
221 | if (species >= sMaxTreeSpecies) sMaxTreeSpecies = species + 1; | ||
222 | |||
223 | if (!success) | ||
224 | { | ||
225 | LLString name; | ||
226 | static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); | ||
227 | tree_def->getFastAttributeString(name_string, name); | ||
228 | llwarns << "Incomplete definition of tree " << name << llendl; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | BOOL have_all_trees = TRUE; | ||
233 | LLString err; | ||
234 | char buffer[10]; | ||
235 | |||
236 | for (S32 i=0;i<sMaxTreeSpecies;++i) | ||
237 | { | ||
238 | if (!sSpeciesTable.count(i)) | ||
239 | { | ||
240 | snprintf(buffer,10," %d",i); | ||
241 | err.append(buffer); | ||
242 | have_all_trees = FALSE; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | if (!have_all_trees) | ||
247 | { | ||
248 | LLStringBase<char>::format_map_t args; | ||
249 | args["[SPECIES]"] = err; | ||
250 | gViewerWindow->alertXml("ErrorUndefinedTrees", args ); | ||
251 | } | ||
252 | }; | ||
253 | |||
254 | //static | ||
255 | void LLVOTree::cleanupClass() | ||
256 | { | ||
257 | std::for_each(sSpeciesTable.begin(), sSpeciesTable.end(), DeletePairedPointer()); | ||
258 | } | ||
259 | |||
260 | U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys, | ||
261 | void **user_data, | ||
262 | U32 block_num, EObjectUpdateType update_type, | ||
263 | LLDataPacker *dp) | ||
264 | { | ||
265 | // Do base class updates... | ||
266 | U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); | ||
267 | |||
268 | if ( (getVelocity().magVecSquared() > 0.f) | ||
269 | ||(getAcceleration().magVecSquared() > 0.f) | ||
270 | ||(getAngularVelocity().magVecSquared() > 0.f)) | ||
271 | { | ||
272 | llinfos << "ACK! Moving tree!" << llendl; | ||
273 | setVelocity(LLVector3::zero); | ||
274 | setAcceleration(LLVector3::zero); | ||
275 | setAngularVelocity(LLVector3::zero); | ||
276 | } | ||
277 | |||
278 | if (update_type == OUT_TERSE_IMPROVED) | ||
279 | { | ||
280 | // Nothing else needs to be done for the terse message. | ||
281 | return retval; | ||
282 | } | ||
283 | |||
284 | // | ||
285 | // Load Instance-Specific data | ||
286 | // | ||
287 | if (mData) | ||
288 | { | ||
289 | mSpecies = ((U8 *)mData)[0]; | ||
290 | } | ||
291 | |||
292 | if (!sSpeciesTable.count(mSpecies)) | ||
293 | { | ||
294 | if (sSpeciesTable.size()) | ||
295 | { | ||
296 | SpeciesMap::const_iterator it = sSpeciesTable.begin(); | ||
297 | mSpecies = (*it).first; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | // | ||
302 | // Load Species-Specific data | ||
303 | // | ||
304 | mTreeImagep = gImageList.getImage(sSpeciesTable[mSpecies]->mTextureID); | ||
305 | if (mTreeImagep) | ||
306 | { | ||
307 | mTreeImagep->bindTexture(0); | ||
308 | mTreeImagep->setClamp(TRUE, TRUE); | ||
309 | } | ||
310 | mBranchLength = sSpeciesTable[mSpecies]->mBranchLength; | ||
311 | mTrunkLength = sSpeciesTable[mSpecies]->mTrunkLength; | ||
312 | mLeafScale = sSpeciesTable[mSpecies]->mLeafScale; | ||
313 | mDroop = sSpeciesTable[mSpecies]->mDroop; | ||
314 | mTwist = sSpeciesTable[mSpecies]->mTwist; | ||
315 | mBranches = sSpeciesTable[mSpecies]->mBranches; | ||
316 | mDepth = sSpeciesTable[mSpecies]->mDepth; | ||
317 | mScaleStep = sSpeciesTable[mSpecies]->mScaleStep; | ||
318 | mTrunkDepth = sSpeciesTable[mSpecies]->mTrunkDepth; | ||
319 | mBillboardScale = sSpeciesTable[mSpecies]->mBillboardScale; | ||
320 | mBillboardRatio = sSpeciesTable[mSpecies]->mBillboardRatio; | ||
321 | mTrunkAspect = sSpeciesTable[mSpecies]->mTrunkAspect; | ||
322 | mBranchAspect = sSpeciesTable[mSpecies]->mBranchAspect; | ||
323 | |||
324 | return retval; | ||
325 | } | ||
326 | |||
327 | BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) | ||
328 | { | ||
329 | const U16 FRAMES_PER_WIND_UPDATE = 20; // How many frames between wind update per tree | ||
330 | const F32 TREE_WIND_SENSITIVITY = 0.005f; | ||
331 | const F32 TREE_TRUNK_STIFFNESS = 0.1f; | ||
332 | |||
333 | if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TREE))) | ||
334 | { | ||
335 | return TRUE; | ||
336 | } | ||
337 | |||
338 | F32 mass_inv; | ||
339 | |||
340 | // For all tree objects, update the trunk bending with the current wind | ||
341 | // Walk sprite list in order away from viewer | ||
342 | if (!(mFrameCount % FRAMES_PER_WIND_UPDATE)) | ||
343 | { | ||
344 | // If needed, Get latest wind for this tree | ||
345 | mWind = mRegionp->mWind.getVelocity(getPositionRegion()); | ||
346 | } | ||
347 | mFrameCount++; | ||
348 | |||
349 | mass_inv = 1.f/(5.f + mDepth*mBranches*0.2f); | ||
350 | mTrunkVel += (mWind * mass_inv * TREE_WIND_SENSITIVITY); // Pull in direction of wind | ||
351 | mTrunkVel -= (mTrunkBend * mass_inv * TREE_TRUNK_STIFFNESS); // Restoring force in direction of trunk | ||
352 | mTrunkBend += mTrunkVel; | ||
353 | mTrunkVel *= 0.99f; // Add damping | ||
354 | |||
355 | if (mTrunkBend.magVec() > 1.f) | ||
356 | { | ||
357 | mTrunkBend.normVec(); | ||
358 | } | ||
359 | |||
360 | if (mTrunkVel.magVec() > 1.f) | ||
361 | { | ||
362 | mTrunkVel.normVec(); | ||
363 | } | ||
364 | |||
365 | return TRUE; | ||
366 | } | ||
367 | |||
368 | |||
369 | const F32 TREE_BLEND_MIN = 1.f; | ||
370 | const F32 TREE_BLEND_RANGE = 1.f; | ||
371 | |||
372 | |||
373 | void LLVOTree::render(LLAgent &agent) | ||
374 | { | ||
375 | } | ||
376 | |||
377 | |||
378 | void LLVOTree::setPixelAreaAndAngle(LLAgent &agent) | ||
379 | { | ||
380 | // First calculate values as for any other object (for mAppAngle) | ||
381 | LLViewerObject::setPixelAreaAndAngle(agent); | ||
382 | |||
383 | // Re-calculate mPixelArea accurately | ||
384 | |||
385 | // This should be the camera's center, as soon as we move to all region-local. | ||
386 | LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent(); | ||
387 | F32 range = relative_position.magVec(); // ugh, square root | ||
388 | |||
389 | F32 max_scale = mBillboardScale * getMaxScale(); | ||
390 | F32 area = max_scale * (max_scale*mBillboardRatio); | ||
391 | |||
392 | // Compute pixels per meter at the given range | ||
393 | F32 pixels_per_meter = gCamera->getViewHeightInPixels() / | ||
394 | (tan(gCamera->getView()) * range); | ||
395 | |||
396 | mPixelArea = (pixels_per_meter) * (pixels_per_meter) * area; | ||
397 | #if 0 | ||
398 | // mAppAngle is a bit of voodoo; | ||
399 | // use the one calculated LLViewerObject::setPixelAreaAndAngle above | ||
400 | // to avoid LOD miscalculations | ||
401 | mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG; | ||
402 | #endif | ||
403 | } | ||
404 | |||
405 | void LLVOTree::updateTextures(LLAgent &agent) | ||
406 | { | ||
407 | F32 texel_area_ratio = 1.f; | ||
408 | F32 cos_angle = 1.f; | ||
409 | if (mTreeImagep) | ||
410 | { | ||
411 | mTreeImagep->addTextureStats(mPixelArea, texel_area_ratio, cos_angle); | ||
412 | } | ||
413 | |||
414 | } | ||
415 | |||
416 | |||
417 | LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline) | ||
418 | { | ||
419 | pipeline->allocDrawable(this); | ||
420 | mDrawable->setLit(FALSE); | ||
421 | |||
422 | mDrawable->setRenderType(LLPipeline::RENDER_TYPE_TREE); | ||
423 | |||
424 | LLDrawPool *poolp = gPipeline.getPool(LLDrawPool::POOL_TREE, mTreeImagep); | ||
425 | |||
426 | // Just a placeholder for an actual object... | ||
427 | LLFace *facep = mDrawable->addFace(poolp, mTreeImagep, TRUE); | ||
428 | facep->setSize(1, 3); | ||
429 | |||
430 | gPipeline.markMaterialed(mDrawable); | ||
431 | |||
432 | updateRadius(); | ||
433 | |||
434 | return mDrawable; | ||
435 | } | ||
436 | |||
437 | |||
438 | // Yes, I know this is bad. I'll clean this up soon. - djs 04/02/02 | ||
439 | const S32 LEAF_INDICES = 24; | ||
440 | const S32 LEAF_VERTICES = 16; | ||
441 | |||
442 | BOOL LLVOTree::updateGeometry(LLDrawable *drawable) | ||
443 | { | ||
444 | U32 i, j; | ||
445 | const S32 MAX_SLICES = 32; | ||
446 | |||
447 | const F32 LEAF_LEFT = 0.52f; | ||
448 | const F32 LEAF_RIGHT = 0.98f; | ||
449 | const F32 LEAF_TOP = 1.0f; | ||
450 | const F32 LEAF_BOTTOM = 0.52f; | ||
451 | |||
452 | const F32 LEAF_WIDTH = 1.f; | ||
453 | |||
454 | |||
455 | U32 slices = MAX_SLICES; | ||
456 | |||
457 | S32 max_indices = LEAF_INDICES; | ||
458 | S32 max_vertices = LEAF_VERTICES; | ||
459 | S32 lod; | ||
460 | |||
461 | LLFace *face = drawable->getFace(0); | ||
462 | |||
463 | face->mCenterAgent = getPositionAgent(); | ||
464 | face->mCenterLocal = face->mCenterAgent; | ||
465 | |||
466 | LLDrawPool *poolp = face->getPool(); | ||
467 | |||
468 | if (poolp->getVertexCount()) | ||
469 | { | ||
470 | return TRUE; | ||
471 | } | ||
472 | |||
473 | if (!face->getDirty()) | ||
474 | { | ||
475 | return FALSE; | ||
476 | } | ||
477 | |||
478 | poolp->setDirty(); | ||
479 | |||
480 | for (lod = 0; lod < 4; lod++) | ||
481 | { | ||
482 | slices = sLODSlices[lod]; | ||
483 | sLODVertexOffset[lod] = max_vertices; | ||
484 | sLODVertexCount[lod] = slices*slices; | ||
485 | sLODIndexOffset[lod] = max_indices; | ||
486 | sLODIndexCount[lod] = (slices-1)*(slices-1)*6; | ||
487 | max_indices += sLODIndexCount[lod]; | ||
488 | max_vertices += sLODVertexCount[lod]; | ||
489 | } | ||
490 | |||
491 | LLStrider<LLVector3> vertices; | ||
492 | LLStrider<LLVector3> normals; | ||
493 | LLStrider<LLVector2> tex_coords; | ||
494 | U32 *indicesp; | ||
495 | |||
496 | face->setSize(max_vertices, max_indices); | ||
497 | face->getGeometry(vertices, normals, tex_coords, indicesp); | ||
498 | |||
499 | S32 vertex_count = 0; | ||
500 | S32 index_count = 0; | ||
501 | |||
502 | // First leaf | ||
503 | for (i = 0; i < 4; i++) | ||
504 | { | ||
505 | *(normals++) = LLVector3(0.f, 0.f, 1.f); | ||
506 | } | ||
507 | |||
508 | *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); | ||
509 | *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); | ||
510 | vertex_count++; | ||
511 | |||
512 | *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); | ||
513 | *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); | ||
514 | vertex_count++; | ||
515 | |||
516 | *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); | ||
517 | *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); | ||
518 | vertex_count++; | ||
519 | |||
520 | *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); | ||
521 | *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); | ||
522 | vertex_count++; | ||
523 | |||
524 | |||
525 | *(indicesp++) = 0; | ||
526 | index_count++; | ||
527 | *(indicesp++) = 1; | ||
528 | index_count++; | ||
529 | *(indicesp++) = 2; | ||
530 | index_count++; | ||
531 | |||
532 | *(indicesp++) = 0; | ||
533 | index_count++; | ||
534 | *(indicesp++) = 3; | ||
535 | index_count++; | ||
536 | *(indicesp++) = 1; | ||
537 | index_count++; | ||
538 | |||
539 | // Same leaf, inverse winding/normals | ||
540 | for (i = 0; i < 4; i++) | ||
541 | { | ||
542 | *(normals++) = LLVector3(0.f, 0.f, 1.f); | ||
543 | } | ||
544 | |||
545 | *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); | ||
546 | *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); | ||
547 | vertex_count++; | ||
548 | |||
549 | //*(tex_coords++) = LLVector2(1.f, 1.0f); | ||
550 | *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); | ||
551 | *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); | ||
552 | vertex_count++; | ||
553 | |||
554 | //*(tex_coords++) = LLVector2(0.52f, 1.0f); | ||
555 | *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); | ||
556 | *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); | ||
557 | vertex_count++; | ||
558 | |||
559 | //*(tex_coords++) = LLVector2(1.f, 0.52f); | ||
560 | *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); | ||
561 | *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); | ||
562 | vertex_count++; | ||
563 | |||
564 | *(indicesp++) = 4; | ||
565 | index_count++; | ||
566 | *(indicesp++) = 6; | ||
567 | index_count++; | ||
568 | *(indicesp++) = 5; | ||
569 | index_count++; | ||
570 | |||
571 | *(indicesp++) = 4; | ||
572 | index_count++; | ||
573 | *(indicesp++) = 5; | ||
574 | index_count++; | ||
575 | *(indicesp++) = 7; | ||
576 | index_count++; | ||
577 | |||
578 | |||
579 | for (i = 0; i < 4; i++) | ||
580 | { | ||
581 | *(normals++) = LLVector3(0.f, 0.f, 1.f); | ||
582 | } | ||
583 | |||
584 | *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); | ||
585 | *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); | ||
586 | vertex_count++; | ||
587 | |||
588 | *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); | ||
589 | *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); | ||
590 | vertex_count++; | ||
591 | |||
592 | *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); | ||
593 | *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); | ||
594 | vertex_count++; | ||
595 | |||
596 | *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); | ||
597 | *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); | ||
598 | vertex_count++; | ||
599 | |||
600 | *(indicesp++) = 8; | ||
601 | index_count++; | ||
602 | *(indicesp++) = 9; | ||
603 | index_count++; | ||
604 | *(indicesp++) = 10; | ||
605 | index_count++; | ||
606 | |||
607 | *(indicesp++) = 8; | ||
608 | index_count++; | ||
609 | *(indicesp++) = 11; | ||
610 | index_count++; | ||
611 | *(indicesp++) = 9; | ||
612 | index_count++; | ||
613 | |||
614 | for (i = 0; i < 4; i++) | ||
615 | { | ||
616 | *(normals++) = LLVector3(0.f, 0.f, 1.f); | ||
617 | } | ||
618 | |||
619 | *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); | ||
620 | *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); | ||
621 | vertex_count++; | ||
622 | |||
623 | *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); | ||
624 | *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); | ||
625 | vertex_count++; | ||
626 | |||
627 | *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); | ||
628 | *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); | ||
629 | vertex_count++; | ||
630 | |||
631 | *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); | ||
632 | *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); | ||
633 | vertex_count++; | ||
634 | |||
635 | |||
636 | *(indicesp++) = 12; | ||
637 | index_count++; | ||
638 | *(indicesp++) = 14; | ||
639 | index_count++; | ||
640 | *(indicesp++) = 13; | ||
641 | index_count++; | ||
642 | |||
643 | *(indicesp++) = 12; | ||
644 | index_count++; | ||
645 | *(indicesp++) = 13; | ||
646 | index_count++; | ||
647 | *(indicesp++) = 15; | ||
648 | index_count++; | ||
649 | |||
650 | // Generate geometry for the cylinders | ||
651 | |||
652 | // Different LOD's | ||
653 | |||
654 | // Generate the vertices | ||
655 | // Generate the indices | ||
656 | |||
657 | for (lod = 0; lod < 4; lod++) | ||
658 | { | ||
659 | slices = sLODSlices[lod]; | ||
660 | F32 base_radius = 0.65f; | ||
661 | F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper; | ||
662 | //llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl; | ||
663 | //llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl; | ||
664 | F32 angle = 0; | ||
665 | F32 angle_inc = 360.f/(slices-1); | ||
666 | F32 z = 0.f; | ||
667 | F32 z_inc = 1.f; | ||
668 | if (slices > 3) | ||
669 | { | ||
670 | z_inc = 1.f/(slices - 3); | ||
671 | } | ||
672 | F32 radius = base_radius; | ||
673 | |||
674 | F32 x1,y1; | ||
675 | F32 noise_scale = sSpeciesTable[mSpecies]->mNoiseMag; | ||
676 | LLVector3 nvec; | ||
677 | |||
678 | const F32 cap_nudge = 0.1f; // Height to 'peak' the caps on top/bottom of branch | ||
679 | |||
680 | const S32 fractal_depth = 5; | ||
681 | F32 nvec_scale = 1.f * sSpeciesTable[mSpecies]->mNoiseScale; | ||
682 | F32 nvec_scalez = 4.f * sSpeciesTable[mSpecies]->mNoiseScale; | ||
683 | |||
684 | F32 tex_z_repeat = sSpeciesTable[mSpecies]->mRepeatTrunkZ; | ||
685 | |||
686 | F32 start_radius; | ||
687 | F32 nangle = 0; | ||
688 | F32 height = 1.f; | ||
689 | F32 r0; | ||
690 | |||
691 | for (i = 0; i < slices; i++) | ||
692 | { | ||
693 | if (i == 0) | ||
694 | { | ||
695 | z = - cap_nudge; | ||
696 | r0 = 0.0; | ||
697 | } | ||
698 | else if (i == (slices - 1)) | ||
699 | { | ||
700 | z = 1.f + cap_nudge;//((i - 2) * z_inc) + cap_nudge; | ||
701 | r0 = 0.0; | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | z = (i - 1) * z_inc; | ||
706 | r0 = base_radius + (top_radius - base_radius)*z; | ||
707 | } | ||
708 | |||
709 | for (j = 0; j < slices; j++) | ||
710 | { | ||
711 | if (slices - 1 == j) | ||
712 | { | ||
713 | angle = 0.f; | ||
714 | } | ||
715 | else | ||
716 | { | ||
717 | angle = j*angle_inc; | ||
718 | } | ||
719 | |||
720 | nangle = angle; | ||
721 | |||
722 | x1 = cos(angle * DEG_TO_RAD); | ||
723 | y1 = sin(angle * DEG_TO_RAD); | ||
724 | LLVector2 tc; | ||
725 | // This isn't totally accurate. Should compute based on slope as well. | ||
726 | start_radius = r0 * (1.f + 1.2f*fabs(z - 0.66f*height)/height); | ||
727 | nvec.setVec( cos(nangle * DEG_TO_RAD)*start_radius*nvec_scale, | ||
728 | sin(nangle * DEG_TO_RAD)*start_radius*nvec_scale, | ||
729 | z*nvec_scalez); | ||
730 | // First and last slice at 0 radius (to bring in top/bottom of structure) | ||
731 | radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale; | ||
732 | |||
733 | if (slices - 1 == j) | ||
734 | { | ||
735 | // Not 0.5 for slight slop factor to avoid edges on leaves | ||
736 | tc = LLVector2(0.490f, (1.f - z/2.f)*tex_z_repeat); | ||
737 | } | ||
738 | else | ||
739 | { | ||
740 | tc = LLVector2((angle/360.f)*0.5f, (1.f - z/2.f)*tex_z_repeat); | ||
741 | } | ||
742 | |||
743 | *(vertices++) = LLVector3(x1*radius, y1*radius, z); | ||
744 | *(normals++) = LLVector3(x1, y1, 0.f); | ||
745 | *(tex_coords++) = tc; | ||
746 | vertex_count++; | ||
747 | } | ||
748 | } | ||
749 | |||
750 | for (i = 0; i < (slices - 1); i++) | ||
751 | { | ||
752 | for (j = 0; j < (slices - 1); j++) | ||
753 | { | ||
754 | S32 x1_offset = j+1; | ||
755 | if ((j+1) == slices) | ||
756 | { | ||
757 | x1_offset = 0; | ||
758 | } | ||
759 | // Generate the matching quads | ||
760 | *(indicesp) = j + (i*slices) + sLODVertexOffset[lod]; | ||
761 | llassert(*(indicesp) < (U32)max_vertices); | ||
762 | indicesp++; | ||
763 | index_count++; | ||
764 | *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod]; | ||
765 | llassert(*(indicesp) < (U32)max_vertices); | ||
766 | indicesp++; | ||
767 | index_count++; | ||
768 | *(indicesp) = j + ((i+1)*slices) + sLODVertexOffset[lod]; | ||
769 | llassert(*(indicesp) < (U32)max_vertices); | ||
770 | indicesp++; | ||
771 | index_count++; | ||
772 | |||
773 | *(indicesp) = j + (i*slices) + sLODVertexOffset[lod]; | ||
774 | llassert(*(indicesp) < (U32)max_vertices); | ||
775 | indicesp++; | ||
776 | index_count++; | ||
777 | *(indicesp) = x1_offset + (i*slices) + sLODVertexOffset[lod]; | ||
778 | llassert(*(indicesp) < (U32)max_vertices); | ||
779 | indicesp++; | ||
780 | index_count++; | ||
781 | *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod]; | ||
782 | llassert(*(indicesp) < (U32)max_vertices); | ||
783 | indicesp++; | ||
784 | index_count++; | ||
785 | } | ||
786 | } | ||
787 | slices /= 2; | ||
788 | } | ||
789 | |||
790 | llassert(vertex_count == max_vertices); | ||
791 | llassert(index_count == max_indices); | ||
792 | |||
793 | return TRUE; | ||
794 | } | ||
795 | |||
796 | void LLVOTree::drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha) | ||
797 | { | ||
798 | // | ||
799 | // Draws a tree by recursing, drawing branches and then a 'leaf' texture. | ||
800 | // If stop_level = -1, simply draws the whole tree as a billboarded texture | ||
801 | // | ||
802 | |||
803 | if (!draw_pool->getIndexCount()) | ||
804 | { | ||
805 | return; // safety net | ||
806 | } | ||
807 | |||
808 | static F32 constant_twist; | ||
809 | static F32 width = 0; | ||
810 | |||
811 | //F32 length = ((scale == 1.f)? mTrunkLength:mBranchLength); | ||
812 | //F32 aspect = ((scale == 1.f)? mTrunkAspect:mBranchAspect); | ||
813 | F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength); | ||
814 | F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect); | ||
815 | |||
816 | constant_twist = 360.f/branches; | ||
817 | |||
818 | if (stop_level >= 0) | ||
819 | { | ||
820 | // | ||
821 | // Draw the tree using recursion | ||
822 | // | ||
823 | if (depth > stop_level) | ||
824 | { | ||
825 | { | ||
826 | llassert(sLODIndexCount[trunk_LOD] > 0); | ||
827 | width = scale * length * aspect; | ||
828 | glPushMatrix(); | ||
829 | glScalef(width,width,scale * length); | ||
830 | //glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_INT, draw_pool.getRawIndices() + sLODIndexOffset[trunk_LOD]); | ||
831 | glDrawRangeElements(GL_TRIANGLES, | ||
832 | sLODVertexOffset[trunk_LOD], | ||
833 | sLODVertexOffset[trunk_LOD] + sLODVertexCount[trunk_LOD]-1, | ||
834 | sLODIndexCount[trunk_LOD], | ||
835 | GL_UNSIGNED_INT, | ||
836 | draw_pool->getRawIndices() + sLODIndexOffset[trunk_LOD]); | ||
837 | stop_glerror(); | ||
838 | draw_pool->addIndicesDrawn(sLODIndexCount[trunk_LOD]); | ||
839 | glPopMatrix(); | ||
840 | } | ||
841 | |||
842 | // Recurse to create more branches | ||
843 | for (S32 i=0; i < (S32)branches; i++) | ||
844 | { | ||
845 | glPushMatrix(); | ||
846 | glTranslatef(0.f, 0.f, scale * length); | ||
847 | glRotatef((constant_twist + ((i%2==0)?twist:-twist))*i, 0.f, 0.f, 1.f); | ||
848 | glRotatef(droop, 0.f, 1.f, 0.f); | ||
849 | glRotatef(20.f, 0.f, 0.f, 1.f); // rotate 20deg about axis of new branch to add some random variation | ||
850 | drawBranchPipeline(draw_pool, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha); | ||
851 | glPopMatrix(); | ||
852 | } | ||
853 | // Recurse to continue trunk | ||
854 | if (trunk_depth) | ||
855 | { | ||
856 | glPushMatrix(); | ||
857 | glTranslatef(0.f, 0.f, scale * length); | ||
858 | glRotatef(70.5f, 0.f, 0.f, 1.f); // rotate a bit around Z when ascending | ||
859 | drawBranchPipeline(draw_pool, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha); | ||
860 | glPopMatrix(); | ||
861 | } | ||
862 | } | ||
863 | else | ||
864 | { | ||
865 | // | ||
866 | // Draw leaves as two 90 deg crossed quads with leaf textures | ||
867 | // | ||
868 | { | ||
869 | glPushMatrix(); | ||
870 | //glRotatef(llFrand(50.0), llFrand(1.0), llFrand(1.0), llFrand(1.0); | ||
871 | //width = scale * (TREE_BRANCH_ASPECT + TREE_LEAF_ASPECT); | ||
872 | glScalef(scale*mLeafScale, scale*mLeafScale, scale*mLeafScale); | ||
873 | //glScalef(1.5f*width*mLeafScale,1,1.5f*scale*mLeafScale); | ||
874 | // glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, draw_pool.getRawIndices()); | ||
875 | glDrawRangeElements(GL_TRIANGLES, | ||
876 | 0, | ||
877 | LEAF_VERTICES-1, | ||
878 | LEAF_INDICES, | ||
879 | GL_UNSIGNED_INT, | ||
880 | draw_pool->getRawIndices()); | ||
881 | stop_glerror(); | ||
882 | draw_pool->addIndicesDrawn(LEAF_INDICES); | ||
883 | glPopMatrix(); | ||
884 | } | ||
885 | } | ||
886 | } | ||
887 | else | ||
888 | { | ||
889 | // | ||
890 | // Draw the tree as a single billboard texture | ||
891 | // | ||
892 | |||
893 | glMatrixMode(GL_TEXTURE); | ||
894 | glPushMatrix(); | ||
895 | glTranslatef(0.0, -0.5, 0.0); | ||
896 | glMatrixMode(GL_MODELVIEW); | ||
897 | { | ||
898 | glPushMatrix(); | ||
899 | glScalef(mBillboardScale*mBillboardRatio, mBillboardScale*mBillboardRatio, mBillboardScale); | ||
900 | // glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, draw_pool.getRawIndices()); | ||
901 | glDrawRangeElements(GL_TRIANGLES, | ||
902 | 0, | ||
903 | LEAF_VERTICES-1, | ||
904 | LEAF_INDICES, | ||
905 | GL_UNSIGNED_INT, | ||
906 | draw_pool->getRawIndices()); | ||
907 | stop_glerror(); | ||
908 | draw_pool->addIndicesDrawn(LEAF_INDICES); | ||
909 | glPopMatrix(); | ||
910 | } | ||
911 | glMatrixMode(GL_TEXTURE); | ||
912 | glPopMatrix(); | ||
913 | glMatrixMode(GL_MODELVIEW); | ||
914 | } | ||
915 | } | ||
916 | |||
917 | void LLVOTree::updateRadius() | ||
918 | { | ||
919 | if (mDrawable.isNull()) | ||
920 | { | ||
921 | return; | ||
922 | } | ||
923 | |||
924 | mDrawable->setRadius(32.0f); | ||
925 | } | ||