// NOTE: Assumes that this mesh has enough capacity void eMesh::merge(const eMesh &other, const eMatrix4x4& mtx, const eMatrix4x4& mtxRotOnly) { eU32 vtxCntBefore = m_vertices.size(); for(eU32 i = 0; i < other.getVertexCount(); i++) { m_vertices.append(other.getVertex(i)); eVertex& v = m_vertices.lastElement(); v.position = eVector3(v.position) * mtx; v.normal = eVector3(v.normal) * mtxRotOnly; m_bbox.updateExtentFast(v.position); } for(eU32 d = 0; d < other.getDrawSectionCount(); d++) { const DrawSection& ods = other.getDrawSection(d); DrawSection &ds = _findDrawSection(ods.material, ods.type); ds.primitives.reserve(ods.primitives.size()); for(eU32 i = 0; i < ods.primitives.size(); i++) { const Primitive& oprim = other.getPrimitive(ods.primitives[i]); m_primitives.append(oprim); Primitive& prim = m_primitives.lastElement(); prim.material = ods.material; for(eU32 k = 0; k < 3; k++) prim.indices[k] = oprim.indices[k] + vtxCntBefore; ds.primitives.append(m_primitives.size()-1); } } }
void eDeferredRenderer::renderQuad(const eRect &r, const eSize &size, eTexture2dDx11 *tex, const eVector2 &tileUv, const eVector2 &scrollUv) const { // set render states eRenderState &rs = eGfx->getRenderState(); rs.cullMode = eCULL_NONE; rs.depthTest = eFALSE; rs.viewport.set(0, 0, size.width, size.height); if (tex) rs.textures[0] = tex; // use default shaders if no other shaders set if (!rs.ps) rs.ps = m_psQuad; if (!rs.vs) rs.vs = m_vsQuad; // render quad const eCamera cam(0.0f, (eF32)size.width, 0.0f, (eF32)size.height, -1.0f, 1.0f); cam.activate(); eSimpleVtx *vp = nullptr; eGfx->beginLoadGeometry(m_geoQuad, 4, (ePtr *)&vp); { vp[0].set(eVector3((eF32)r.left, (eF32)r.top, 0.0f), eVector2(scrollUv.u, scrollUv.v+tileUv.v)); vp[1].set(eVector3((eF32)r.left, (eF32)r.bottom, 0.0f), eVector2(scrollUv.u, scrollUv.v)); vp[2].set(eVector3((eF32)r.right, (eF32)r.bottom, 0.0f), eVector2(scrollUv.u+tileUv.u, scrollUv.v)); vp[3].set(eVector3((eF32)r.right, (eF32)r.top, 0.0f), eVector2(scrollUv.u+tileUv.u, scrollUv.v+tileUv.v)); } eGfx->endLoadGeometry(m_geoQuad); eGfx->renderGeometry(m_geoQuad); }
void convert(const KDL::Frame &in, eMatrixHom &out) { double x,y,z,w; in.M.GetQuaternion(x, y, z, w); out = createMatrix(eQuaternion(w, x, y, z), eVector3(in.p.x(), in.p.y(), in.p.z())); }
void eLSystem::applyForce(tSymbol& symbol, const eQuat& curRot, eQuat& targetRot, eVector3& targetPos) { ePROFILER_ZONE("L-System - Apply Force"); for(eS32 a = -1; a < (eS32)m_forces.size(); a++) { eF32 attractAmount = m_gravity; eU32 axis = 2; eVector3 attractionVec = eVector3(0,-1,0); if(a != -1) { const tForceGenerator& attractor = m_forces[a]; eVector3 attractorPos = (*attractor.triDefs)[0]; attractAmount = attractor.mass; axis = attractor.attractAxis; /* #ifdef eEDITOR if(attractor.gen_type == FG_CLOSEST_FACE) { eU32 bestFaceOffset = 0; eVector3 bestFaceStats(eF32_MAX, 0, 0); for(eU32 i = 0; i < attractor.triDefs->size(); i += 3) { const eVector3& B = (*attractor.triDefs)[i]; const eVector3& E0 = (*attractor.triDefs)[i+1]; const eVector3& E1 = (*attractor.triDefs)[i+2]; eVector3 distTest = targetPos.distanceToTriangle(B, E0, E1); if(distTest.x < bestFaceStats.x) { bestFaceStats = distTest; bestFaceOffset = i; } } // calculate attractor face const eVector3& B = (*attractor.triDefs)[bestFaceOffset]; const eVector3& E0 = (*attractor.triDefs)[bestFaceOffset+1]; const eVector3& E1 = (*attractor.triDefs)[bestFaceOffset+2]; attractorPos = B + E0 * bestFaceStats.y + E1 * bestFaceStats.z; attractAmount = attractor.mass * (1.0f / bestFaceStats.x); } #endif */ attractionVec = attractorPos - targetPos; } eVector3 look = curRot.getVector(axis); eVector3 side = look^attractionVec; eF32 cosAngleAttrLen = look * attractionVec; eF32 cosAngleSqr = (cosAngleAttrLen * cosAngleAttrLen / attractionVec.sqrLength()); eF32 sinAngleSqr = 1.0f - cosAngleSqr; eF32 amount = (1.0f - (1.0f / (1.0f + attractAmount))); // |side| = sin(alpha) eF32 sideLen = side.length(); if(sideLen > eALMOST_ZERO) { side /= sideLen; eQuat rotation(side, ePI * 0.5f * sinAngleSqr * amount); targetRot = rotation * targetRot; } } }
OP_INTERACT(eGraphicsApiDx9 *gfx, eSceneData &sd) { static eMesh::Instance mi(m_lightMesh); eMatrix4x4 mtx; mtx.scale(eVector3(getParameter(1).getValue().flt)*0.5f); mtx.translate(getParameter(0).getValue().fxyz); sd.addRenderable(&mi, mtx); }
OP_INIT() { eOP_PARAM_ADD_FXYZ("Position", eF32_MIN, eF32_MAX, 10.0f, 10.0f, 10.0f); eOP_PARAM_ADD_FLOAT("Range", 0.01f, eF32_MAX, 100.0f); eOP_PARAM_ADD_RGB("Diffuse", 1.0f, 1.0f, 1.0f); eOP_PARAM_ADD_RGB("Ambient", 0.0f, 0.0f, 0.0f); eOP_PARAM_ADD_RGB("Specular", 1.0f, 1.0f, 1.0f); eOP_PARAM_ADD_LABEL("Shadows", "Shadows"); eOP_PARAM_ADD_BOOL("Casts shadows", eFALSE); eOP_PARAM_ADD_FLAGS("Shadowed faces", "X+|X-|Y+|Y-|Z+|Z-", 0x3f); // All on = first 6 bits set. eOP_PARAM_ADD_FLOAT("Penumbra size", 0.0f, eF32_MAX, 2.0f); eOP_PARAM_ADD_FLOAT("Shadow bias", 0.0f, 1.0f, 0.001f); // Create light bounding sphere mesh. _addCircleToMesh(m_lightMesh, 100, eVector3( 0.0f, 0.0f, eHALFPI)); _addCircleToMesh(m_lightMesh, 100, eVector3( 0.0f, eHALFPI, 0.0f)); _addCircleToMesh(m_lightMesh, 100, eVector3(eHALFPI, 0.0f, 0.0f)); m_lightMesh.finishLoading(eMesh::TYPE_DYNAMIC); }
void eMesh::createWireCube(eMesh &mesh, const eVector3 &size, const eMaterial *mat) { eASSERT(mat != eNULL); const eVector3 vertices[8] = { eVector3(-0.5f, -0.5f, -0.5f), // ulh eVector3(-0.5f, -0.5f, 0.5f), // ulv eVector3( 0.5f, -0.5f, 0.5f), // urv eVector3( 0.5f, -0.5f, -0.5f), // urh eVector3(-0.5f, 0.5f, -0.5f), // olh eVector3(-0.5f, 0.5f, 0.5f), // olv eVector3( 0.5f, 0.5f, 0.5f), // orv eVector3( 0.5f, 0.5f, -0.5f), // orh }; mesh.clear(); for (eU32 i=0; i<8; i++) { eVector3 pos = vertices[i]; pos.scale(size); mesh.addVertex(pos); } // bottom quad mesh.addLine(0, 1, mat); mesh.addLine(1, 2, mat); mesh.addLine(2, 3, mat); mesh.addLine(3, 0, mat); // top quad mesh.addLine(4, 5, mat); mesh.addLine(5, 6, mat); mesh.addLine(6, 7, mat); mesh.addLine(7, 4, mat); // four lines mesh.addLine(0, 4, mat); mesh.addLine(1, 5, mat); mesh.addLine(2, 6, mat); mesh.addLine(3, 7, mat); mesh.finishLoading(TYPE_DYNAMIC); }
OP_EXEC(eGraphicsApiDx9 *gfx, eF32 radius, eU32 count, const eVector3 &rot) { eSceneData &sd = ((eIModelOp *)getInputOperator(0))->getResult().sceneData; const eVector3 exRot = rot*eTWOPI; const eVector3 trans(0.0f, 0.0f, radius); eVector3 curRot = exRot; eF32 step = eTWOPI/(count+1); for (eU32 i=0; i<=count; i++) { curRot += exRot; curRot.y += step; m_sceneData.merge(sd, eMatrix4x4(curRot, trans, eVector3(1.0f), eTRUE)); } }
void eDeferredRenderer::renderQuad(const eRect &r, const eSize &size, const eVector2 &tileUv, const eVector2 &scrollUv) const { const eCamera cam(0.0f, (eF32)size.width, 0.0f, (eF32)size.height, -1.0f, 1.0f); cam.activate(m_gfx); eGeometry geo(4, 0, 2, eVTXTYPE_DEFAULT, eGeometry::TYPE_DYNAMIC, ePRIMTYPE_TRIANGLESTRIPS); eVertex *vertices = eNULL; geo.startFilling((ePtr *)&vertices, eNULL); { // +0.5 and -0.5 are required for offsetting screen-space // coordinates of quad a bit in order to compensate // for correct texel to pixel mapping in Direct3D9. vertices[0].set(eVector3((eF32)r.left-0.5f, (eF32)r.bottom+0.5f, 0.0f), eVector3(), eVector2(scrollUv.u, scrollUv.v), eColor::WHITE); vertices[1].set(eVector3((eF32)r.left-0.5f, (eF32)r.top+0.5f, 0.0f), eVector3(), eVector2(scrollUv.u, tileUv.v+scrollUv.v), eColor::WHITE); vertices[2].set(eVector3((eF32)r.right-0.5f, (eF32)r.bottom+0.5f, 0.0f), eVector3(), eVector2(tileUv.u+scrollUv.u, scrollUv.v), eColor::WHITE); vertices[3].set(eVector3((eF32)r.right-0.5f, (eF32)r.top+0.5f, 0.0f), eVector3(), eVector2(tileUv.u+scrollUv.u, tileUv.v+scrollUv.v), eColor::WHITE); } geo.stopFilling(); geo.render(); }
void eCamera::_extractFrustumPlanes() { eASSERT(m_type == eCAM_PERSPECTIVE); // frustum corners after perspective projection eVector3 corners[8] = { eVector3(-1.0f, -1.0f, 0.0f), eVector3( 1.0f, -1.0f, 0.0f), eVector3(-1.0f, 1.0f, 0.0f), eVector3( 1.0f, 1.0f, 0.0f), eVector3(-1.0f, -1.0f, 1.0f), eVector3( 1.0f, -1.0f, 1.0f), eVector3(-1.0f, 1.0f, 1.0f), eVector3( 1.0f, 1.0f, 1.0f), }; // get corners before perspective projection by // multiplying with inverse projection matrix const eMatrix4x4 invViewProjMtx = (m_viewMtx*m_projMtx).inverse(); for (eInt i=0; i<8; i++) { eVector4 v(corners[i], 1.0f); v *= invViewProjMtx; v /= v.w; corners[i].set(v.x, v.y, v.z); } // setup frustum planes m_frustumPlanes[0] = ePlane(corners[0], corners[1], corners[2]); m_frustumPlanes[1] = ePlane(corners[6], corners[7], corners[5]); m_frustumPlanes[2] = ePlane(corners[2], corners[6], corners[4]); m_frustumPlanes[3] = ePlane(corners[7], corners[3], corners[5]); m_frustumPlanes[4] = ePlane(corners[2], corners[3], corners[6]); m_frustumPlanes[5] = ePlane(corners[1], corners[0], corners[4]); }
OP_EXEC(eGraphicsApiDx9 *gfx, const eVector3 &trans, const eVector3 &rot, const eVector3 &scale, eU32 count, const eVector3 &randTrans, const eVector3 &randRot, const eVector3 &randScale, eU32 seed) { eSceneData &sd = ((eIModelOp *)getInputOperator(0))->getResult().sceneData; eMatrix4x4 tf; tf.transformation(rot*eTWOPI, trans, scale); eMatrix4x4 mtx; seed++; for (eU32 i=0; i<count+1; i++) { const eVector3 vec_s = eVector3(1.0f)+randScale.random(seed); const eVector3 vec_t = randTrans.random(seed); const eVector3 vec_r = (randRot*eTWOPI).random(seed); const eMatrix4x4 randMtx(vec_r, vec_t, vec_s, eTRUE); m_sceneData.merge(sd, randMtx*mtx); mtx *= tf; } }
eVector3 eMatrix3x3::getColumn(eU32 col) const { eASSERT(col <= 2); return eVector3(m[col], m[col+3], m[col+6]); }
eU32 eMesh::addVertex(const eVector3 &pos, const eColor &color) { return addVertex(pos, eVector3(), eVector2(), color); }
Approximation::Approximation(eU32 gridCnt, eU32 sampleCnt, eF32* samples, eF32* normals) { // this->m_gridCnt = gridCnt; // m_boundBox.clear(); eKD_Tree* kdTree = new eKD_Tree(); KD_Item* sampleItems = new KD_Item[sampleCnt]; for(eU32 i = 0; i < sampleCnt; i++) { sampleItems[i].pos = eVector3(samples[i * 3 + 0], samples[i * 3 + 1], samples[i * 3 + 2]); sampleItems[i].objectData = &normals[i * 3]; // m_boundBox.updateExtentsFast(sampleItems[i].pos); } // m_boundBox.updateExtentsFinalize(); kdTree->InsertPoints(sampleItems, sampleCnt); this->root = new ApproxNode(kdTree->root); /* KD_Lookup_Entry* queryBuffer = new KD_Lookup_Entry[sampleCnt]; eF32* pointBuffer = new eF32[(3 + 1) * (sampleCnt * 3 + 1)]; eF32* valueBuffer = new eF32[sampleCnt * 3 + 1]; this->m_spaces = new TensorProductSpace[gridCnt*gridCnt*gridCnt]; m_step = m_boundBox.getSizeVector() / (eF32)(gridCnt); int t = 0; for(eU32 z = 0; z < gridCnt; z++) for(eU32 y = 0; y < gridCnt; y++) for(eU32 x = 0; x < gridCnt; x++) { eVector3 pos0((eF32)x * m_step.x, (eF32)y * m_step.y, (eF32)z * m_step.z); pos0 += m_boundBox.getMinimum(); eVector3 pos1 = pos0 + m_step; eU32 p = 0; eU32 v = 0; eU32 minSamples = 10; eU32 cnt = 0; eVector3 pivot = (pos0 + pos1) * 0.5; eF32 radiusSquared = (m_step * 0.5).sqrLength(); kdTree->CollectInRadius(&pivot, radiusSquared, queryBuffer, cnt); if(cnt < minSamples) { kdTree->findKNearest(&pivot, minSamples, queryBuffer, cnt); radiusSquared = queryBuffer[cnt-1].distanceSquared; pointBuffer[p++] = 1; pointBuffer[p++] = pivot.x; pointBuffer[p++] = pivot.y; pointBuffer[p++] = pivot.z; eVector3 normal(*(((eF32*)queryBuffer[0].element->objectData) + 0), *(((eF32*)queryBuffer[0].element->objectData) + 1), *(((eF32*)queryBuffer[0].element->objectData) + 2)); // valueBuffer[v++] = ((pivot - queryBuffer[0].element->pos).normalized() * normal.normalized()) * eSqrt(queryBuffer[0].distanceSquared); valueBuffer[v++] = ((pivot - queryBuffer[0].element->pos) * normal); } for(eU32 i = 0; i < cnt; i++) { for(eS32 d = -1; d <= 1; d++) { eF32 epsilon = (eF32)d * 0.001; // pointBuffer[p++] = Wendland(eSqrt(queryBuffer[i].distanceSquared), eSqrt(radiusSquared)); pointBuffer[p++] = 1.0f; pointBuffer[p++] = queryBuffer[i].element->pos.x + *(((eF32*)queryBuffer[i].element->objectData) + 0) * epsilon; pointBuffer[p++] = queryBuffer[i].element->pos.y + *(((eF32*)queryBuffer[i].element->objectData) + 1) * epsilon; pointBuffer[p++] = queryBuffer[i].element->pos.z + *(((eF32*)queryBuffer[i].element->objectData) + 2) * epsilon; valueBuffer[v++] = epsilon; } } this->m_spaces[t].Calculate(v, pointBuffer, valueBuffer); t++; } // this->m_spaces = new TensorProductSpace(grade, dimensionality, sampleC this->m_step.x = 1.0 / this->m_step.x; this->m_step.y = 1.0 / this->m_step.y; this->m_step.z = 1.0 / this->m_step.z; */ }
eVector3 eMatrix3x3::operator * (const eVector3 &v) const { return eVector3(m11*v.x+m12*v.y+m13*v.z, m21*v.x+m22*v.y+m23*v.z, m31*v.x+m32*v.y+m33*v.z); }
eVector3 toVec3() { return eVector3(x, y, z); }
void eCALLBACK eTriangulator::_combineCallback(eF64 newVert[3], eU32 neighbourVert[4], eF32 neighborWeight[4], eU32 *index, eTriangulator *trg) { trg->m_vertices.append(eVector3((eF32)newVert[0], (eF32)newVert[1], (eF32)newVert[2])); *index = trg->m_vertices.size()-1; }
eVector3 eMatrix4x4::operator * (const eVector3 &v) const { return eVector3(m11*v.x+m12*v.y+m13*v.z+m14, m21*v.x+m22*v.y+m23*v.z+m24, m31*v.x+m32*v.y+m33*v.z+m34); }
void eLSystem::drawInternal(eSceneData& destsg, eMesh& destMesh, tState* state) { ePROFILER_ZONE("L-System - Draw Internal Pre"); this->m_gen_materials_dsIdx.clear(); for(eU32 i = 0 ; i < this->m_gen_materials.size(); i++) this->m_gen_materials_dsIdx.append(destMesh.addDrawSection(this->m_gen_materials[i], eMesh::DrawSection::TYPE_TRIANGLES)); eQuat originRot = state->curBaseRotation; { eArray<tProdSymbol>& curProd = m_prodBuffer[0]; curProd.clear(); eArray<tSymbol>& production = productions[0]; for(eU32 s = 0; s < production.size(); s++) { tSymbol& curSymbol = production[s]; tProdSymbol& ps = curProd.push(); ps.correctRot = originRot; } } eF32 accumulatedStepLen = 0.0f; eU32 accumulatedStepCount = 0; drawStackPos = 0; tDrawState* drawState = getDefaultDrawState(); drawState->lastTurtle = state->turtle; for(eU32 p = 1; p < numProductions; p++) { this->pushState(&state); eBool isLastProduction = p == numProductions - 1; state->curBaseRotation = eQuat(); eU32 polyScopeCnt = 0; eArray<tSymbol>& prevProduction = productions[p - 1]; eArray<tSymbol>& production = productions[p]; eArray<tProdSymbol>& prevProd = m_prodBuffer[(1-p % 2)]; eArray<tProdSymbol>& curProd = m_prodBuffer[p % 2]; curProd.clear(); curProd.reserve(production.size()); for(eU32 s = 0; s < production.size(); s++) { tSymbol& curSymbol = production[s]; const tSymbol& parentSymbol = prevProduction[curSymbol.parentIdx]; tProdSymbol& curProdSym = curProd.push(); const tProdSymbol& parentProdSym = prevProd[curSymbol.parentIdx]; const eS32 symbolRaw = curSymbol.symbol; switch(curSymbol.symbol) { case '^': state->turtle.width *= 2.0f; break; case '&': state->turtle.width *= 0.5f; break; // case '!': state->turtle.width = curSymbol.params[0] * this->m_baseWidth; break; case '\'': if(state->turtle.polyMatIdx < this->m_gen_materials.size() - 1) state->turtle.polyMatIdx++; break; case '[': pushState(&state); break; case ']': popState(&state); break; case '{': polyScopeCnt++; break; case '}': polyScopeCnt--; break; case 'F': case 'G': { eQuat currentRot = parentProdSym.correctRot * curSymbol.rotation; eQuat currentGlobalRot = state->curBaseRotation * currentRot; this->applyForce(curSymbol, currentGlobalRot, state->curBaseRotation, state->turtle.position); state->turtle.rotation = (state->curBaseRotation * currentRot); eF32 amount = (state->turtle.size * state->turtle.height * curSymbol.params[0]); state->turtle.texPos += curSymbol.texVec * (this->m_gen_texScale * amount); state->turtle.position += state->turtle.rotation.getVector(2) * amount; } default: state->turtle.size *= m_sizeDecayPar; curProdSym.correctRot = state->curBaseRotation * parentProdSym.correctRot; // { // ePROFILER_ZONE("L-System - Draw Internal Calc"); state->turtle.rotation = curProdSym.correctRot * curSymbol.rotation; // } } // only draw last production if(!isLastProduction) continue; ePROFILER_ZONE("L-System - DrawInterpret"); switch(curSymbol.symbol) { case '%': { // skip remaining eU32 scopeCnt = 1; while(((++s) < (eS32)production.size()) && (scopeCnt > 0)) if(production[s].symbol == '[') scopeCnt++; else if(production[s].symbol == ']') scopeCnt--; s -= 2; } continue; case '[': this->pushDrawState(&drawState); break; case ']': this->popDrawState(&drawState); break; case '{': if(polyStackPos >= polygonStack.size()) polygonStack.append(eArray<eInt>()); polygon = &polygonStack[polyStackPos++]; polygon->clear(); break; case '}': { if((state->turtle.polyMatIdx >= 0) && (state->turtle.polyMatIdx < m_gen_materials.size())) { for(eU32 p = 0; (eS32)p < (eS32)polygon->size() - 2; p++) { // draw polys destMesh.addTriangleFast((*polygon)[p], (*polygon)[p+1], (*polygon)[polygon->size() - 1], m_gen_materials_dsIdx[state->turtle.polyMatIdx]); } } // pop stack polyStackPos--; if(polyStackPos > 0) polygon = &polygonStack[polyStackPos - 1]; } break; case 'F': case '.': if(polyStackPos > 0) { polygon->append(destMesh.addVertex(state->turtle.position, state->turtle.rotation.getVector(2), state->turtle.texPos)); } // no break default: if((symbolRaw >= LSYS_VAR_MIN) && (symbolRaw <= LSYS_VAR_MAX)) { if(this->m_subSystem[symbolRaw] != eNULL) { // ePROFILER_ZONE("L-System - Draw Sub LSys"); this->m_subSystem[symbolRaw]->processSub(destsg, destMesh, state->turtle); } else if(this->m_subMesh[symbolRaw] != eNULL) { ePROFILER_ZONE("L-System - Draw Sub Model"); eMatrix4x4 mtx; mtx.scale(state->turtle.size); eQuat con = state->turtle.rotation; con.conjugate(); eMatrix4x4 rotMtx((eQuat(eVector3(1,0,0), -ePI * 0.5f) * (con))); mtx = mtx * rotMtx; mtx.translate(eVector3(state->turtle.position.x, state->turtle.position.y, state->turtle.position.z)); if(m_subMeshInstancing[symbolRaw]) destsg.merge(*this->m_subMesh[symbolRaw], mtx); else for(eU32 i = 0; i < m_subMesh[symbolRaw]->getEntryCount(); i++) _mergeIntoMesh(destMesh, mtx, rotMtx, m_subMesh[symbolRaw]->getEntry(i)); // _mergeIntoMesh(destMesh, mtx, mtx, m_subMesh[symbolRaw]->getEntry(i)); } else { bool skipDraw = false; if((polyStackPos == 0) || (polygon->size() == 0)) { // draw aggregated shapes if((symbolRaw != 'F') || (state->turtle.polyMatIdx < 0) || (state->turtle.polyMatIdx >= m_gen_materials.size())) { } else { eBool forceDraw = (s >= production.size() - 1) || (production[s + 1].symbol != curSymbol.symbol); eF32 stepLen = state->turtle.size * state->turtle.height; skipDraw = !this->drawShapes(destMesh, *drawState, drawState->lastTurtle, state->turtle, accumulatedStepLen + stepLen, drawState->texYOffset, drawState->texYOffset + m_gen_texScale, forceDraw, accumulatedStepCount + 1); if(skipDraw) { accumulatedStepCount++; accumulatedStepLen += stepLen; } else { accumulatedStepCount = 0; accumulatedStepLen = 0.0f; } } } drawState->texYOffset += m_gen_texScale; if(!skipDraw) drawState->lastTurtle = state->turtle; } } } } this->popState(&state); } }