void STLModule::bounds(const js::Value &args, js::Sink &sink) { SmartPointer<js::Value> facets = args.get("stl")->get("facets"); Rectangle3F bounds; unsigned length = facets->length(); for (unsigned i = 0; i < length; i++) { SmartPointer<js::Value> facet = facets->get(i); for (unsigned j = 0; j < 3; j++) bounds.add(toVector3F(*facet->get(j))); } sink.beginList(); append(sink, bounds.getMin()); append(sink, bounds.getMax()); sink.endList(); }
void ParticleScene::DoTick( U32 deltaTime ) { for( int i=0; i<buttonArr.Size(); ++i ) { ToggleButton* toggle = buttonArr[i]->ToToggleButton(); if ( toggle && toggle->Down() ) { Vector3F pos = { SIZE/2, 0.01f, SIZE/2 }; Vector3F normal = { 0, 1, 0 }; //Vector3F dir = { 1, 0, 0 }; ParticleDef* def = &particleDefArr[i]; if ( def->spread == ParticleDef::SPREAD_POINT ) { engine->particleSystem->EmitPD( *def, pos, normal, deltaTime ); } else { Rectangle3F r; r.Set( pos.x-0.5f, pos.y, pos.z-0.5f, pos.x+0.5f, pos.y, pos.z+0.5f ); engine->particleSystem->EmitPD( *def, r, normal, deltaTime ); } } } }
Chit* LumosChitBag::NewItemChit( const grinliz::Vector3F& _pos, GameItem* orphanItem, bool fuzz, bool onGround, int selfDestructTimer ) { GLASSERT( !orphanItem->Intrinsic() ); GLASSERT( !orphanItem->IResourceName().empty() ); Vector3F pos = _pos; if ( fuzz ) { pos.x = floorf(pos.x) + random.Uniform(); pos.z = floorf(pos.z) + random.Uniform(); } Chit* chit = this->NewChit(); chit->Add( new ItemComponent( orphanItem )); chit->Add( new RenderComponent( orphanItem->ResourceName() )); chit->Add(new GameMoveComponent()); if ( onGround ) { const ModelResource* res = chit->GetRenderComponent()->MainResource(); Rectangle3F aabb = res->AABB(); pos.y = -aabb.min.y; if ( aabb.SizeY() < 0.1f ) { pos.y += 0.1f; } } chit->SetPosition( pos ); chit->Add( new HealthComponent()); if (!selfDestructTimer && orphanItem->keyValues.Has(ISC::selfDestruct)) { orphanItem->keyValues.Get("selfDestruct", &selfDestructTimer); selfDestructTimer *= 1000; } if ( selfDestructTimer ) { chit->Add( new CountDownScript( selfDestructTimer )); } return chit; }
void DecalMesh::SetPosV( const Vector3F& newPos, const Matrix4& _newRot ) { float zRot = _newRot.CalcRotationAroundAxis(2); zRot = NormalizeAngleDegrees( zRot ); Matrix4 newRot; newRot.SetZRotation( zRot ); // We don't need to ask the container (the TerrainMesh) where we // will be, since the decal is patched to the terrain. if ( newPos.x != pos.x || newPos.y != pos.y || newRot != rotation || !InList() ) { pos = newPos; rotation = newRot; Rectangle3F base; base.Set( -size / 2.0f, -size / 2.0f, (TERRAIN_MIN+0.01f), size / 2.0f, size / 2.0f, (TERRAIN_MAX-0.01f) ); if ( InList() ) ListRemove(); ComputeTransform(); CalcAABB( base ); Lilith3D::Instance()->GetQuadTree()->AddMesh( this ); // Compute the texture matrix for this decal. Matrix4 center, inverse, scale; Transform().Invert( &inverse ); // position the texture with the mesh center.SetTranslation( 0.5f, 0.5f, 0.5f ); // center the decal scale.SetScale( 1.0f / size ); texMat = center * scale * inverse; } }
int grinliz::IntersectRayAllAABB( const Vector3F& origin, const Vector3F& dir, const Rectangle3F& aabb, int* inTest, Vector3F* inIntersect, int *outTest, Vector3F* outIntersect ) { // Could be more efficient, but looking for simplicity as I write this. float t; // First check if we hit the box at all, and that establishes in test. *inTest = IntersectRayAABB( origin, dir, aabb, inIntersect, &t ); if ( *inTest == grinliz::REJECT ) { *outTest = grinliz::REJECT; return grinliz::REJECT; } // Could get fancy and intersect from the inside. But that's hard, so I'll run // the ray out and shoot it backwards. float deltaLen = aabb.SizeX() + aabb.SizeY() + aabb.SizeZ(); Vector3F dirNormal = dir; dirNormal.Normalize(); Vector3F invOrigin = origin + dir*deltaLen; Vector3F invDir = -dirNormal; *outTest = IntersectRayAABB( invOrigin, invDir, aabb, outIntersect, &t ); GLASSERT( *outTest != grinliz::INSIDE ); // bad algorith. if ( *outTest == grinliz::REJECT ) { // some strange floating point thing. Hit a corner. Reject everything. *inTest = grinliz::REJECT; return grinliz::REJECT; } return grinliz::INTERSECT; }
Model* SpaceTree::QueryRay( const Vector3F& _origin, const Vector3F& _direction, int required, int excluded, const Model** ignore, HitTestMethod testType, Vector3F* intersection ) { //GLOUTPUT(( "query ray\n" )); modelRoot = 0; nodesVisited = 0; modelsFound = 0; requiredFlags = required; excludedFlags = excluded | Model::MODEL_HIDDEN_FROM_TREE; ++queryID; Vector3F dummy; if ( !intersection ) { intersection = &dummy; } Vector3F dir = _direction; dir.Normalize(); Rectangle3F aabb; aabb.min.Set( 0, yMin, 0 ); aabb.max.Set( Map::SIZE, yMax, Map::SIZE ); // Where does this ray enter and leave the spaceTree? // It enters at 'p0' and leaves at 'p1' int p0Test, p1Test; Vector3F p0, p1; int test = IntersectRayAllAABB( _origin, dir, aabb, &p0Test, &p0, &p1Test, &p1 ); if ( test != grinliz::INTERSECT ) { // Can click outside of AABB pretty commonly, actually. return 0; } Plane planes[6]; Rectangle3F rect; rect.FromPair( p0, p1 ); Plane::CreatePlanes( rect, planes ); Model* modelRoot = Query( planes, 6, required, excluded ); // We now have a batch of models. Are any of them a hit?? GLASSERT( testType == TEST_HIT_AABB || testType == TEST_TRI ); float close = FLT_MAX; Model* closeModel = 0; Vector3F testInt; float t; for( Model* root=modelRoot; root; root=root->next ) { if ( Ignore( root, ignore ) ) continue; //GLOUTPUT(( "Consider: %s\n", root->GetResource()->header.name )); int result = grinliz::REJECT; if ( testType == TEST_HIT_AABB ) { Rectangle3F modelAABB; root->CalcHitAABB( &modelAABB ); result = IntersectRayAABB( p0, dir, modelAABB, &testInt, &t ); } else if ( testType == TEST_TRI ) { t = FLT_MAX; result = root->IntersectRay( p0, dir, &testInt ); if ( result == grinliz::INTERSECT ) { Vector3F delta = p0 - testInt; t = delta.LengthSquared(); //GLOUTPUT(( "Hit: %s t=%.2f\n", root->GetResource()->header.name, t )); } } if ( result == grinliz::INTERSECT ) { // Ugly little bug: check for t>=0, else could collide with objects // that touch the bounding box but are before the ray starts. if ( t >= 0.0f && t < close ) { closeModel = root; *intersection = testInt; close = t; } } } if ( closeModel ) { return closeModel; } return 0; }
Lilith3D::Lilith3D( U32 msecPerDay, U32 msecStart ) : timeClock( msecPerDay, msecStart ), pointLightSentinel( InnerCircle<PointLight>::SENTINEL ) { int viewPort[4]; glGetIntegerv(GL_VIEWPORT, viewPort); surfaceWidth = viewPort[2]-viewPort[0]; surfaceHeight = viewPort[3]-viewPort[1]; InitShadows(); instance = this; displayPerfData = false; infoDisplay = INFO_DEFAULT; renderMode = RENDER_FLAT; mapSize = 0.0f; targetMapSize = 0.0f; // Lilith doesn't have a performance meauring system (yet), so // use the shader flag as a performance measure for now. bool powerful = ShaderManager::Instance()->PowerFragments(); renderFoliage = powerful; renderShadows = true; // I like the shadows too much to default them off Rectangle3F bounds; bounds.Set( 0.0f, 0.0f, TERRAIN_MIN, (float) MAPSIZE, (float) MAPSIZE, WORLD_CEILING ); terrainMesh = new TerrainMesh(); quadTree = new QuadTree(); // quadtree depends on the terrain, construct 2nd camera.SetCamera( 20.0f, 0.0f, 32.0f, 55.0f, 23.0f ); //camera.SetCamera( 20.0f, 0.0f, 32.0f, 0.0f, 0.0f, 0.0f ); sequenceStart = 0; sequenceLength = 0; // ------- Set up the perspective ----------- GLfloat ratio; ratio = ( float )surfaceWidth / ( float )surfaceHeight; glViewport( 0, 0, surfaceWidth, surfaceHeight ); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); // The further the near plane can be pushed out, the better the resolution // that can be obtained. gluPerspective( VIEW_ANGLE, ratio, 1.0f, FAR_PLANE_DISTANCE ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); terrainDecor = new TerrainDecor(); gravityParticles = new GravParticles(); rainDropParticles = new RainDropParticles(); rainSplashParticles = new RainSplashParticles(); RegisterParticleSystem( gravityParticles ); RegisterParticleSystem( rainDropParticles ); RegisterParticleSystem( rainSplashParticles ); GLLOG(( "Sizeof Vertex=%d\n", sizeof( Vertex ) )); }
int grinliz::IntersectionRayAABB( const Ray& ray, const Rectangle3F& aabb, Rectangle3F* result ) { bool hasStart = false; bool hasEnd = false; Vector3F start, end; GLASSERT( Equal( ray.direction.Length(), 1.0f, 0.001f ) ); if ( aabb.Contains( ray.origin ) ) { hasStart = true; start = ray.origin; } // Check for an intersection with each face. If t>0 and it is a // positive dot then it is an 'end'. If t>0 and it is a negative // dot, then it is a 'start'. Vector3F at; float t; for( int k=0; k<=1; ++k ) { Vector3F originToPlane; if ( k == 0 ) { // min originToPlane.Set( aabb.min.x - ray.origin.x, aabb.min.y - ray.origin.y, aabb.min.z - ray.origin.z ); } else { // max originToPlane.Set( aabb.max.x - ray.origin.x, aabb.max.y - ray.origin.y, aabb.max.z - ray.origin.z ); } for ( int i=0; i<3 && !(hasEnd && hasStart); ++i ) { int i1 = (i + 1)%3; int i2 = (i + 2)%3; Vector3F planeNormal = { 0.0f, 0.0f, 0.0f }; planeNormal.X(i) = ( k == 0 ) ? -1.0f : 1.0f; float dot = DotProduct( originToPlane, planeNormal ); int hit = IntersectRayAAPlane( ray.origin, ray.direction, i, (k==0) ? aabb.min.X(i) : aabb.max.X(i), &at, &t ); if ( hit == INTERSECT && t > 0.0f && InRange( at.X(i1), aabb.min.X(i1), aabb.max.X(i1) ) && InRange( at.X(i2), aabb.min.X(i2), aabb.max.X(i2) ) ) { // We have hit a face of the AABB if ( dot > 0.0f ) { GLASSERT( !hasEnd ); hasEnd = true; if ( t > ray.length ) end = ray.origin + ray.direction*t; else end = at; } else if ( dot < 0.0f ) { GLASSERT( !hasStart ); hasStart = true; if ( t > ray.length ) { return REJECT; // the start never gets to the AABB } start = at; } } } } if( !hasStart || !hasEnd ) { return REJECT; } for( int i=0; i<3; ++i ) { result->min.X(i) = Min( start.X(i), end.X(i) ); result->max.X(i) = Max( start.X(i), end.X(i) ); } return INTERSECT; }