texHeightInput    = dynamicTextureIDs[CA_TEXTURE_HEIGHT_SOURCE]; texHeightOutput   = dynamicTextureIDs[CA_TEXTURE_HEIGHT_TARGET];  texVelocityInput  = dynamicTextureIDs[CA_TEXTURE_VELOCITY_SOURCE]; texVelocityOutput = dynamicTextureIDs[CA_TEXTURE_VELOCITY_TARGET];
texHeightInput    = dynamicTextures[CA_TEXTURE_HEIGHT_SOURCE].getTextureObject(); texHeightOutput   = dynamicTextures[CA_TEXTURE_HEIGHT_TARGET].getTextureObject();  texVelocityInput  = dynamicTextures[CA_TEXTURE_VELOCITY_SOURCE].getTextureObject(); texVelocityOutput = dynamicTextures[CA_TEXTURE_VELOCITY_TARGET].getTextureObject();
  private void doSingleTimeStep(GL gl) {    int temp;    // Swap texture source & target indices & pointers    //  0 = start from initial loaded texture    //  1/2 = flip flop back and forth between targets & sources    switch (flipState) {    case 0:      texHeightInput    = dynamicTextureIDs[CA_TEXTURE_HEIGHT_SOURCE];       // initial height map.      texHeightOutput   = dynamicTextureIDs[CA_TEXTURE_HEIGHT_TARGET];    // next height map.      texVelocityInput  = dynamicTextureIDs[CA_TEXTURE_VELOCITY_SOURCE];  // initial velocity.      texVelocityOutput = dynamicTextureIDs[CA_TEXTURE_VELOCITY_TARGET];  // next velocity.      // Clear initial velocity texture to 0x80 == gray      gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);      gl.glClear(GL.GL_COLOR_BUFFER_BIT);      // Now we need to copy the resulting pixels into the intermediate force field texture      gl.glActiveTexture(GL.GL_TEXTURE0);      gl.glBindTexture(GL.GL_TEXTURE_2D, texVelocityInput);      // use CopyTexSubImage for speed (even though we copy all of it) since we pre-allocated the texture      gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, 0, 0, initialMapDimensions[0], initialMapDimensions[1]);      break;              case 1:      temp              = texHeightInput;      texHeightInput    = texHeightOutput;      texHeightOutput   = temp;      temp              = texVelocityInput;      texVelocityInput  = texVelocityOutput;      texVelocityOutput = temp;      break;    case 2:      temp              = texHeightInput;      texHeightInput    = texHeightOutput;      texHeightOutput   = temp;      temp              = texVelocityInput;      texVelocityInput  = texVelocityOutput;      texVelocityOutput = temp;      break;    }	    // even if wireframe mode, render to texture as solid    gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);	    /////////////////////////////////////////////////////////////    //  Render first 3 components of force from three neighbors    //  Offsets selected are 1 center texel for center height    //    and 3 of the 4 nearest neighbors.  Texture selected    //    is same for all stages as we're turning height difference    //    of nearest neightbor texels into a force value.    gl.glCallList(displayListIDs[CA_FRAGMENT_PROGRAM_NEIGHBOR_FORCE_CALC_1]);    // set current source texture for stage 0 texture    for (int i = 0; i < 4; i++)      {        gl.glActiveTexture(GL.GL_TEXTURE0 + i);        gl.glBindTexture(GL.GL_TEXTURE_2D, texHeightInput);        gl.glEnable(GL.GL_TEXTURE_2D);      }    int wrapMode = wrap ? GL.GL_REPEAT : GL.GL_CLAMP_TO_EDGE;    gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, wrapMode);    gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, wrapMode);    // disable blending    gl.glDisable(GL.GL_BLEND);    // render using offset 1 (type 1 -- center + 3 of 4 nearest neighbors).    gl.glProgramEnvParameter4fARB(GL.GL_VERTEX_PROGRAM_ARB, CV_UV_OFFSET_TO_USE, 1, 0, 0, 0);    // bind the vertex program to be used for this step and the next one.    gl.glBindProgramARB(GL.GL_VERTEX_PROGRAM_ARB, vertexProgramID);    gl.glEnable(GL.GL_VERTEX_PROGRAM_ARB);    // render a screen quad. with texture coords doing difference of nearby texels for force calc.    gl.glCallList(displayListIDs[CA_DRAW_SCREEN_QUAD]);    gl.glDisable(GL.GL_FRAGMENT_PROGRAM_ARB);    // Now we need to copy the resulting pixels into the intermediate force field texture    gl.glActiveTexture(GL.GL_TEXTURE2);    gl.glBindTexture(GL.GL_TEXTURE_2D, dynamicTextureIDs[CA_TEXTURE_FORCE_INTERMEDIATE]);    // use CopyTexSubImage for speed (even though we copy all of it) since we pre-allocated the texture    gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, 0, 0, initialMapDimensions[0], initialMapDimensions[1]);    ////////////////////////////////////////////////////////////////    // Now add in last component of force for the 4th neighbor    //  that we didn't have enough texture lookups to do in the     //  first pass    gl.glCallList(displayListIDs[CA_FRAGMENT_PROGRAM_NEIGHBOR_FORCE_CALC_2]);        // Cannot use additive blending as the force contribution might    //   be negative and would have to subtract from the dest.    // We must instead use an additional texture as target and read    //   the previous partial 3-neighbor result into the pixel shader    //   for possible subtraction    // Alphablend must be false    //; t0 = center  (same as last phase)    //; t1 = 2nd axis final point (same as last phase)    //; t2 = previous partial result texture sampled at center (result of last phase copied to texture)    //; t3 = not used (disable now)    gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, wrapMode);    gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, wrapMode);    gl.glActiveTexture(GL.GL_TEXTURE3);    gl.glDisable(GL.GL_TEXTURE_2D);    // vertex program already bound.    // render using offset 2 (type 2 -- final nearest neighbor plus center of previous result).    gl.glProgramEnvParameter4fARB(GL.GL_VERTEX_PROGRAM_ARB, CV_UV_OFFSET_TO_USE, 2, 0, 0, 0);    // render a screen quad    gl.glCallList(displayListIDs[CA_DRAW_SCREEN_QUAD]);    gl.glDisable(GL.GL_FRAGMENT_PROGRAM_ARB);    // Now we need to copy the resulting pixels into the intermediate force field texture    gl.glActiveTexture(GL.GL_TEXTURE1);    gl.glBindTexture(GL.GL_TEXTURE_2D, dynamicTextureIDs[CA_TEXTURE_FORCE_TARGET]);    // use CopyTexSubImage for speed (even though we copy all of it) since we pre-allocated the texture    gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, 0, 0, initialMapDimensions[0], initialMapDimensions[1]);    /////////////////////////////////////////////////////////////////    // Apply the force with a scale factor to reduce it's magnitude.    // Add this to the current texture representing the water height.        gl.glCallList(displayListIDs[CA_FRAGMENT_PROGRAM_APPLY_FORCE]);    // use offsets of zero    gl.glProgramEnvParameter4fARB(GL.GL_VERTEX_PROGRAM_ARB, CV_UV_OFFSET_TO_USE, 0, 0, 0, 0);    // bind the vertex program to be used for this step and the next one.    gl.glActiveTexture(GL.GL_TEXTURE0);    gl.glBindTexture(GL.GL_TEXTURE_2D, texVelocityInput);    gl.glActiveTexture(GL.GL_TEXTURE1);    gl.glBindTexture(GL.GL_TEXTURE_2D, dynamicTextureIDs[CA_TEXTURE_FORCE_TARGET]);    gl.glActiveTexture(GL.GL_TEXTURE2);    gl.glDisable(GL.GL_TEXTURE_2D);    gl.glActiveTexture(GL.GL_TEXTURE3);    gl.glDisable(GL.GL_TEXTURE_2D);    // Draw the quad to add in force.    gl.glCallList(displayListIDs[CA_DRAW_SCREEN_QUAD]);    gl.glDisable(GL.GL_FRAGMENT_PROGRAM_ARB);    ///////////////////////////////////////////////////////////////////    // With velocity texture selected, render new excitation droplets    //   at random freq.    float randomFrequency = (float) Math.random();    if (dropletFrequency > randomFrequency) {      // a drop falls - decide where      Droplet drop = new Droplet(2 * ((float)Math.random() - 0.5f),                                 2 * ((float)Math.random() - 0.5f),                                 0.02f +  0.1f * ((float)Math.random()));      addDroplet(drop);    }    //  Now draw the droplets:    if (!droplets.isEmpty()) {      drawDroplets(gl);      droplets.clear();    }    // Now we need to copy the resulting pixels into the velocity texture    gl.glActiveTexture(GL.GL_TEXTURE1);    gl.glBindTexture(GL.GL_TEXTURE_2D, texVelocityOutput);    // use CopyTexSubImage for speed (even though we copy all of it) since we pre-allocated the texture    gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, 0, 0, initialMapDimensions[0], initialMapDimensions[1]);      //////////////////////////////////////////////////////////////////////    // Apply velocity to position    gl.glCallList(displayListIDs[CA_FRAGMENT_PROGRAM_APPLY_VELOCITY]);    gl.glEnable(GL.GL_VERTEX_PROGRAM_ARB);    gl.glActiveTexture(GL.GL_TEXTURE0);    gl.glBindTexture(GL.GL_TEXTURE_2D, texHeightInput);    gl.glActiveTexture(GL.GL_TEXTURE1); // velocity output already bound    gl.glEnable(GL.GL_TEXTURE_2D);    // use offsets of zero    gl.glProgramEnvParameter4fARB(GL.GL_VERTEX_PROGRAM_ARB, CV_UV_OFFSET_TO_USE, 0, 0, 0, 0);    // Draw the quad to add in force.    gl.glCallList(displayListIDs[CA_DRAW_SCREEN_QUAD]);    gl.glDisable(GL.GL_FRAGMENT_PROGRAM_ARB);    // Now we need to copy the resulting pixels into the input height texture    gl.glActiveTexture(GL.GL_TEXTURE0);    gl.glBindTexture(GL.GL_TEXTURE_2D, texHeightInput);        // use CopyTexSubImage for speed (even though we copy all of it) since we pre-allocated the texture    gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, 0, 0, initialMapDimensions[0], initialMapDimensions[1]);     ///////////////////////////////////////////////////////////////////    //  blur positions to smooth noise & generaly dampen things    //  degree of blur is controlled by magnitude of 4 neighbor texel    //   offsets with bilinear on        for (int i = 1; i < 4; i++) {      gl.glActiveTexture(GL.GL_TEXTURE0 + i);      gl.glBindTexture(GL.GL_TEXTURE_2D, texHeightInput);      gl.glEnable(GL.GL_TEXTURE_2D);    }    // use offsets of 3    gl.glProgramEnvParameter4fARB(GL.GL_VERTEX_PROGRAM_ARB, CV_UV_OFFSET_TO_USE, 3, 0, 0, 0);    gl.glCallList(displayListIDs[CA_FRAGMENT_PROGRAM_EQ_WEIGHT_COMBINE]);    gl.glCallList(displayListIDs[CA_DRAW_SCREEN_QUAD]);    gl.glDisable(GL.GL_FRAGMENT_PROGRAM_ARB);    // Draw the logo in the water.    if (applyInteriorBoundaries) {      gl.glDisable(GL.GL_VERTEX_PROGRAM_ARB);      drawInteriorBoundaryObjects(gl);    }    // Now we need to copy the resulting pixels into the velocity texture    gl.glActiveTexture(GL.GL_TEXTURE0);    gl.glBindTexture(GL.GL_TEXTURE_2D, texHeightOutput);    // use CopyTexSubImage for speed (even though we copy all of it) since we pre-allocated the texture    gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, 0, 0, initialMapDimensions[0], initialMapDimensions[1]);          ///////////////////////////////////////////////////////////////////    // If selected, create a normal map from the height          if (createNormalMap) {      createNormalMap(gl);    }          ///////////////////////////////////////////////////////////    // Flip the state variable for the next round of rendering    switch (flipState) {    case 0:      flipState = 1;      break;    case 1:      flipState = 2;      break;    case 2:      flipState = 1;      break;    }  }