📄 bubblemon.c
字号:
r = ((((int)c1.components.r) * (255 - amount)) + (((int)c2.components.r) * amount)) / 255; g = ((((int)c1.components.g) * (255 - amount)) + (((int)c2.components.g) * amount)) / 255; b = ((((int)c1.components.b) * (255 - amount)) + (((int)c2.components.b) * amount)) / 255; a = ((((int)c1.components.a) * (255 - amount)) + (((int)c2.components.a) * amount)) / 255; /* assert(a >= 0 && a <= 255); assert(r >= 0 && r <= 255); assert(g >= 0 && g <= 255); assert(b >= 0 && b <= 255); assert(((c1.components.a <= a) && (a <= c2.components.a)) || ((c1.components.a >= a) && (a >= c2.components.a))); assert(((c1.components.r <= r) && (r <= c2.components.r)) || ((c1.components.r >= r) && (r >= c2.components.r))); assert(((c1.components.g <= g) && (g <= c2.components.g)) || ((c1.components.g >= g) && (g >= c2.components.g))); assert(((c1.components.b <= b) && (b <= c2.components.b)) || ((c1.components.b >= b) && (b >= c2.components.b))); */ returnme.components.r = r; returnme.components.g = g; returnme.components.b = b; returnme.components.a = a; assert((amount != 0) || (returnme.value == c1.value)); assert((amount != 255) || (returnme.value == c2.value)); return returnme;}/* Update the bubble array from the system load */static void bubblemon_updatePhysics(int msecsSinceLastCall, int youveGotMail){ /* No size -- no go */ if ((bubblePic.width == 0) || (bubblePic.height == 0)) { assert(bubblePic.pixels == NULL); assert(bubblePic.airAndWater == NULL); return; } /* Make sure the water levels exist */ if (physics.waterLevels == NULL) { physics.waterLevels = (bubblemon_WaterLevel *)calloc(bubblePic.width, sizeof(bubblemon_WaterLevel)); assert(physics.waterLevels != NULL); } /* Make sure the sea-weeds exist */ if (physics.weeds == NULL) { int i; physics.weeds = (bubblemon_Weed *)calloc(bubblePic.width, sizeof(bubblemon_Weed)); assert(physics.weeds != NULL); // Colorize the weeds for (i = 0; i < bubblePic.width; i++) { static int stripey = 0; physics.weeds[i].color = bubblemon_interpolateColor(bubblemon_constant2color(WEEDCOLOR0), bubblemon_constant2color(WEEDCOLOR1), (random() % 156) + stripey); stripey = 100 - stripey; } } /* Make sure the bubbles exist */ if (physics.bubbles == NULL) { physics.n_bubbles = 0; // FIXME: max_bubbles should be the width * the time it takes for // a bubble to rise all the way to the ceiling. physics.max_bubbles = (bubblePic.width * bubblePic.height) / 5; physics.bubbles = (bubblemon_Bubble *)calloc(physics.max_bubbles, sizeof(bubblemon_Bubble)); assert(physics.bubbles != NULL); } /* Update our universe */ bubblemon_updateWaterlevels(msecsSinceLastCall); bubblemon_updateWeeds(msecsSinceLastCall); bubblemon_updateBubbles(msecsSinceLastCall); bubblemon_updateBottle(msecsSinceLastCall, youveGotMail);}int bubblemon_getMemoryPercentage(){ int returnme; if (sysload.memorySize == 0L) { returnme = 0; } else { returnme = (int)((200L * sysload.memoryUsed + 1) / (2 * sysload.memorySize)); }#ifdef ENABLE_PROFILING return 100;#else return returnme;#endif}int bubblemon_getSwapPercentage(){ int returnme; if (sysload.swapSize == 0L) { returnme = 0; } else { returnme = (int)((200L * sysload.swapUsed + 1) / (2 * sysload.swapSize)); }#ifdef ENABLE_PROFILING return 100;#else return returnme;#endif}/* The cpu parameter is the cpu number, 1 - #CPUs. 0 means average load */int bubblemon_getCpuLoadPercentage(int cpuNo){ assert(cpuNo >= 0 && cpuNo < sysload.nCpus); #ifdef ENABLE_PROFILING return 100;#else return sysload.cpuLoad[cpuNo];#endif}int bubblemon_getAverageLoadPercentage(){ int cpuNo; int totalLoad; totalLoad = 0; for (cpuNo = 0; cpuNo < sysload.nCpus; cpuNo++) { totalLoad += bubblemon_getCpuLoadPercentage(cpuNo); } totalLoad = totalLoad / sysload.nCpus; assert(totalLoad >= 0); assert(totalLoad <= 100);#ifdef ENABLE_PROFILING return 100;#else return totalLoad;#endif}static void bubblemon_censorLoad(){ /* Calculate the projected memory + swap load to show the user. The values given to the user is how much memory the system is using relative to the total amount of electronic RAM. The swap color indicates how much memory above the amount of electronic RAM the system is using. This scheme does *not* show how the system has decided to allocate swap and electronic RAM to the users' processes. */ u_int64_t censoredMemUsed; u_int64_t censoredSwapUsed; assert(sysload.memorySize > 0); censoredMemUsed = sysload.swapUsed + sysload.memoryUsed; if (censoredMemUsed > sysload.memorySize) { censoredSwapUsed = censoredMemUsed - sysload.memorySize; censoredMemUsed = sysload.memorySize; } else { censoredSwapUsed = 0; } /* Sanity check that we don't use more swap/mem than what's available */ assert((censoredMemUsed <= sysload.memorySize) && (censoredSwapUsed <= sysload.swapSize)); sysload.memoryUsed = censoredMemUsed; sysload.swapUsed = censoredSwapUsed;#ifdef ENABLE_PROFILING sysload.memoryUsed = sysload.memorySize; sysload.swapUsed = sysload.swapSize;#endif}static void bubblemon_draw_bubble(/*@out@*/ bubblemon_picture_t *bubblePic, int x, int y){ bubblemon_colorcode_t *bubbleBuf = bubblePic->airAndWater; int w = bubblePic->width; int h = bubblePic->height; bubblemon_colorcode_t *buf_ptr; /* Clipping is not necessary for x, but it is for y. To prevent ugliness, we draw aliascolor only on top of watercolor, and aircolor on top of aliascolor. */ /* Top row */ buf_ptr = &(bubbleBuf[(y - 1) * w + x - 1]); if (y <= physics.waterLevels[x].y) { if (*buf_ptr != AIR) { (*buf_ptr)++ ; } buf_ptr++; *buf_ptr = AIR; buf_ptr++; if (*buf_ptr != AIR) { (*buf_ptr)++ ; } buf_ptr += (w - 2); } else { buf_ptr += w; } /* Middle row - no clipping necessary */ *buf_ptr = AIR; buf_ptr++; *buf_ptr = AIR; buf_ptr++; *buf_ptr = AIR; buf_ptr += (w - 2); /* Bottom row */ if (y < (h - 1)) { if (*buf_ptr != AIR) { (*buf_ptr)++ ; } buf_ptr++; *buf_ptr = AIR; buf_ptr++; if (*buf_ptr != AIR) { (*buf_ptr)++ ; } }}static void bubblemon_environmentToBubbleArray(bubblemon_picture_t *bubblePic, bubblemon_layer_t layer){ // Render bubbles, waterlevels and stuff into the bubblePic int w = bubblePic->width; int h = bubblePic->height; int x, y, i; float hf; bubblemon_Bubble *bubble; if (bubblePic->airAndWater == NULL) { bubblePic->airAndWater = (bubblemon_colorcode_t *)malloc(w * h * sizeof(bubblemon_colorcode_t)); assert(bubblePic->airAndWater != NULL); } // Draw the air and water background for (x = 0; x < w; x++) { bubblemon_colorcode_t *pixel; double dummy; float waterHeight = physics.waterLevels[x].y; int nAirPixels = h - waterHeight; int antialias = 0; if (modf(waterHeight, &dummy) >= 0.5) { nAirPixels--; antialias = 1; } pixel = &(bubblePic->airAndWater[x]); for (y = 0; y < nAirPixels; y++) { *pixel = AIR; pixel += w; } if (antialias) { *pixel = ANTIALIAS; pixel += w; y++; } for (; y < h; y++) { *pixel = WATER; pixel += w; } } // Draw the bubbles bubble = physics.bubbles; hf = h; // Move the int->float cast out of the loop for (i = 0; i < physics.n_bubbles; i++) { if (bubble->layer >= layer) { bubblemon_draw_bubble(bubblePic, bubble->x, hf - bubble->y); } bubble++; }}static void bubblemon_bubbleArrayToPixmap(bubblemon_picture_t *bubblePic, bubblemon_layer_t layer){ static bubblemon_color_t noSwapAirColor; static bubblemon_color_t noSwapWaterColor; static bubblemon_color_t maxSwapAirColor; static bubblemon_color_t maxSwapWaterColor; bubblemon_color_t colors[3]; bubblemon_colorcode_t *airOrWater; bubblemon_color_t *pixel; int i; int w, h; noSwapAirColor = bubblemon_constant2color(NOSWAPAIRCOLOR); noSwapWaterColor = bubblemon_constant2color(NOSWAPWATERCOLOR); maxSwapAirColor = bubblemon_constant2color(MAXSWAPAIRCOLOR); maxSwapWaterColor = bubblemon_constant2color(MAXSWAPWATERCOLOR); colors[AIR] = bubblemon_interpolateColor(noSwapAirColor, maxSwapAirColor, (bubblemon_getSwapPercentage() * 255) / 100); colors[WATER] = bubblemon_interpolateColor(noSwapWaterColor, maxSwapWaterColor, (bubblemon_getSwapPercentage() * 255) / 100); colors[ANTIALIAS] = bubblemon_interpolateColor(colors[AIR], colors[WATER], 128); w = bubblePic->width; h = bubblePic->height; /* Make sure the pixel array exist */ if (bubblePic->pixels == NULL) { bubblePic->pixels = (bubblemon_color_t *)malloc(bubblePic->width * bubblePic->height * sizeof(bubblemon_color_t)); assert(bubblePic->pixels != NULL); } pixel = bubblePic->pixels; airOrWater = bubblePic->airAndWater; if (layer == BACKGROUND) { // Erase the old pic as we draw for (i = 0; i < w * h; i++) { *pixel++ = colors[*airOrWater++]; } } else { // Draw on top of the current pic for (i = 0; i < w * h; i++) { bubblemon_color_t myColor = colors[*airOrWater++]; *pixel = bubblemon_interpolateColor(*pixel, myColor, myColor.components.a); pixel++; } }}static void bubblemon_bottleToPixmap(bubblemon_picture_t *bubblePic){ int bottleX, bottleY; int bottleW, bottleH; int bottleYMin, bottleYMax; int pictureX0, pictureY0; int pictureW, pictureH; if (physics.bottle_state == GONE) { return; } assert(bubblePic->pixels != NULL); pictureW = bubblePic->width; pictureH = bubblePic->height; bottleW = msgInBottle.width; bottleH = msgInBottle.height; // Ditch the bottle if the image is too small // FIXME: Should we check the image height as well? if (pictureW < (bottleW + 4)) { return; } // Center the bottle horizontally pictureX0 = (bubblePic->width - bottleW) / 2; // Position the bottle vertically pictureY0 = pictureH - physics.bottle_y - bottleH / 2; // Clip the bottle vertically to fit it into the picture bottleYMin = 0; if (pictureY0 < 0) { bottleYMin = -pictureY0; } bottleYMax = bottleH; if (pictureY0 + bottleH >= pictureH) { bottleYMax = bottleH - (pictureY0 + bottleH - pictureH); } // Iterate over the bottle for (bottleX = 0; bottleX < bottleW; bottleX++) { for (bottleY = bottleYMin; bottleY < bottleYMax; bottleY++) { int pictureX = pictureX0 + bottleX; int pictureY = pictureY0 + bottleY; bubblemon_color_t bottlePixel; bubblemon_color_t *picturePixel; // assert(pictureY < pictureH); bottlePixel = ((bubblemon_color_t*)(msgInBottle.pixel_data))[bottleX + bottleY * bottleW]; picturePixel = &(bubblePic->pixels[pictureX + pictureY * pictureW]); *picturePixel = bubblemon_interpolateColor(*picturePixel, bottlePixel, bottlePixel.components.a); } }}static void bubblemon_weedsToPixmap(bubblemon_picture_t *bubblePic){ int w = bubblePic->width; int h = bubblePic->height; int x; for (x = 0; x < w; x++) { int y; int highestWeedPixel = h - physics.weeds[x].height; for (y = highestWeedPixel; y < h; y++) { bubblePic->pixels[y * w + x] = bubblemon_interpolateColor(bubblePic->pixels[y * w + x], physics.weeds[x].color, physics.weeds[x].color.components.a); } }}const bubblemon_picture_t *bubblemon_getPicture(){ static const int msecsPerPhysicsFrame = 1000 / PHYSICS_FRAMERATE; static int physicalTimeElapsed = 0; int msecsSinceLastCall = bubblemon_getMsecsSinceLastCall(); int youveGotMail = mail_hasUnreadMail(); // Get the system load meter_getLoad(&sysload); bubblemon_censorLoad(); // Update the network load statistics. Since they measure a real // time phenomenon, they need to keep track of how much real time // has actually passed since last time. Thus, we provide the // uncensored msecsSinceLastCall. netload_updateLoadstats(msecsSinceLastCall); // If a "long" time has passed since the last frame, settle for // updating the physics just a bit of the way. if (msecsSinceLastCall > 200) { msecsSinceLastCall = 200; } // Push the universe around if (msecsSinceLastCall <= msecsPerPhysicsFrame) { bubblemon_updatePhysics(msecsSinceLastCall, youveGotMail); } else { while (physicalTimeElapsed < msecsSinceLastCall) { bubblemon_updatePhysics(msecsPerPhysicsFrame, youveGotMail); physicalTimeElapsed += msecsPerPhysicsFrame; } physicalTimeElapsed -= msecsSinceLastCall; } // Draw the pixels bubblemon_environmentToBubbleArray(&bubblePic, BACKGROUND); bubblemon_bubbleArrayToPixmap(&bubblePic, BACKGROUND); bubblemon_weedsToPixmap(&bubblePic); bubblemon_bottleToPixmap(&bubblePic); bubblemon_environmentToBubbleArray(&bubblePic, FOREGROUND); bubblemon_bubbleArrayToPixmap(&bubblePic, FOREGROUND); return &bubblePic;}int main(int argc, char *argv[]){ int exitcode;#ifdef ENABLE_PROFILING fprintf(stderr, "Warning: " PACKAGE " has been configured with --enable-profiling and will show max\n" "load all the time.\n");#endif // Initialize the random number generation srandom(time(NULL)); // Initialize the load metering meter_init(argc, argv, &sysload); sysload.cpuLoad = (int *)calloc(sysload.nCpus, sizeof(int)); assert(sysload.cpuLoad != NULL); // Initialize the bottle physics.bottle_state = GONE; // Do the disco duck exitcode = ui_main(argc, argv); // Terminate the load metering meter_done(); return exitcode;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -