const IBox View::computeCursor(const int2 &start, const int2 &end, const int3 &bbox, int height, int offset) const { float2 height_off = worldToScreen(float3(0, height, 0)); int3 gbox(cellSize(), 1, cellSize()); int3 start_pos = asXZ((int2)( screenToWorld(float2(start + pos()) - height_off) + float2(0.5f, 0.5f))); int3 end_pos = asXZ((int2)( screenToWorld(float2(end + pos()) - height_off) + float2(0.5f, 0.5f))); start_pos.y = end_pos.y = height + offset; { int apos1 = start_pos.x % gbox.x; int apos2 = apos1 - gbox.x + bbox.x; start_pos.x -= apos1 < gbox.x - apos1 || bbox.x >= gbox.x? apos1 : apos2; } { int apos1 = start_pos.z % gbox.z; int apos2 = apos1 - gbox.z + bbox.z; start_pos.z -= apos1 < gbox.z - apos1 || bbox.z >= gbox.z? apos1 : apos2; } if(end == start) end_pos = start_pos; int3 dir(end_pos.x >= start_pos.x? 1 : -1, 1, end_pos.z >= start_pos.z? 1 : -1); int3 size(::abs(end_pos.x - start_pos.x), 1, ::abs(end_pos.z - start_pos.z)); size += bbox - int3(1, 1, 1); size.x -= size.x % bbox.x; size.z -= size.z % bbox.z; size = vmax(bbox, size); if(dir.x < 0) start_pos.x += bbox.x; if(dir.z < 0) start_pos.z += bbox.z; end_pos = start_pos + dir * size; if(start_pos.x > end_pos.x) swap(start_pos.x, end_pos.x); if(start_pos.z > end_pos.z) swap(start_pos.z, end_pos.z); int2 dims = m_tile_map.dimensions(); start_pos = asXZY(vclamp(start_pos.xz(), int2(0, 0), dims), start_pos.y); end_pos = asXZY(vclamp( end_pos.xz(), int2(0, 0), dims), end_pos.y); return IBox(start_pos, end_pos); }
Vec2 TouchTracker::Calibrator::getBinPosition(Vec2 pIn) const { // Soundplane A static MLRange binRangeX(2.0, 61.0, 0., mWidth); static MLRange binRangeY(0.5, 6.5, 0., mHeight); Vec2 minPos(2.5, 0.5); Vec2 maxPos(mWidth - 2.5f, mHeight - 0.5f); Vec2 pos(binRangeX(pIn.x()), binRangeY(pIn.y())); return vclamp(pos, minPos, maxPos); }
static void setpart(part * p) { float fact; if (p->p[0][1] < 0.1) { setnewpart(p); return; } p->v[1] += AGRAV * dt; vadds(p->p[0], dt, p->v); vadds(p->p[1], dt, p->v); vadds(p->p[2], dt, p->v); p->age++; if ((p->age) > maxage) { vequ(p->c[0], blu2); vequ(p->c[1], blu2); vequ(p->c[2], blu2); } else { fact = 1.0 / maxage; vadds(p->c[0], fact, blu2); vclamp(p->c[0]); p->c[0][3] = fact * (maxage - p->age); vadds(p->c[1], fact, blu2); vclamp(p->c[1]); p->c[1][3] = fact * (maxage - p->age); vadds(p->c[2], fact, blu2); vclamp(p->c[2]); p->c[2][3] = fact * (maxage - p->age); } }
/* set fire particle values */ static void setpart(firestruct * fs, part * p) { float fact; if (p->p[0][1] < 0.1) { setnewpart(fs, p); return; } p->v[1] += AGRAV * fs->dt; vadds(p->p[0], fs->dt, p->v); vadds(p->p[1], fs->dt, p->v); vadds(p->p[2], fs->dt, p->v); p->age++; if ((p->age) > fs->maxage) { vequ(p->c[0], partcol2); vequ(p->c[1], partcol2); vequ(p->c[2], partcol2); } else { fact = 1.0 / fs->maxage; vadds(p->c[0], fact, partcol2); vclamp(p->c[0]); p->c[0][3] = fact * (fs->maxage - p->age); vadds(p->c[1], fact, partcol2); vclamp(p->c[1]); p->c[1][3] = fact * (fs->maxage - p->age); vadds(p->c[2], fact, partcol2); vclamp(p->c[2]); p->c[2][3] = fact * (fs->maxage - p->age); } }
void View::update(const InputState &state) { if(state.isKeyDown('g')) { if(m_is_visible) { if(m_cell_size == 3) m_cell_size = 6; else if(m_cell_size == 6) m_cell_size = 9; else { m_cell_size = 1; m_is_visible = false; } } else { m_cell_size = 3; m_is_visible = true; } } int height_change = state.mouseWheelMove() + (state.isKeyDownAuto(InputKey::pagedown)? -1 : 0) + (state.isKeyDownAuto(InputKey::pageup)? 1 : 0); if(height_change) m_height = clamp(m_height + height_change, 0, (int)Grid::max_height); { int actions[TileGroup::Group::side_count] = { InputKey::kp_1, InputKey::kp_2, InputKey::kp_3, InputKey::kp_6, InputKey::kp_9, InputKey::kp_8, InputKey::kp_7, InputKey::kp_4 }; for(int n = 0; n < arraySize(actions); n++) if(state.isKeyDownAuto(actions[n])) m_view_pos += worldToScreen(TileGroup::Group::s_side_offsets[n] * m_cell_size); } if((state.isKeyPressed(InputKey::lctrl) && state.isMouseButtonPressed(InputButton::left)) || state.isMouseButtonPressed(InputButton::middle)) m_view_pos -= state.mouseMove(); IRect rect = worldToScreen(IBox(int3(0, 0, 0), asXZY(m_tile_map.dimensions(), 256))); m_view_pos = vclamp(m_view_pos, rect.min(), rect.max() - m_view_size); }
void __glcore_transform_vertices (GLcontext *g) { GLrenderstate *r = g->renderstate; GL_vertex *verts = r->verts; GL_procvert *procverts = r->procverts; int i; GL_float modelview[4][4]; GL_float projection[4][4]; GL_float texture[4][4]; GL_float composite[4][4]; GL_float invmodelview[4][4]; minit(modelview, g->trans.modelview[g->trans.modelviewdepth]); minit(projection, g->trans.projection[g->trans.projectiondepth]); minit(texture, g->trans.texture[g->trans.texturedepth]); mmult(composite, projection, modelview); minvtrans(invmodelview, modelview); for (i = 0; i < r->nverts; i++) { /* position */ mmultv(procverts[i].position, composite, verts[i].position); /* eye position */ mmultv(procverts[i].eyeposition, modelview, verts[i].position); /* color */ if (g->lighting.lighting) { GL_float objnormal[4]; GL_float normal[4]; /* object space normal */ vcopy(objnormal, verts[i].normal); objnormal[3] = 0.0f; if (verts[i].position[3] != 0.0f) { objnormal[3] = -vdot3(objnormal, verts[i].position); objnormal[3] /= verts[i].position[3]; } /* eye space normal */ mmultv(normal, invmodelview, objnormal); if (g->current.normalize) vnorm3(normal, normal); /* front color */ compute_lighting(g, procverts[i].frontcolor, procverts[i].eyeposition, normal, &verts[i].frontmaterial); /* back color */ if (g->lighting.lightmodeltwoside) { vscale(normal, normal, -1.0f); compute_lighting(g, procverts[i].backcolor, procverts[i].eyeposition, normal, &verts[i].backmaterial); } } else { vcopy(procverts[i].frontcolor, verts[i].color); vcopy(procverts[i].backcolor, verts[i].color); } vclamp(procverts[i].frontcolor, procverts[i].frontcolor, 0.0f, 1.0f); vclamp(procverts[i].backcolor, procverts[i].backcolor, 0.0f, 1.0f); /* no texture coordinate generation */ /* texture coords */ mmultv(procverts[i].texcoord, texture, verts[i].texcoord); } }
// input: the pressure data, after static calibration (tare) but otherwise raw. // input feeds a state machine that first collects a normalization map, then // collects a touch shape, or kernel, at each point. int TouchTracker::Calibrator::addSample(const MLSignal& m) { int r = 0; static Vec2 intPeak1; static MLSignal f2(mSrcWidth, mSrcHeight); static MLSignal input(mSrcWidth, mSrcHeight); static MLSignal tare(mSrcWidth, mSrcHeight); static MLSignal normTemp(mSrcWidth, mSrcHeight); // decreasing this will collect a wider area during normalization, // smoothing the results. const float kNormalizeThreshold = 0.125f; float kc, ke, kk; kc = 4./16.; ke = 2./16.; kk=1./16.; // simple lopass time filter for calibration f2 = m; f2.subtract(mFilteredInput); f2.scale(0.1f); mFilteredInput.add(f2); input = mFilteredInput; input.sigMax(0.); // get peak of sample data Vec3 testPeak = input.findPeak(); float peakZ = testPeak.z(); const int startupSamples = 1000; const int waitAfterNormalize = 2000; if (mTotalSamples < startupSamples) { age = 0; mStartupSum += peakZ; if(mTotalSamples % 100 == 0) { MLConsole() << "."; } } else if (mTotalSamples == startupSamples) { age = 0; //mAutoThresh = kNormalizeThresh; mAutoThresh = mStartupSum / (float)startupSamples * 10.f; MLConsole() << "\n****************************************************************\n\n"; MLConsole() << "OK, done collecting silence (auto threshold: " << mAutoThresh << "). \n"; MLConsole() << "Now please slide your palm across the surface, \n"; MLConsole() << "applying a firm and even pressure, until all the rectangles \n"; MLConsole() << "at left turn blue. \n\n"; mNormalizeMap.clear(); mNormalizeCount.clear(); mCollectingNormalizeMap = true; } else if (mCollectingNormalizeMap) { // smooth temp signal, duplicating values at border normTemp.copy(input); normTemp.convolve3x3rb(kc, ke, kk); normTemp.convolve3x3rb(kc, ke, kk); normTemp.convolve3x3rb(kc, ke, kk); if(peakZ > mAutoThresh) { // collect additions in temp signals mTemp.clear(); // adds to map mTemp2.clear(); // adds to sample count // where input > thresh and input is near max current input, add data. for(int j=0; j<mHeight; ++j) { for(int i=0; i<mWidth; ++i) { // test threshold with smoothed data float zSmooth = normTemp(i, j); // but add actual samples from unsmoothed input float z = input(i, j); if(zSmooth > peakZ * kNormalizeThreshold) { // map must = count * z/peakZ mTemp(i, j) = z / peakZ; mTemp2(i, j) = 1.0f; } } } // add temp signals to data mNormalizeMap.add(mTemp); mNormalizeCount.add(mTemp2); mVisSignal.copy(mNormalizeCount); mVisSignal.scale(1.f / (float)kNormMapSamples); } if(doneCollectingNormalizeMap()) { float mapMaximum = makeNormalizeMap(); MLConsole() << "\n****************************************************************\n\n"; MLConsole() << "\n\nOK, done collecting normalize map. (max = " << mapMaximum << ").\n"; MLConsole() << "Please lift your hands."; mCollectingNormalizeMap = false; mWaitSamplesAfterNormalize = 0; mVisSignal.clear(); mStartupSum = 0; } } else { if(mWaitSamplesAfterNormalize < waitAfterNormalize) { mStartupSum += peakZ; mWaitSamplesAfterNormalize++; if(mTotalSamples % 100 == 0) { MLConsole() << "."; } } else if(mWaitSamplesAfterNormalize == waitAfterNormalize) { mWaitSamplesAfterNormalize++; mAutoThresh *= 1.5f; MLConsole() << "\nOK, done collecting silence again (auto threshold: " << mAutoThresh << "). \n"; MLConsole() << "\n****************************************************************\n\n"; MLConsole() << "Now please slide a single finger over the \n"; MLConsole() << "Soundplane surface, visiting each area twice \n"; MLConsole() << "until all the areas are colored green at left. \n"; MLConsole() << "Sliding over a key the first time will turn it gray. \n"; MLConsole() << "Sliding over a key the second time will turn it green.\n"; MLConsole() << "\n"; } else if(peakZ > mAutoThresh) { // normalize input mTemp.copy(input); mTemp.multiply(mNormalizeMap); // smooth input mTemp.convolve3x3r(kc, ke, kk); mTemp.convolve3x3r(kc, ke, kk); mTemp.convolve3x3r(kc, ke, kk); // get corrected peak mPeak = mTemp.findPeak(); mPeak = mTemp.correctPeak(mPeak.x(), mPeak.y()); Vec2 minPos(2.0, 0.); Vec2 maxPos(mWidth - 2., mHeight - 1.); mPeak = vclamp(mPeak, minPos, maxPos); age++; // continue touch // get sample from input around peak and normalize mIncomingSample.clear(); mIncomingSample.add2D(m, -mPeak + Vec2(kTemplateRadius, kTemplateRadius)); mIncomingSample.sigMax(0.f); mIncomingSample.scale(1.f / mIncomingSample(kTemplateRadius, kTemplateRadius)); // get integer bin Vec2 binPeak = getBinPosition(mPeak); mVisPeak = binPeak - Vec2(0.5, 0.5); int bix = binPeak.x(); int biy = binPeak.y(); // clamp to calibratable area bix = clamp(bix, 2, mWidth - 2); biy = clamp(biy, 0, mHeight - 1); Vec2 bIntPeak(bix, biy); // count sum and minimum of all kernel samples for the bin int dataIdx = biy*mWidth + bix; mDataSum[dataIdx].add(mIncomingSample); mData[dataIdx].sigMin(mIncomingSample); mSampleCount[dataIdx]++; if(bIntPeak != intPeak1) { // entering new bin. intPeak1 = bIntPeak; if(mPassesCount[dataIdx] < kPassesToCalibrate) { mPassesCount[dataIdx]++; mVisSignal(bix, biy) = (float)mPassesCount[dataIdx] / (float)kPassesToCalibrate; } } // check for done if(isDone()) { mCalibrateSignal.setDims(kTemplateSize, kTemplateSize, mWidth*mHeight); // get result for each junction for(int j=0; j<mHeight; ++j) { for(int i=0; i<mWidth; ++i) { int idx = j*mWidth + i; // copy to 3d signal mCalibrateSignal.setFrame(idx, mData[idx]); } } getAverageTemplateDistance(); mHasCalibration = true; mActive = false; r = 1; MLConsole() << "\n****************************************************************\n\n"; MLConsole() << "Calibration is now complete and will be auto-saved in the file \n"; MLConsole() << "SoundplaneAppState.txt. \n"; MLConsole() << "\n****************************************************************\n\n"; } } else { age = 0; intPeak1 = Vec2(-1, -1); mVisPeak = Vec2(-1, -1); } } mTotalSamples++; return r; }