uint32_t hsQueueStream::Write(uint32_t byteCount, const void* buffer) { hsAssert(fWriteCursor >= 0 && fWriteCursor < fSize,"hsQueueStream: WriteCursor out of range."); hsAssert(fReadCursor >= 0 && fReadCursor < fSize,"hsQueueStream: ReadCursor out of range."); int32_t length; length = hsMinimum(fSize-fWriteCursor,byteCount); HSMemory::BlockMove(buffer,fQueue+fWriteCursor,length); if (fReadCursor > fWriteCursor) { #if 0 if (fReadCursor < fWriteCursor+length+1) hsStatusMessage("ReadCursor wrapped\n"); #endif fReadCursor = hsMaximum(fReadCursor,fWriteCursor+length+1); fReadCursor %= fSize; } fWriteCursor += length; fWriteCursor %= fSize; if (length < byteCount) { Write(byteCount - length,static_cast<const char*>(buffer)+length); } return byteCount; }
void plSimulationMgr::ConsiderSynch(plPXPhysical* physical, plPXPhysical* other) { if (physical->GetProperty(plSimulationInterface::kNoSynchronize) && (!other || other->GetProperty(plSimulationInterface::kNoSynchronize))) return; // We only need to sync if a dynamic is colliding with something. // Set it up so the dynamic is in 'physical' if (other && other->GetGroup() == plSimDefs::kGroupDynamic) { plPXPhysical* temp = physical; physical = other; other = temp; } // Neither is dynamic, so we can exit now else if (physical->GetGroup() != plSimDefs::kGroupDynamic) return; bool syncPhys = !physical->GetProperty(plSimulationInterface::kNoSynchronize) && physical->IsDynamic() && physical->IsLocallyOwned(); bool syncOther = other && !other->GetProperty(plSimulationInterface::kNoSynchronize) && other->IsDynamic() != 0.f && other->IsLocallyOwned(); if (syncPhys) { double timeNow = hsTimer::GetSysSeconds(); double timeElapsed = timeNow - physical->GetLastSyncTime(); // If both objects are capable of syncing, we want to do it at the same // time, so no interpenetration issues pop up on other clients if (syncOther) timeElapsed = hsMaximum(timeElapsed, timeNow - other->GetLastSyncTime()); // Set the sync time to 1 second from the last sync double syncTime = 0.0; if (timeElapsed > 1.0) syncTime = hsTimer::GetSysSeconds(); else syncTime = hsTimer::GetSysSeconds() + (1.0 - timeElapsed); // This line will create and insert the request if it's not there already. SynchRequest& physReq = fPendingSynchs[physical]; if (physReq.fTime == SynchRequest::kDefaultTime) physReq.fKey = physical->GetKey(); physReq.fTime = syncTime; if (syncOther) { SynchRequest& otherReq = fPendingSynchs[other]; if (otherReq.fTime == SynchRequest::kDefaultTime) otherReq.fKey = other->GetKey(); otherReq.fTime = syncTime; } } }
static void MakeBoxFromHull(NxConvexMesh* convexMesh, NxBoxShapeDesc& box) { NxConvexMeshDesc desc; convexMesh->saveToDesc(desc); float minX, minY, minZ, maxX, maxY, maxZ; minX = minY = minZ = FLT_MAX; maxX = maxY = maxZ = -FLT_MAX; for (int i = 0; i < desc.numVertices; i++) { float* point = (float*)(((char*)desc.points) + desc.pointStrideBytes*i); float x = point[0]; float y = point[1]; float z = point[2]; minX = hsMinimum(minX, x); minY = hsMinimum(minY, y); minZ = hsMinimum(minZ, z); maxX = hsMaximum(maxX, x); maxY = hsMaximum(maxY, y); maxZ = hsMaximum(maxZ, z); } float xWidth = maxX - minX; float yWidth = maxY - minY; float zWidth = maxZ - minZ; box.dimensions.x = xWidth / 2; box.dimensions.y = yWidth / 2; box.dimensions.z = zWidth / 2; //hsMatrix44 mat; //box.localPose.getRowMajor44(&mat.fMap[0][0]); hsPoint3 trans(minX + (xWidth / 2), minY + (yWidth / 2), minZ + (zWidth / 2)); //mat.SetTranslate(&trans); //box.localPose.setRowMajor44(&mat.fMap[0][0]); hsMatrix44 boxL2W; boxL2W.Reset(); boxL2W.SetTranslate(&trans); plPXConvert::Matrix(boxL2W, box.localPose); }
hsBool plViewTransform::Union(const plViewTransform& view) { hsPoint3 mins; hsPoint3 maxs; int i; for( i = 0; i < 3; i++ ) { mins[i] = hsMinimum(fMin[i], view.fMin[i]); maxs[i] = hsMaximum(fMax[i], view.fMax[i]); } SetView(mins, maxs); return true; }
hsBool plViewTransform::Intersect(const plViewTransform& view) { hsPoint3 mins; hsPoint3 maxs; hsBool retVal = true; int i; for( i = 0; i < 3; i++ ) { mins[i] = hsMaximum(fMin[i], view.fMin[i]); maxs[i] = hsMinimum(fMax[i], view.fMax[i]); if( mins[i] >= maxs[i] ) { mins[i] = maxs[i] = (mins[i] + maxs[i]) * 0.5f; retVal = false; } } SetView(mins, maxs); return retVal; }
bool plDistributor::IFailsProbBitmap(int iFace, const Point3& bary) const { // If we don't have a probability map, or we don't have // valid coordinates into it, just return false. That is, // with no valid probability map, everything goes. int uvwChan = 1; Matrix3 uvtrans(true); Bitmap* bm = nil; UINT filtType = BMM_FILTER_PYRAMID; if( fProbBitmapTex ) { uvwChan = fProbBitmapTex->GetMapChannel(); fProbBitmapTex->GetUVTransform(uvtrans); bm = fProbBitmapTex->GetBitmap(TimeValue(0)); if( bm && !bm->HasFilter() ) { switch( fProbBitmapTex->GetFilterType() ) { default: case FILTER_PYR: filtType = BMM_FILTER_PYRAMID; break; case FILTER_SAT: filtType = BMM_FILTER_SUM; break; case FILTER_NADA: filtType = BMM_FILTER_NONE; break; } } } else if( fProbLayerTex ) { uvwChan = fProbLayerTex->GetMapChannel(); fProbLayerTex->GetUVTransform(uvtrans); bm = fProbLayerTex->GetBitmap(TimeValue(0)); } if( !bm ) return false; if( !bm->HasFilter() ) bm->SetFilter(filtType); bm->PrepareGChannels(&bm->Storage()->bi); if( !fSurfMesh->mapSupport(uvwChan) ) return false; if( !fSurfMesh->mapFaces(uvwChan) || !fSurfMesh->mapVerts(uvwChan) ) return false; // Lookup the appropriate texel value Point3 uvw; uvw = fSurfMesh->mapVerts(uvwChan)[fSurfMesh->mapFaces(uvwChan)[iFace].getTVert(0)] * bary[0]; uvw += fSurfMesh->mapVerts(uvwChan)[fSurfMesh->mapFaces(uvwChan)[iFace].getTVert(1)] * bary[1]; uvw += fSurfMesh->mapVerts(uvwChan)[fSurfMesh->mapFaces(uvwChan)[iFace].getTVert(2)] * bary[2]; uvw = uvw * uvtrans; float fu = uvw.x - int(uvw.x); if( fu < 0 ) fu += 1.f; float fv = 1.0f - (uvw.y - int(uvw.y)); if( fv < 0 ) fv += 1.f; float du = 1.f / bm->Width(); float dv = 1.f / bm->Height(); BMM_Color_fl evCol; bm->GetFiltered(fu, fv, du, dv, &evCol); float frac; switch( fProbColorChan ) { case kRed: frac = evCol.r; break; case kGreen: frac = evCol.g; break; case kBlue: frac = evCol.b; break; case kAlpha: frac = evCol.a; break; case kAverageRedGreen: frac = (evCol.r + evCol.g) / 2.f; break; case kAverageRedGreenTimesAlpha: frac = (evCol.r + evCol.g) / 2.f * evCol.a; break; case kAverage: frac = (evCol.r + evCol.g + evCol.b ) / 3.f; break; case kAverageTimesAlpha: frac = (evCol.r + evCol.g + evCol.b ) / 3.f * evCol.a; break; case kMax: case kMaxColor: frac = hsMaximum(evCol.r, hsMaximum(evCol.g, evCol.b)); break; case kMaxColorTimesAlpha: frac = hsMaximum(evCol.r, hsMaximum(evCol.g, evCol.b)) * evCol.a; break; case kMaxRedGreen: frac = hsMaximum(evCol.r, evCol.g); break; case kMaxRedGreenTimesAlpha: frac = hsMaximum(evCol.r, evCol.g) * evCol.a; break; } if( fProbRemapFromHi != fProbRemapFromLo ) frac = fProbRemapToLo + (frac - fProbRemapFromLo) / (fProbRemapFromHi - fProbRemapFromLo) * (fProbRemapToHi - fProbRemapToLo); else frac = frac > fProbRemapFromHi ? fProbRemapToHi : fProbRemapToLo; return frac < fRand.RandZeroToOne(); }
hsBool plDynaRippleVSMgr::IRippleFromShape(const plPrintShape* shape, hsBool force) { if( !ICheckRTMat() ) return false; if( !shape ) return false; hsBool retVal = false; plDynaDecalInfo& info = IGetDecalInfo(uintptr_t(shape), shape->GetKey()); const hsMatrix44& shapeL2W = shape->GetOwner()->GetLocalToWorld(); plConst(float) kMinDist(2.0f); plConst(float) kMinTime(1.5f); double t = hsTimer::GetSysSeconds(); float dt = float(t - info.fLastTime) * sRand.RandZeroToOne(); hsBool longEnough = (dt >= kMinTime); hsPoint3 xlate = shapeL2W.GetTranslate(); hsBool farEnough = (hsVector3(&info.fLastPos, &xlate).Magnitude() > kMinDist); if( force || longEnough || farEnough ) { hsPoint3 pos = shapeL2W.GetTranslate(); // We'll perturb the position a little so it doesn't look quite so regular, // but we perturb it more if we're just standing still hsVector3 randPert(sRand.RandMinusOneToOne(), sRand.RandMinusOneToOne(), 0); randPert.Normalize(); if( !farEnough ) { plConst(float) kRandPert = 0.5f; randPert *= kRandPert; } else { plConst(float) kRandPert = 0.15f; randPert *= kRandPert; } pos += randPert; // Are we potentially touching the water? float waterHeight = fWaveSetBase->GetHeight(); if( (pos.fZ - fScale.fZ * shape->GetHeight() < waterHeight) &&(pos.fZ + fScale.fZ * shape->GetHeight() > waterHeight) ) { hsVector3 dir(fWaveSetBase->GetWindDir()); hsVector3 up(0.f, 0.f, 1.f); float wid = hsMaximum(shape->GetWidth(), shape->GetLength()); plConst(float) kMaxWaterDepth(1000.f); hsVector3 size(wid * fScale.fX, wid * fScale.fY, kMaxWaterDepth); fCutter->SetLength(size); fCutter->Set(pos, dir, up); hsBool hit = ICutoutTargets(t); if( hit ) { info.fLastTime = t; info.fLastPos = shapeL2W.GetTranslate(); retVal = true; } else { retVal = false; // No-effect else just for break points. } } } return retVal; }
void TimeBasedAvgRing<T>::AddItem(T value, double time) { std::lock_guard<std::mutex> lock(fLock); if ( fList.empty() ) { // initialize with the first time and zero the first value fList.insert(fList.end(),Item<T>(0.0,time)); fRingStart = fRingEnd = fList.begin(); fAvg = (float)value; } else { // if we're within the percision amount subtract the RingEnd value from total // and update the RingEnd value by adding the current value to it if (time - (*fRingEnd).GetTime() <= kPercision) { fTotal -= PercisionRoundUp((*fRingEnd).GetValue()); (*fRingEnd).SetValue((*fRingEnd).GetValue() + value); } else { // clean up the begining of the ring //// there can be some precision loss in the loop time calc //// check to see if the difference is within 1 milli while (time - (*fRingStart).GetTime() > fLen + kPercision && fRingStart != fRingEnd) { // remove RingStart from the avg part of the average calc fTotal -= (*fRingStart).GetValue(); typename TimeList::iterator prev = fRingStart++; // loop the ring if needed if (fRingStart == fList.end()) fRingStart = fList.begin(); // if the new ring start is in the range, interpolate // and reuse prev if (time - (*fRingStart).GetTime() < fLen) { // remove RingStart from the avg part of the average calc fTotal -= PercisionRoundUp((*fRingStart).GetValue()); // Set up the interp double remainder = fLen - (time - (*fRingStart).GetTime()); double timedelta = (*fRingStart).GetTime() - (*prev).GetTime(); (*prev).SetTime((*fRingStart).GetTime() - remainder); (*prev).SetValue(0); // rounding loss occurs here if T is not floting point double scale = remainder/timedelta; hsAssert(scale < 1.0 && scale > 0.0,"Interp Scale Out of Bounds"); (*fRingStart).SetValue((float)((*fRingStart).GetValue() * scale)); // add the new value in fTotal += (*fRingStart).GetValue(); // put prev back as ring start fRingStart = prev; } } // zero total & fAvg if we looped or neg if (fRingStart == fRingEnd || fTotal < 0.0) { fTotal = 0.0; fAvg = 0.0; } // put the new value in the ring by expanding the ring if needed // or replacing an empty value fRingEnd++; if (fRingEnd == fList.end()) fRingEnd = fList.begin(); // Do we have free space? if (fRingEnd == fRingStart) { // no free space fList.insert(fRingEnd,Item<T>(value,time)); fRingEnd--; } else { // yes free space @ fRingEnd (*fRingEnd) = Item<T>(value,time); } } //update the avg fTotal += (*fRingEnd).GetValue(); double currentLen = (*fRingEnd).GetTime() - (*fRingStart).GetTime(); if (currentLen < 1.0) fAvg = (float)fTotal; else fAvg = (float)(fTotal / currentLen); } // update the max avg fMaxAvg = hsMaximum( fMaxAvg, fAvg ); }
void plProfileManagerFull::Update() { if (fLogStats) ILogStats(); // // Print the groups we're showing // int maxX = 0; int y = 10; GroupSet::iterator it; for (it = fShowGroups.begin(); it != fShowGroups.end(); it++) { plString groupName = *it; std::vector<plProfileBase*> group; for (int i = 0; i < fVars.size(); i++) if (groupName.Compare(fVars[i]->GetGroup()) == 0) group.push_back(fVars[i]); int x = 10; PrintGroup(group, groupName.c_str(), x, y); maxX = hsMaximum(maxX, x); y += 10; } // // Print the laps we're showing // if (fShowLaps && fShowLaps->GetLaps()) { plProfileLaps* laps = fShowLaps->GetLaps(); std::vector<plProfileBase*> group; int numLaps = laps->GetNumLaps(); if(numLaps < fMinLap) fMinLap = 0; for (int i = 0; i < numLaps; i++) { if(i >= fMinLap && i < (fMinLap + 40)) group.push_back(laps->GetLap(i)); } y = 10; char buf[256]; sprintf(buf, "%s - %s", fShowLaps->GetGroup(), fShowLaps->GetName()); PrintLapGroup(group, buf, maxX, y, fMinLap); } // // Update the graphs // float size = 0.25; float xPos = 1 - size / 2; float yPos = -1 + size / 2; for (int i = 0; i < fGraphs.size(); i++) { plGraphPlate* graph = fGraphs[i]; plProfileVar* var = IFindTimer(graph->GetTitle()); if (var) { graph->SetPosition(xPos, yPos); graph->AddData(var->GetValue()); graph->SetVisible(true); yPos += size; } } UpdateStandardGraphs(xPos, yPos); float detailSize = 0.9; float detailX = 1 - detailSize / 2; float detailY = 1 - detailSize / 2; if (fDetailGraph) { fDetailGraph->SetPosition(detailX,detailY); double value; double scale; int i; std::vector<int32_t> values; for (i=0; i<fDetailVars.size(); i++) { value = (double)fDetailVars[i].var->GetValue(); scale = 100.0/((double)(fDetailVars[i].max-fDetailVars[i].min)); value = scale*value-fDetailVars[i].min; values.push_back((int32_t)value); } fDetailGraph->AddData(values); fDetailGraph->SetVisible(true); } }
static void PrintColumn(ProfileGroup& group, const char* groupName, int column, int x, int y, int& width, int& height, int off =0) { plDebugText& txt = plDebugText::Instance(); int yInc = txt.GetFontHeight() + 2; height = 0; width = 0; width = hsMaximum(width, txt.CalcStringWidth(groupName) + 1); txt.DrawString(x, y+height, groupName, 255, 255, 255, 255, plDebugText::kStyleBold); height += yInc; uint32_t samplesWidth = txt.CalcStringWidth("[000]"); for (int i = 0; i < group.size(); i++) { char str[1024]; switch (column) { case kColName: strcpy(str, group[i]->GetName()); // Since we don't draw the samples text for stats that only have 1 sample, // if the stat with the longest name is fluctuating between 1 and more than // 1 sample the width of the column will jump around. So we calculate the // width based on the stat name plus the width of the widest sample we should // get width = hsMaximum(width, txt.CalcStringWidth(str) + samplesWidth + 1); // Now add on the samples text, if we have any if (group[i]->GetTimerSamples()) { char cnt[20]; sprintf(cnt, "[%d]", group[i]->GetTimerSamples()); strcat(str, cnt); } break; case kColValue: group[i]->PrintValue(str); break; case kColAvg: group[i]->PrintAvg(str); break; case kColMax: group[i]->PrintMax(str); break; case kColIndex: sprintf(str,"[%3d]",i+off); break; } txt.DrawString(x, y+height, str); if (column != kColName) width = hsMaximum(width, txt.CalcStringWidth(str) + 1); height += yInc; } // So the columns don't jump around as much as values change, pad them out to a certain width width = hsMaximum(width, txt.CalcStringWidth("000.0 ms") + 1); }
hsVectorStream* plPhysXCooking::IMakePolytope(const plMaxMeshExtractor::NeutralMesh& inMesh) { hsBool success=0; std::vector<hsPoint3> outCloud; hsPoint3 offset; int numPlanes=26; float planeMax[26]; int indexMax[26]; hsPoint3 AABBMin(FLT_MAX,FLT_MAX,FLT_MAX); hsPoint3 AABBMax(-FLT_MAX,-FLT_MAX,-FLT_MAX); //prep NxVec3* vectors = new NxVec3[26]; int curvec=0; for(int xcomp= -1;xcomp<2;xcomp++) { for(int ycomp= -1;ycomp<2;ycomp++) { for(int zcomp= -1;zcomp<2;zcomp++) { if(!((xcomp==0)&&(ycomp==0)&&(zcomp==0))) { vectors[curvec].set((float)(xcomp),(float)(ycomp),(float)(zcomp)); vectors[curvec].normalize(); planeMax[curvec]=(-FLT_MAX); //indexMax[curvec]=0; curvec++; } } } } /* for(int i=0;i<26;i++) {//make your max and mins planeMax[i]=(-FLT_MAX); } */ hsPoint3 centroid(0.0f,0.0f,0.0f); for(int i=0;i<inMesh.fNumVerts;i++) centroid+=inMesh.fVerts[i]; centroid=centroid/(float)inMesh.fNumVerts; //temp NxVec3* nxLocs=new NxVec3[inMesh.fNumVerts]; NxVec3* nxLocs2=new NxVec3[inMesh.fNumVerts]; for(int i=0;i<inMesh.fNumVerts;i++) { hsPoint3 temppt=inMesh.fVerts[i] - centroid; nxLocs[i]=plPXConvert::Point(temppt); } NxMat33 rot; NxVec3 eigen; PCA(nxLocs,inMesh.fNumVerts,rot); NxMat33 invrot; rot.getInverse(invrot); for(int i=0; i<inMesh.fNumVerts;i++) { nxLocs2[i]=invrot*nxLocs[i]; } for(int i=0;i<inMesh.fNumVerts;i++) { for(int plane=0;plane<26;plane++) { float dist=nxLocs2[i].dot(vectors[plane]); if(dist>=planeMax[plane]) { planeMax[plane]=dist; indexMax[plane]=i; } } } for(int i=0;i<inMesh.fNumVerts;i++) { AABBMin.fX = hsMinimum(nxLocs2[i].x, AABBMin.fX); AABBMin.fY = hsMinimum(nxLocs2[i].y, AABBMin.fY); AABBMin.fZ = hsMinimum(nxLocs2[i].z, AABBMin.fZ); AABBMax.fX = hsMaximum(nxLocs2[i].x, AABBMax.fX); AABBMax.fY = hsMaximum(nxLocs2[i].y, AABBMax.fY); AABBMax.fZ = hsMaximum(nxLocs2[i].z, AABBMax.fZ); } int resultingPoints=0; for(int i=0;i<26;i++) { for(int j=0;j<26;j++) { for(int k=0;k<26;k++) { NxVec3 res; if(ThreePlaneIntersect(vectors[i],nxLocs2[indexMax[i]],vectors[j],nxLocs2[indexMax[j]], vectors[k],nxLocs2[indexMax[k]],res)) { //check it is within all slabs bool within=true; int curplane=0; do { float intersecdist=res.dot(vectors[curplane]); if((intersecdist-planeMax[curplane])>0.0001) { within=false; } curplane++; } while((curplane<26)&&within); if(within) // if((res.x>=AABBMin.fX)&&(res.x<=AABBMax.fX)&& // (res.y>=AABBMin.fY)&&(res.y<=AABBMax.fY)&& // (res.z>=AABBMin.fZ)&&(res.z<=AABBMax.fZ)) { NxVec3 reverted; reverted=rot*res; reverted.x=reverted.x +centroid.fX; reverted.y=reverted.y +centroid.fY; reverted.z=reverted.z +centroid.fZ; hsPoint3 out; out=plPXConvert::Point(reverted); outCloud.push_back(out); } } } } } //planes discovered //this is'nt right //cleanup offset=centroid; delete[] vectors; hsPoint3* pointages=new hsPoint3[outCloud.size()]; for(int x=0;x<outCloud.size();x++)pointages[x]=outCloud[x]; hsVectorStream* vectorstrm; vectorstrm= CookHull(outCloud.size(),pointages,true); delete[] pointages; delete[] nxLocs; delete[] nxLocs2; return vectorstrm; }
void plNetClientMgr::IShowRelevanceRegions() { plDebugText& txt = plDebugText::Instance(); const int yOff = 12, xOff = 20, startY=70, startX=10; int x = startX, y = startY; const char* title = "Name / In / Care"; txt.DrawString(x, y - yOff, title, 255, 255, 255, 255, plDebugText::kStyleBold); plNetTransportMember** members = nil; fTransport.GetMemberListDistSorted(members); // // Print out the player names in the first column // uint32_t maxPlayerName = 0; txt.DrawString(x, y, GetPlayerName().c_str()); maxPlayerName = hsMaximum(maxPlayerName, txt.CalcStringWidth(GetPlayerName().c_str())); y += yOff; int i; for (i = 0; i < fTransport.GetNumMembers(); i++) { plNetTransportMember* mbr = members[i]; hsAssert(mbr, "ShowLists: nil member?"); if (mbr->IsServer()) continue; const plString& name = mbr->GetPlayerName(); txt.DrawString(x, y, name.c_str()); maxPlayerName = hsMaximum(maxPlayerName, txt.CalcStringWidth(name.c_str())); y += yOff; } x = startX + maxPlayerName + xOff; y = startY; // // Print out the regions // const hsBitVector* ourCare = nil; const hsBitVector* ourIn = nil; plSceneObject* player = plSceneObject::ConvertNoRef(GetLocalPlayer()); if (player) { const plArmatureMod *avMod = plArmatureMod::ConvertNoRef(player->GetModifierByType(plArmatureMod::Index())); if (avMod) { ourIn = &avMod->GetRelRegionImIn(); uint32_t width = IPrintRelRegion(*ourIn, x, y, nil); ourCare = &avMod->GetRelRegionCareAbout(); IPrintRelRegion(*ourCare, x + width + xOff, y, nil); y += yOff; } } for (i = 0; i < fTransport.GetNumMembers(); i++) { plNetTransportMember* mbr = members[i]; if (mbr->IsServer()) continue; player = (mbr->GetAvatarKey() ? plSceneObject::ConvertNoRef(mbr->GetAvatarKey()->ObjectIsLoaded()) : nil); if (player) { const plArmatureMod* avMod = plArmatureMod::ConvertNoRef(player->GetModifierByType(plArmatureMod::Index())); if (avMod) { const hsBitVector& in = avMod->GetRelRegionImIn(); uint32_t width = IPrintRelRegion(in, x, y, ourCare); const hsBitVector& care = avMod->GetRelRegionCareAbout(); IPrintRelRegion(care, x + width + xOff, y, ourIn); y += yOff; } } } delete [] members; }