BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_CLOUDS); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS))) { return TRUE; } dirtySpatialGroup(); LLFace *facep; S32 num_faces = mCloudGroupp->getNumPuffs(); if (num_faces > drawable->getNumFaces()) { drawable->setNumFacesFast(num_faces, NULL, getTEImage(0)); } mDepth = (getPositionAgent()-LLViewerCamera::getInstance()->getOrigin())*LLViewerCamera::getInstance()->getAtAxis(); S32 face_indx = 0; for ( ; face_indx < num_faces; face_indx++) { facep = drawable->getFace(face_indx); if (!facep) { llwarns << "No facep for index " << face_indx << llendl; continue; } facep->setSize(4, 6); facep->setTEOffset(face_indx); facep->setTexture(getTEImage(0)); const LLCloudPuff &puff = mCloudGroupp->getPuff(face_indx); const LLVector3 puff_pos_agent = gAgent.getPosAgentFromGlobal(puff.getPositionGlobal()); facep->mCenterLocal = puff_pos_agent; /// Update cloud color based on sun color. LLColor4 float_color(LLColor3(gSky.getSunDiffuseColor() + gSky.getSunAmbientColor()),puff.getAlpha()); facep->setFaceColor(float_color); } for ( ; face_indx < drawable->getNumFaces(); face_indx++) { facep = drawable->getFace(face_indx); if (!facep) { llwarns << "No facep for index " << face_indx << llendl; continue; } facep->setTEOffset(face_indx); facep->setSize(0,0); } drawable->movePartition(); return TRUE; }
BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(FTM_UPDATE_PARTICLES); dirtySpatialGroup(); S32 num_parts = mViewerPartGroupp->getCount(); LLFace *facep; LLSpatialGroup* group = drawable->getSpatialGroup(); if (!group && num_parts) { drawable->movePartition(); group = drawable->getSpatialGroup(); } if (group && group->isVisible()) { dirtySpatialGroup(TRUE); } if (!num_parts) { if (group && drawable->getNumFaces()) { group->setState(LLSpatialGroup::GEOM_DIRTY); } drawable->setNumFaces(0, NULL, getTEImage(0)); return TRUE; } if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES))) { return TRUE; } if (num_parts > drawable->getNumFaces()) { drawable->setNumFacesFast(num_parts+num_parts/4, NULL, getTEImage(0)); } F32 tot_area = 0; F32 max_area = LLViewerPartSim::getMaxPartCount() * MAX_PARTICLE_AREA_SCALE; F32 pixel_meter_ratio = LLViewerCamera::getInstance()->getPixelMeterRatio(); pixel_meter_ratio *= pixel_meter_ratio; LLViewerPartSim::checkParticleCount(mViewerPartGroupp->mParticles.size()) ; S32 count=0; mDepth = 0.f; S32 i = 0 ; LLVector3 camera_agent = getCameraPosition(); F32 max_scale = 0.f; for (i = 0 ; i < (S32)mViewerPartGroupp->mParticles.size(); i++) { const LLViewerPart *part = mViewerPartGroupp->mParticles[i]; //remember the largest particle max_scale = llmax(max_scale, part->mScale.mV[0], part->mScale.mV[1]); if (part->mFlags & LLPartData::LL_PART_RIBBON_MASK) { //include ribbon segment length in scale const LLVector3* pos_agent = NULL; if (part->mParent) { pos_agent = &(part->mParent->mPosAgent); } else if (part->mPartSourcep.notNull()) { pos_agent = &(part->mPartSourcep->mPosAgent); } if (pos_agent) { F32 dist = (*pos_agent-part->mPosAgent).length(); max_scale = llmax(max_scale, dist); } } LLVector3 part_pos_agent(part->mPosAgent); LLVector3 at(part_pos_agent - camera_agent); F32 camera_dist_squared = at.lengthSquared(); F32 inv_camera_dist_squared; if (camera_dist_squared > 1.f) inv_camera_dist_squared = 1.f / camera_dist_squared; else inv_camera_dist_squared = 1.f; llassert(llfinite(inv_camera_dist_squared)); llassert(!llisnan(inv_camera_dist_squared)); F32 area = part->mScale.mV[0] * part->mScale.mV[1] * inv_camera_dist_squared; tot_area = llmax(tot_area, area); if (tot_area > max_area) { break; } count++; facep = drawable->getFace(i); if (!facep) { LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL; continue; } facep->setTEOffset(i); const F32 NEAR_PART_DIST_SQ = 5.f*5.f; // Only discard particles > 5 m from the camera const F32 MIN_PART_AREA = .005f*.005f; // only less than 5 mm x 5 mm at 1 m from camera if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA) { facep->setSize(0, 0); continue; } facep->setSize(4, 6); facep->setViewerObject(this); if (part->mFlags & LLPartData::LL_PART_EMISSIVE_MASK) { facep->setState(LLFace::FULLBRIGHT); } else { facep->clearState(LLFace::FULLBRIGHT); } facep->mCenterLocal = part->mPosAgent; facep->setFaceColor(part->mColor); facep->setTexture(part->mImagep); //check if this particle texture is replaced by a parcel media texture. if(part->mImagep.notNull() && part->mImagep->hasParcelMedia()) { part->mImagep->getParcelMedia()->addMediaToFace(facep) ; } mPixelArea = tot_area * pixel_meter_ratio; const F32 area_scale = 10.f; // scale area to increase priority a bit facep->setVirtualSize(mPixelArea*area_scale); } for (i = count; i < drawable->getNumFaces(); i++) { LLFace* facep = drawable->getFace(i); if (!facep) { LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL; continue; } facep->setTEOffset(i); facep->setSize(0, 0); } //record max scale (used to stretch bounding box for visibility culling) mScale.set(max_scale, max_scale, max_scale); mDrawable->movePartition(); return TRUE; }
void LLVOClouds::getGeometry(S32 idx, LLStrider<LLVector4a>& verticesp, LLStrider<LLVector3>& normalsp, LLStrider<LLVector2>& texcoordsp, LLStrider<LLColor4U>& colorsp, LLStrider<U16>& indicesp) { if (idx >= mCloudGroupp->getNumPuffs()) { return; } LLDrawable* drawable = mDrawable; LLFace *facep = drawable->getFace(idx); if (!facep->hasGeometry()) { return; } const LLCloudPuff &puff = mCloudGroupp->getPuff(idx); LLColor4 float_color(LLColor3(gSky.getSunDiffuseColor() + gSky.getSunAmbientColor()),puff.getAlpha()); LLColor4U color; color.setVec(float_color); facep->setFaceColor(float_color); U32 vert_offset = facep->getGeomIndex(); LLVector4a part_pos_agent; part_pos_agent.load3(facep->mCenterLocal.mV); LLVector4a at; at.load3(LLViewerCamera::getInstance()->getAtAxis().mV); LLVector4a up(0, 0, 1); LLVector4a right; right.setCross3(at, up); right.normalize3fast(); up.setCross3(right, at); up.normalize3fast(); right.mul(0.5f*CLOUD_PUFF_WIDTH); up.mul(0.5f*CLOUD_PUFF_HEIGHT); LLVector3 normal(0.f,0.f,-1.f); //HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should) // this works because there is actually a 4th float stored after the vertex position which is used as a texture index // also, somebody please VECTORIZE THIS LLVector4a ppapu; LLVector4a ppamu; ppapu.setAdd(part_pos_agent, up); ppamu.setSub(part_pos_agent, up); verticesp->setSub(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setSub(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppapu, right); (*verticesp++).getF32ptr()[3] = 0.f; verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; // *verticesp++ = puff_pos_agent - right + up; // *verticesp++ = puff_pos_agent - right - up; // *verticesp++ = puff_pos_agent + right + up; // *verticesp++ = puff_pos_agent + right - up; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; *texcoordsp++ = LLVector2(0.f, 1.f); *texcoordsp++ = LLVector2(0.f, 0.f); *texcoordsp++ = LLVector2(1.f, 1.f); *texcoordsp++ = LLVector2(1.f, 0.f); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = vert_offset + 0; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 2; *indicesp++ = vert_offset + 1; *indicesp++ = vert_offset + 3; *indicesp++ = vert_offset + 2; }
BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_PARTICLES); dirtySpatialGroup(); S32 num_parts = mViewerPartGroupp->getCount(); LLFace *facep; LLSpatialGroup* group = drawable->getSpatialGroup(); if (!group && num_parts) { drawable->movePartition(); group = drawable->getSpatialGroup(); } if (!num_parts) { if (group && drawable->getNumFaces()) { group->setState(LLSpatialGroup::GEOM_DIRTY); } drawable->setNumFaces(0, NULL, getTEImage(0)); LLPipeline::sCompiles++; return TRUE; } if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES))) { return TRUE; } if (num_parts > drawable->getNumFaces()) { drawable->setNumFacesFast(num_parts+num_parts/4, NULL, getTEImage(0)); } F32 tot_area = 0; F32 max_area = LLViewerPartSim::getMaxPartCount() * MAX_PARTICLE_AREA_SCALE; F32 pixel_meter_ratio = LLViewerCamera::getInstance()->getPixelMeterRatio(); pixel_meter_ratio *= pixel_meter_ratio; LLViewerPartSim::checkParticleCount(mViewerPartGroupp->mParticles.size()) ; S32 count=0; mDepth = 0.f; S32 i = 0 ; LLVector3 camera_agent = getCameraPosition(); for (i = 0 ; i < (S32)mViewerPartGroupp->mParticles.size(); i++) { const LLViewerPart *part = mViewerPartGroupp->mParticles[i]; LLVector3 part_pos_agent(part->mPosAgent); LLVector3 at(part_pos_agent - camera_agent); F32 camera_dist_squared = at.lengthSquared(); F32 inv_camera_dist_squared; if (camera_dist_squared > 1.f) inv_camera_dist_squared = 1.f / camera_dist_squared; else inv_camera_dist_squared = 1.f; F32 area = part->mScale.mV[0] * part->mScale.mV[1] * inv_camera_dist_squared; tot_area = llmax(tot_area, area); if (tot_area > max_area) { break; } count++; facep = drawable->getFace(i); if (!facep) { llwarns << "No face found for index " << i << "!" << llendl; continue; } facep->setTEOffset(i); const F32 NEAR_PART_DIST_SQ = 5.f*5.f; // Only discard particles > 5 m from the camera const F32 MIN_PART_AREA = .005f*.005f; // only less than 5 mm x 5 mm at 1 m from camera if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA) { facep->setSize(0, 0); continue; } facep->setSize(4, 6); facep->setViewerObject(this); if (part->mFlags & LLPartData::LL_PART_EMISSIVE_MASK) { facep->setState(LLFace::FULLBRIGHT); } else { facep->clearState(LLFace::FULLBRIGHT); } facep->mCenterLocal = part->mPosAgent; facep->setFaceColor(part->mColor); facep->setTexture(part->mImagep); mPixelArea = tot_area * pixel_meter_ratio; const F32 area_scale = 10.f; // scale area to increase priority a bit facep->setVirtualSize(mPixelArea*area_scale); } for (i = count; i < drawable->getNumFaces(); i++) { LLFace* facep = drawable->getFace(i); if (!facep) { llwarns << "No face found for index " << i << "!" << llendl; continue; } facep->setTEOffset(i); facep->setSize(0, 0); } mDrawable->movePartition(); LLPipeline::sCompiles++; return TRUE; }
void LLVOClouds::getGeometry(S32 te, LLStrider<LLVector3>& verticesp, LLStrider<LLVector3>& normalsp, LLStrider<LLVector2>& texcoordsp, LLStrider<LLColor4U>& colorsp, LLStrider<U16>& indicesp) { if (te >= mCloudGroupp->getNumPuffs()) { return; } LLDrawable* drawable = mDrawable; LLFace *facep = drawable->getFace(te); if (!facep->hasGeometry()) { return; } LLVector3 normal(0.f,0.f,-1.f); const LLCloudPuff &puff = mCloudGroupp->getPuff(te); S32 index_offset = facep->getGeomIndex(); LLColor4 float_color(LLColor3(gSky.getSunDiffuseColor() + gSky.getSunAmbientColor()),puff.getAlpha()); LLColor4U color; color.setVec(float_color); facep->setFaceColor(float_color); LLVector3 up; LLVector3 right; LLVector3 at; const LLVector3& puff_pos_agent = facep->mCenterLocal; LLVector2 uvs[4]; uvs[0].setVec(0.f, 1.f); uvs[1].setVec(0.f, 0.f); uvs[2].setVec(1.f, 1.f); uvs[3].setVec(1.f, 0.f); LLVector3 vtx[4]; at = LLViewerCamera::getInstance()->getAtAxis(); right = at % LLVector3(0.f, 0.f, 1.f); right.normVec(); up = right % at; up.normVec(); right *= 0.5f*CLOUD_PUFF_WIDTH; up *= 0.5f*CLOUD_PUFF_HEIGHT;; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; vtx[0] = puff_pos_agent - right + up; vtx[1] = puff_pos_agent - right - up; vtx[2] = puff_pos_agent + right + up; vtx[3] = puff_pos_agent + right - up; verticesp->mV[3] = 0.f; *verticesp++ = vtx[0]; verticesp->mV[3] = 0.f; *verticesp++ = vtx[1]; verticesp->mV[3] = 0.f; *verticesp++ = vtx[2]; verticesp->mV[3] = 0.f; *verticesp++ = vtx[3]; *texcoordsp++ = uvs[0]; *texcoordsp++ = uvs[1]; *texcoordsp++ = uvs[2]; *texcoordsp++ = uvs[3]; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = index_offset + 0; *indicesp++ = index_offset + 1; *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 1; *indicesp++ = index_offset + 3; *indicesp++ = index_offset + 2; }
void LLSprite::updateFace(LLFace &face) { LLViewerCamera &camera = *LLViewerCamera::getInstance(); // First, figure out how many vertices/indices we need. U32 num_vertices, num_indices; U32 vertex_count = 0; // Get the total number of vertices and indices if (mFollow) { num_vertices = 4; num_indices = 6; } else { num_vertices = 4; num_indices = 12; } face.setSize(num_vertices, num_indices); if (mFollow) { sCameraUp = camera.getUpAxis(); sCameraRight = -camera.getLeftAxis(); sCameraPosition = camera.getOrigin(); sNormal = -camera.getAtAxis(); if (mUseCameraUp) { // these need to live here because the height/width may change between render calls mScaledUp = sCameraUp; mScaledRight = sCameraRight; mScaledUp *= mHeightDiv2; mScaledRight *= mWidthDiv2; mA = mPosition + mScaledRight + mScaledUp; mB = mPosition - mScaledRight + mScaledUp; mC = mPosition - mScaledRight - mScaledUp; mD = mPosition + mScaledRight - mScaledUp; } else { // The up vector is perpendicular to the camera vector... LLVector3 camera_vec = mPosition - sCameraPosition; mScaledRight = camera_vec % LLVector3(0.f, 0.f, 1.f); mScaledUp = -(camera_vec % mScaledRight); mScaledUp.normalize(); mScaledRight.normalize(); mScaledUp *= mHeightDiv2; mScaledRight *= mWidthDiv2; mA = mPosition + mScaledRight + mScaledUp; mB = mPosition - mScaledRight + mScaledUp; mC = mPosition - mScaledRight - mScaledUp; mD = mPosition + mScaledRight - mScaledUp; } } else { // this is equivalent to how it was done before. . . // we need to establish a way to // identify the orientation of a particular sprite rather than // just banging it in on the x,z plane if it's not following the camera. LLVector3 x_axis; LLVector3 y_axis; F32 dot = sNormal * LLVector3(0.f, 1.f, 0.f); if (dot == 1.f || dot == -1.f) { x_axis.setVec(1.f, 0.f, 0.f); y_axis.setVec(0.f, 1.f, 0.f); } else { x_axis = sNormal % LLVector3(0.f, -1.f, 0.f); x_axis.normalize(); y_axis = sNormal % x_axis; } LLQuaternion yaw_rot(mYaw, sNormal); // rotate axes by specified yaw x_axis = x_axis * yaw_rot; y_axis = y_axis * yaw_rot; // rescale axes by width and height of sprite x_axis = x_axis * mWidthDiv2; y_axis = y_axis * mHeightDiv2; mA = -x_axis + y_axis; mB = x_axis + y_axis; mC = x_axis - y_axis; mD = -x_axis - y_axis; mA += mPosition; mB += mPosition; mC += mPosition; mD += mPosition; } face.setFaceColor(mColor); LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; LLStrider<LLVector2> tex_coordsp; LLStrider<U16> indicesp; U16 index_offset; // Setup face if (!face.getVertexBuffer()) { LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STREAM_DRAW_ARB); buff->allocateBuffer(4, 12, TRUE); face.setGeomIndex(0); face.setIndicesIndex(0); face.setVertexBuffer(buff); } index_offset = face.getGeometry(verticesp,normalsp,tex_coordsp, indicesp); *tex_coordsp = LLVector2(0.f, 0.f); *verticesp = mC; tex_coordsp++; verticesp++; vertex_count++; *tex_coordsp = LLVector2(0.f, 1.f); *verticesp = mB; tex_coordsp++; verticesp++; vertex_count++; *tex_coordsp = LLVector2(1.f, 1.f); *verticesp = mA; tex_coordsp++; verticesp++; vertex_count++; *tex_coordsp = LLVector2(1.f, 0.0f); *verticesp = mD; tex_coordsp++; verticesp++; vertex_count++; // Generate indices, since they're easy. // Just a series of quads. *indicesp++ = index_offset; *indicesp++ = 2 + index_offset; *indicesp++ = 1 + index_offset; *indicesp++ = index_offset; *indicesp++ = 3 + index_offset; *indicesp++ = 2 + index_offset; if (!mFollow) { *indicesp++ = 0 + index_offset; *indicesp++ = 1 + index_offset; *indicesp++ = 2 + index_offset; *indicesp++ = 0 + index_offset; *indicesp++ = 2 + index_offset; *indicesp++ = 3 + index_offset; } face.getVertexBuffer()->setBuffer(0); face.mCenterAgent = mPosition; }
BOOL LLVOGround::updateGeometry(LLDrawable *drawable) { LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; LLStrider<LLVector2> texCoordsp; LLStrider<U16> indicesp; S32 index_offset; LLFace *face; LLDrawPoolGround *poolp = (LLDrawPoolGround*) gPipeline.getPool(LLDrawPool::POOL_GROUND); if (drawable->getNumFaces() < 1) drawable->addFace(poolp, NULL); face = drawable->getFace(0); if (face->mVertexBuffer.isNull()) { face->setSize(5, 12); face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolGround::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); face->setGeomIndex(0); face->setIndicesIndex(0); } index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); if (-1 == index_offset) { return TRUE; } /////////////////////////////////////// // // // LLVector3 at_dir = LLViewerCamera::getInstance()->getAtAxis(); at_dir.mV[VZ] = 0.f; if (at_dir.normVec() < 0.01) { // We really don't care, as we're not looking anywhere near the horizon. } LLVector3 left_dir = LLViewerCamera::getInstance()->getLeftAxis(); left_dir.mV[VZ] = 0.f; left_dir.normVec(); // Our center top point LLColor4 ground_color = gSky.getFogColor(); ground_color.mV[3] = 1.f; face->setFaceColor(ground_color); *(verticesp++) = LLVector3(64, 64, 0); *(verticesp++) = LLVector3(-64, 64, 0); *(verticesp++) = LLVector3(-64, -64, 0); *(verticesp++) = LLVector3(64, -64, 0); *(verticesp++) = LLVector3(0, 0, -1024); // Triangles for each side *indicesp++ = index_offset + 0; *indicesp++ = index_offset + 1; *indicesp++ = index_offset + 4; *indicesp++ = index_offset + 1; *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 4; *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 3; *indicesp++ = index_offset + 4; *indicesp++ = index_offset + 3; *indicesp++ = index_offset + 0; *indicesp++ = index_offset + 4; *(texCoordsp++) = LLVector2(0.f, 0.f); *(texCoordsp++) = LLVector2(1.f, 0.f); *(texCoordsp++) = LLVector2(1.f, 1.f); *(texCoordsp++) = LLVector2(0.f, 1.f); *(texCoordsp++) = LLVector2(0.5f, 0.5f); face->mVertexBuffer->setBuffer(0); LLPipeline::sCompiles++; return TRUE; }
void LLVOClouds::getGeometry(S32 te, LLStrider<LLVector3>& verticesp, LLStrider<LLVector3>& normalsp, LLStrider<LLVector2>& texcoordsp, LLStrider<LLColor4U>& colorsp, LLStrider<U32>& indicesp) { if (te >= mCloudGroupp->getNumPuffs()) { return; } LLDrawable* drawable = mDrawable; LLFace *facep = drawable->getFace(te); if (!facep->hasGeometry()) { return; } LLVector3 normal(0.f,0.f,-1.f); const LLCloudPuff &puff = mCloudGroupp->getPuff(te); S32 index_offset = facep->getGeomIndex(); LLColor4U color(255, 255, 255, (U8) (puff.getAlpha()*255)); facep->setFaceColor(LLColor4(color)); if (isParticle()) { *verticesp++ = facep->mCenterLocal; *texcoordsp++ = LLVector2(0.5f, 0.5f); *colorsp++ = color; *normalsp++ = normal; *indicesp++ = facep->getGeomIndex(); } else { LLVector3 up; LLVector3 right; LLVector3 at; const LLVector3& puff_pos_agent = facep->mCenterLocal; LLVector2 uvs[4]; uvs[0].setVec(0.f, 1.f); uvs[1].setVec(0.f, 0.f); uvs[2].setVec(1.f, 1.f); uvs[3].setVec(1.f, 0.f); LLVector3 vtx[4]; at = gCamera->getAtAxis(); right = at % LLVector3(0.f, 0.f, 1.f); right.normVec(); up = right % at; up.normVec(); right *= 0.5f*CLOUD_PUFF_WIDTH; up *= 0.5f*CLOUD_PUFF_HEIGHT;; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; *colorsp++ = color; vtx[0] = puff_pos_agent - right + up; vtx[1] = puff_pos_agent - right - up; vtx[2] = puff_pos_agent + right + up; vtx[3] = puff_pos_agent + right - up; *verticesp++ = vtx[0]; *verticesp++ = vtx[1]; *verticesp++ = vtx[2]; *verticesp++ = vtx[3]; *texcoordsp++ = uvs[0]; *texcoordsp++ = uvs[1]; *texcoordsp++ = uvs[2]; *texcoordsp++ = uvs[3]; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = index_offset + 0; *indicesp++ = index_offset + 1; *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 1; *indicesp++ = index_offset + 3; *indicesp++ = index_offset + 2; } }