roymacdonald: Generous offer to look at my “complete code”. I will furnish the main parts of ofApp.cpp but with some features (audio control) deleted. Also no supporting files that do auxiliary stuff like manipulate a copy of vertices to simulate wave action.
This summary might help understanding my very C-like code.
setup():
initialize mouse to “active” state,
set mesh size and “skip” factor,
camera data, lighting data,
initial flat mesh and transfer z-values to working array
update():
With an active mouse (user-set rain drop location),
a mouse click and bChangeColors=true,
then change color everywhere to, in this case, 127.
Find mouse cursor, set drop height and size, calculate rain drop impulse.
Find new z-values (convolution, scale, add into current mesh vertices.
Set normals.
Here, brave volunteer, is my abbreviated ofApp.cpp:
//--------------------------------------------------------------
/* setup():
* Define initial flat mesh: vertices, normals, colors. No texture.
*/
void ofApp::setup(){
ofSetFrameRate(64);
scale = 0.99;
bReflect = false; // ripples reflect off sides
bShowHelp = true; // toggle text display at startup
bChangeColors = false; // allow/disallow automatic color change w/rain drop
bMouseActive = true; // Control mode: mouse driven or random (disabled)
// Define mesh size to nearly fill window
nSkip = 6; // 12 if "full screen"; 6, if not
nVertsX = ofGetWidth() / nSkip;
nVertsY = ofGetHeight() / nSkip;
initZ = 10;
// Derivative quantities:
nZPlusX = nVertsX + 2;
nZPlusY = nVertsY + 2;
nZPlus = nZPlusX * nZPlusY;
zPlus = new float[nZPlus] { initZ };
zDel2 = new float[nZPlus]{ 0 };
// Mouse and mesh relations
myMouseX = myMouseY = 0;
meshX0 = (ofGetWidth() - nSkip * nVertsX) / 2.;
meshY0 = (ofGetHeight() - nSkip * nVertsY) / 2.;
// Random rain drop controls (DELETED)
ofBackground(ofColor(127));
cam.removeAllInteractions();
cam.enableOrtho();
cam.setNearClip(-1000000);
cam.setFarClip(1000000);
cam.setVFlip(true);
// Build mesh as heightfield ("terrain map") with constant z over base (x,y)
buildFlatMesh(mesh, nVertsX, nVertsY, nSkip, initZ, lightSeaGreen);
// Load z-values into working array
getVertexZValues(mesh, nVertsX, nVertsY, zPlus);
addInitZtoBoundary(zPlus, nZPlusX, nZPlusY, initZ);
// Lighting and material
light.setPosition(1000, 1000, 1000);
light.setOrientation(ofVec3f(45.0, -45.0, 0.0));
light.setDiffuseColor(lightSeaGreen);
light.setSpecularColor(ofColor(255.f, 255.f, 255.f));
material.setShininess(120);
// Audio (DELETED)
}
//--------------------------------------------------------------
void ofApp::update(){
unique_lock<mutex> lock(audioMutex);
float dropHt;
float dropSigma;
float midSigma;
float freqFraction = 0.05;
float dropX0, dropY0;
if (bMouseActive) {
if (bNewMouseClick) {
// Process mouse-triggered rain drop
if (bChangeColors) {
// Rebuild mesh once with new color
for (size_t i = 0; i < mesh.getNumColors(); i++) {
mesh.setColor(i, ofColor(127));
}
bChangeColors = false;
}
// Location
meshMouseX = (myMouseX - meshX0) / nSkip;
meshMouseY = (myMouseY - meshY0) / nSkip;
// Drop size and audio volume
dropHt = ofRandom(dropHtMin, dropHtMax);
dropSigma = ofRandom(dropSigmaMin, dropSigmaMax);
volume = (dropHt - dropHtMin) / (dropHtMax - dropHtMin);
// Initialize "pulse" on surface mesh
defineImpulseGauss(gPulse, meshMouseX, meshMouseY, dropSigma, dropHt);
applyImpulseGauss(zPlus, nZPlusX, nZPlusY, gPulse);
// Wait for next mouse click
bNewMouseClick = false;
}
}
// DELETE ALTERNATIVE (RANDOM) RAIN DROP CODE -- for clarity
// DELETE SOUND VOLUME INITIALIZATION
// Make wave in scratch array
convolveZ(zPlus, zDel2, nZPlusX, nZPlusY, bReflect); // Laplacian
scaleConvolution(zDel2, nZPlusX, nZPlusY, scale);
addConvolution(zPlus, zDel2, nZPlusX, nZPlusY); // Apply and scale
// Load new amplitudes back into mesh
setVertexZValues(mesh, nVertsX, nVertsY, zPlus, nZPlusX);
setNormals(mesh);
}
//--------------------------------------------------------------
void ofApp::draw(){
ofEnableLighting();
light.enable();
material.begin();
cam.begin();
//mesh.drawWireframe();
mesh.draw();
cam.end();
material.end();
ofDisableLighting();
}
//--------------------------------------------------------------
// Draw text that explains user choices
void ofApp::drawHelpText() {
string helpText = "Press h to turn help text on or off.";
string switchText = " m to switch between mouse-selected or random drops.";
string colorText = " c to enable/disable color changing mode.";
ofDrawBitmapString(helpText, 20, 20);
ofDrawBitmapString(switchText, 20, 40);
ofDrawBitmapString(colorText, 20, 60);
}
//--------------------------------------------------------------
// Make 'h' help response and other keys to modify random rain properties
// and toggle action, etc.
void ofApp::keyPressed(int key){
if (key == 'h' || key == 'H') {
// Toggle "Help" text
//cout << "Show/hide help text" << endl;
bShowHelp = !bShowHelp;
}
if (key == 'm' || key == 'M') {
bMouseActive = !bMouseActive;
if (!bMouseActive) {
t0 = ofGetElapsedTimeMillis(); // start the clock for random time
}
}
if (key == 'c' || key == 'C') {
// Enable/disable color changes with each rain drop
bChangeColors = !bChangeColors;
if (bChangeColors) {
cout << "Enable color changes" << endl;
}
else {
cout << "Disable color changes" << endl;
}
}
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
//cout << " Got mPressed at (" << x << "," << y << ")" << endl;
myMouseX = x;
myMouseY = y;
bNewMouseClick = true;
}
Thanks again.
Bob