ion::ion () { float temp; pos = rsVec (0.0f, 0.0f, 0.0f); rgb = rsVec (0.0f, 0.0f, 0.0f); temp = rsRandf (2.0f) + 0.4f; size = float (dSize) * temp; speed = float (dSpeed) * 12.0f / temp; }
void ion::update () { int i; int startOver = 0; static float startOverDistance; static rsVec force, tempvec; static float length, temp; force = rsVec (0.0f, 0.0f, 0.0f); for (i = 0; i < dEmitters; i++) { tempvec = pos - elist[i].pos; length = tempvec.normalize (); if (length > 11000.0f) startOver = 1; if (length <= 1.0f) temp = 1.0f; else temp = 1.0f / length; tempvec *= temp; force += tempvec; } startOverDistance = speed * elapsedTime; for (i = 0; i < dAttracters; i++) { tempvec = alist[i].pos - pos; length = tempvec.normalize (); if (length < startOverDistance) startOver = 1; if (length <= 1.0f) temp = 1.0f; else temp = 1.0f / length; tempvec *= temp; force += tempvec; } // Start this ion at an emitter if it gets too close to an attracter // or too far from an emitter if (startOver) start (); else { force.normalize (); pos += (force * elapsedTime * speed); } }
rsVec operator / (const float &div) {float rec = 1.0f/div; return(rsVec(v[0]*rec, v[1]*rec, v[2]*rec));};
rsVec operator * (const float &mul) {return(rsVec(v[0]*mul, v[1]*mul, v[2]*mul));};
rsVec operator - (const rsVec &vec) {return(rsVec(v[0]-vec[0], v[1]-vec[1], v[2]-vec[2]));};
rsVec operator + (const rsVec &vec) {return(rsVec(v[0]+vec[0], v[1]+vec[1], v[2]+vec[2]));};
void hack_draw (xstuff_t * XStuff, double currentTime, float frameTime) { int i; static int ionsReleased = 0; static float releaseTime = 0.0f; Display *dpy = XStuff->display; #ifdef BENCHMARK static int a = 1; #endif Window window = XStuff->window; elapsedTime = frameTime; #ifdef BENCHMARK if (a++ == 1000) exit(0); elapsedTime = 0.1f; #endif // Camera movements // first do translation (distance from center) static float oldCameraDistance; static float cameraDistance; static float targetCameraDistance = -1000.0f; static float preCameraInterp = PI; float cameraInterp; preCameraInterp += float (dCameraspeed) * elapsedTime * 0.01f; cameraInterp = 0.5f - (0.5f * cos (preCameraInterp)); cameraDistance = (1.0f - cameraInterp) * oldCameraDistance + cameraInterp * targetCameraDistance; if (preCameraInterp >= PI) { oldCameraDistance = targetCameraDistance; targetCameraDistance = -rsRandf (1300.0f) - 200.0f; preCameraInterp = 0.0f; } glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (0.0, 0.0, cameraDistance); // then do rotation static rsVec radialVel = rsVec (0.0f, 0.0f, 0.0f); static rsVec targetRadialVel = radialVel; static rsQuat rotQuat = rsQuat (0.0f, 0.0f, 0.0f, 1.0f); rsVec radialVelDiff = targetRadialVel - radialVel; float changeRemaining = radialVelDiff.normalize (); float change = float (dCameraspeed) * 0.0002f * elapsedTime; if (changeRemaining > change) { radialVelDiff *= change; radialVel += radialVelDiff; } else { radialVel = targetRadialVel; if (rsRandi (2)) { targetRadialVel = rsVec (rsRandf (1.0f), rsRandf (1.0f), rsRandf (1.0f)); targetRadialVel.normalize (); targetRadialVel *= float (dCameraspeed) * rsRandf (0.002f); } else targetRadialVel = rsVec (0.0f, 0.0f, 0.0f); } rsVec tempRadialVel = radialVel; float angle = tempRadialVel.normalize (); rsQuat radialQuat; radialQuat.make (angle, tempRadialVel[0], tempRadialVel[1], tempRadialVel[2]); rotQuat.preMult (radialQuat); rsMatrix rotMat; rotMat.fromQuat (rotQuat); // make billboard matrix for rotating particles when they are drawn rotMat.get (billboardMat); // Calculate new color static rsVec oldHsl, newHsl = rsVec (rsRandf (1.0f), 1.0f, 1.0f), targetHsl; static float colorInterp = 1.0f, colorChange; colorInterp += elapsedTime * colorChange; if (colorInterp >= 1.0f) { if (!rsRandi (3) && dIons >= 100) // change color suddenly newHsl = rsVec (rsRandf (1.0f), 1.0f - (rsRandf (1.0f) * rsRandf (1.0f)), 1.0f); oldHsl = newHsl; targetHsl = rsVec (rsRandf (1.0f), 1.0f - (rsRandf (1.0f) * rsRandf (1.0f)), 1.0f); colorInterp = 0.0f; // amount by which to change colorInterp each second colorChange = rsRandf (0.005f * float (dSpeed)) + (0.002f * float (dSpeed)); } else { float diff = targetHsl[0] - oldHsl[0]; if (diff < -0.5f || (diff > 0.0f && diff < 0.5f)) newHsl[0] = oldHsl[0] + colorInterp * diff; else newHsl[0] = oldHsl[0] - colorInterp * diff; diff = targetHsl[1] - oldHsl[1]; newHsl[1] = oldHsl[1] + colorInterp * diff; if (newHsl[0] < 0.0f) newHsl[0] += 1.0f; if (newHsl[0] > 1.0f) newHsl[0] -= 1.0f; hsl2rgb (newHsl[0], newHsl[1], 1.0f, newRgb[0], newRgb[1], newRgb[2]); } // Release ions if (ionsReleased < dIons) { releaseTime -= elapsedTime; while (ionsReleased < dIons && releaseTime <= 0.0f) { ilist[ionsReleased].start (); ionsReleased++; // all ions released after 2 minutes releaseTime += 120.0f / float (dIons); } } // Set interpolation value for emitters and attracters static float wait = 0.0f; static float preinterp = PI, interp; static float interpconst = 0.001f; wait -= elapsedTime; if (wait <= 0.0f) { preinterp += elapsedTime * float (dSpeed) * interpconst; interp = 0.5f - (0.5f * cos (preinterp)); } if (preinterp >= PI) { // select new taget points (not the same pattern twice in a row) static int newTarget = 0, lastTarget; lastTarget = newTarget; newTarget = rsRandi (10); if (newTarget == lastTarget) newTarget++; setTargets (newTarget); preinterp = 0.0f; interp = 0.0f; wait = 10.0f; // pause after forming each new pattern interpconst = 0.001f; if (!rsRandi (4)) // interpolate really fast sometimes interpconst = 0.1f; } // Update particles for (i = 0; i < dEmitters; i++) { elist[i].interppos (interp); elist[i].update (); } for (i = 0; i < dAttracters; i++) { alist[i].interppos (interp); alist[i].update (); } for (i = 0; i < ionsReleased; i++) ilist[i].update (); // Calculate surface if (dSurface) { for (i = 0; i < dEmitters; i++) spheres[i].setPosition (elist[i].pos[0], elist[i].pos[1], elist[i].pos[2]); for (i = 0; i < dAttracters; i++) spheres[dEmitters + i].setPosition (alist[i].pos[0], alist[i].pos[1], alist[i].pos[2]); impCrawlPointVector cpv; for(i=0; i<dEmitters+dAttracters; i++) spheres[i].addCrawlPoint(cpv); surface->reset (); static float valuetrig = 0.0f; valuetrig += elapsedTime; volume->setSurfaceValue(0.45f + 0.05f * cosf(valuetrig)); volume->makeSurface(cpv); } // Draw // clear the screen if (dBlur) { // partially glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity(); glOrtho(0.0, 1.0, 0.0, 1.0, 1.0, -1.0); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.0f, 0.0f, 0.0f, 0.5f - (float(sqrtf(sqrtf(float(dBlur)))) * 0.15495f)); glBegin(GL_TRIANGLE_STRIP); glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(1.0f, 0.0f, 0.0f); glVertex3f(0.0f, 1.0f, 0.0f); glVertex3f(1.0f, 1.0f, 0.0f); glEnd(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); } else // completely glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Draw ions glMatrixMode(GL_MODELVIEW); glBlendFunc (GL_ONE, GL_ONE); glBindTexture (GL_TEXTURE_2D, 1); for (i = 0; i < ionsReleased; i++) ilist[i].draw (); // Draw surfaces float brightFactor = 0; float surfaceColor[3] = { 0.0f, 0.0f, 0.0f }; if (dSurface) { glBindTexture (GL_TEXTURE_2D, 2); glEnable (GL_TEXTURE_GEN_S); glEnable (GL_TEXTURE_GEN_T); // find color for surfaces if (dIons >= 100) { if (dWireframe) brightFactor = 2.0f / (float (dBlur + 30) * float (dBlur + 30)); else brightFactor = 4.0f / (float (dBlur + 30) * float (dBlur + 30)); for (i = 0; i < 100; i++) { surfaceColor[0] += ilist[i].rgb[0] * brightFactor; surfaceColor[1] += ilist[i].rgb[1] * brightFactor; surfaceColor[2] += ilist[i].rgb[2] * brightFactor; } glColor3fv (surfaceColor); } else { if (dWireframe) brightFactor = 200.0f / (float (dBlur + 30) * float (dBlur + 30)); else brightFactor = 400.0f / (float (dBlur + 30) * float (dBlur + 30)); glColor3f (newRgb[0] * brightFactor, newRgb[1] * brightFactor, newRgb[2] * brightFactor); } // draw the surface glPushMatrix (); glMultMatrixf (billboardMat); if (dWireframe) { glDisable (GL_TEXTURE_2D); surface->draw_wireframe (); glEnable (GL_TEXTURE_2D); } else surface->draw (); glPopMatrix (); glDisable (GL_TEXTURE_GEN_S); glDisable (GL_TEXTURE_GEN_T); } // If graphics card does a true buffer swap instead of a copy swap // then everything must get drawn on both buffers if (dBlur & pfd_swap_exchange) { glXSwapBuffers (dpy, window); // wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f (0.0f, 0.0f, 0.0f, 0.5f - (float (sqrt (sqrt (double (dBlur)))) * 0.15495f)); glPushMatrix (); glLoadIdentity (); glBegin (GL_TRIANGLE_STRIP); glVertex3f (-5.0f, -4.0f, -3.0f); glVertex3f (5.0f, -4.0f, -3.0f); glVertex3f (-5.0f, 4.0f, -3.0f); glVertex3f (5.0f, 4.0f, -3.0f); glEnd (); glPopMatrix (); // Draw ions glBlendFunc (GL_ONE, GL_ONE); glBindTexture (GL_TEXTURE_2D, 1); for (i = 0; i < ionsReleased; i++) ilist[i].draw (); // Draw surfaces if (dSurface) { glBindTexture (GL_TEXTURE_2D, 2); glEnable (GL_TEXTURE_GEN_S); glEnable (GL_TEXTURE_GEN_T); if (dIons >= 100) glColor3fv (surfaceColor); else glColor3f (newRgb[0] * brightFactor, newRgb[1] * brightFactor, newRgb[2] * brightFactor); glPushMatrix (); glMultMatrixf (billboardMat); if (dWireframe) { glDisable (GL_TEXTURE_2D); surface->draw_wireframe (); glEnable (GL_TEXTURE_2D); } else surface->draw (); glPopMatrix (); glDisable (GL_TEXTURE_GEN_S); glDisable (GL_TEXTURE_GEN_T); } } }
void setTargets (int whichTarget) { int i; switch (whichTarget) { case 0: // random for (i = 0; i < dEmitters; i++) elist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f))); for (i = 0; i < dAttracters; i++) alist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f))); break; case 1: { // line (all emitters on one side, all attracters on the other) float position = -500.0f, change = 1000.0f / float (dEmitters + dAttracters - 1); for (i = 0; i < dEmitters; i++) { elist[i].settargetpos (rsVec (rsVec (position, position * 0.5f, 0.0f))); position += change; } for (i = 0; i < dAttracters; i++) { alist[i].settargetpos (rsVec (rsVec (position, position * 0.5f, 0.0f))); position += change; } break; } case 2: { // line (emitters and attracters staggered) float change; if (dEmitters > dAttracters) { change = 1000.0f / float (dEmitters * 2 - 1); } else { change = 1000.0f / float (dAttracters * 2 - 1); } float position = -500.0f; for (i = 0; i < dEmitters; i++) { elist[i].settargetpos (rsVec (rsVec (position, position * 0.5f, 0.0f))); position += change * 2.0f; } position = -500.0f + change; for (i = 0; i < dAttracters; i++) { alist[i].settargetpos (rsVec (rsVec (position, position * 0.5f, 0.0f))); position += change * 2.0f; } break; } case 3: { // 2 lines (parallel) float change = 1000.0f / float (dEmitters * 2 - 1); float position = -500.0f; float height = -525.0f + float (dEmitters * 25); for (i = 0; i < dEmitters; i++) { elist[i].settargetpos (rsVec (rsVec (position, height, -50.0f))); position += change * 2.0f; } change = 1000.0f / float (dAttracters * 2 - 1); position = -500.0f; height = 525.0f - float (dAttracters * 25); for (i = 0; i < dAttracters; i++) { alist[i].settargetpos (rsVec (rsVec (position, height, 50.0f))); position += change * 2.0f; } break; } case 4: { // 2 lines (skewed) float change = 1000.0f / float (dEmitters * 2 - 1); float position = -500.0f; float height = -525.0f + float (dEmitters * 25); for (i = 0; i < dEmitters; i++) { elist[i].settargetpos (rsVec (rsVec (position, height, 0.0f))); position += change * 2.0f; } change = 1000.0f / float (dAttracters * 2 - 1); position = -500.0f; height = 525.0f - float (dAttracters * 25); for (i = 0; i < dAttracters; i++) { alist[i].settargetpos (rsVec (rsVec (10.0f, height, position))); position += change * 2.0f; } break; } case 5: // random distribution across a plane for (i = 0; i < dEmitters; i++) elist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, 0.0f, rsRandf (1000.0f) - 500.0f))); for (i = 0; i < dAttracters; i++) alist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, 0.0f, rsRandf (1000.0f) - 500.0f))); break; case 6: { // random distribution across 2 planes float height = -525.0f + float (dEmitters * 25); for (i = 0; i < dEmitters; i++) elist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, height, rsRandf (1000.0f) - 500.0f))); height = 525.0f - float (dAttracters * 25); for (i = 0; i < dAttracters; i++) alist[i].settargetpos (rsVec (rsVec (rsRandf (1000.0f) - 500.0f, height, rsRandf (1000.0f) - 500.0f))); break; } case 7: { // 2 rings (1 inside and 1 outside) float angle = 0.5f, cosangle, sinangle; float change = PIx2 / float (dEmitters); for (i = 0; i < dEmitters; i++) { angle += change; cosangle = cos (angle) * 200.0f; sinangle = sin (angle) * 200.0f; elist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f))); } angle = 1.5f; change = PIx2 / float (dAttracters); for (i = 0; i < dAttracters; i++) { angle += change; cosangle = cos (angle) * 500.0f; sinangle = sin (angle) * 500.0f; alist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f))); } break; } case 8: { // ring (all emitters on one side, all attracters on the other) float angle = 0.5f, cosangle, sinangle; float change = PIx2 / float (dEmitters + dAttracters); for (i = 0; i < dEmitters; i++) { angle += change; cosangle = cos (angle) * 500.0f; sinangle = sin (angle) * 500.0f; elist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f))); } for (i = 0; i < dAttracters; i++) { angle += change; cosangle = cos (angle) * 500.0f; sinangle = sin (angle) * 500.0f; alist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f))); } break; } case 9: { // ring (emitters and attracters staggered) float change; if (dEmitters > dAttracters) { change = PIx2 / float (dEmitters * 2); } else { change = PIx2 / float (dAttracters * 2); } float angle = 0.5f, cosangle, sinangle; for (i = 0; i < dEmitters; i++) { cosangle = cos (angle) * 500.0f; sinangle = sin (angle) * 500.0f; elist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f))); angle += change * 2.0f; } angle = 0.5f + change; for (i = 0; i < dAttracters; i++) { cosangle = cos (angle) * 500.0f; sinangle = sin (angle) * 500.0f; alist[i].settargetpos (rsVec (rsVec (cosangle, sinangle, 0.0f))); angle += change * 2.0f; } break; } case 10: // 2 points for (i = 0; i < dEmitters; i++) elist[i].settargetpos (rsVec (rsVec (500.0f, 100.0f, 50.0f))); for (i = 0; i < dAttracters; i++) alist[i].settargetpos (rsVec (rsVec (-500.0f, -100.0f, -50.0f))); break; } }
attracter::attracter () { pos = rsVec (rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f); }
emitter::emitter () { pos = rsVec (rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f, rsRandf (1000.0f) - 500.0f); }