diff --git a/api/Makefile.am b/api/Makefile.am index f49568a8ca..b680849310 100644 --- a/api/Makefile.am +++ b/api/Makefile.am @@ -12,6 +12,8 @@ graphics_api_files = \ graphics_api.C \ reduce.C \ gutil.C \ + bmplib.C \ + tgalib.C \ graphics_data.h \ reduce.h \ x_opengl.h \ diff --git a/api/bmplib.C b/api/bmplib.C new file mode 100644 index 0000000000..69a8e101b2 --- /dev/null +++ b/api/bmplib.C @@ -0,0 +1,186 @@ +#ifdef _WIN32 +#include "boinc_win.h" +#endif + +#include "bmplib.h" + +// Returns true for success -- false otherwise +bool DIB_BITMAP::set_size(int width, int height, int channels) +{ + + // If DIB_BITMAP has already been set -- clear it out first + FreeDIB_BMP(); + + // Create a temporary compatible device context + HDC temp_hdc = CreateCompatibleDC(NULL); + + // Error Check + if(!temp_hdc) + return false; + + bmp_width = width; // Set the width + bmp_height = height; // Set the height + bmp_channels = channels; // Set the channels (3 == 24-bit, 4 == 32-bit) + + // Set stride -- The stride is the TRUE number of bytes in a line of pixels + // Windows makes all the .bmps DWORD aligned (divisible evenly by 4) + // So if you bitmap say was 103x103 pixels, Windows would add 1 "padding byte" to it + // so in memory it would be 104x103 pixels. The "padding bytes" do not get blit (drawn) + // to the screen, they're just there so again everything is DWORD aligned which makes + // blitting (drawing to the screen) easier for the OS + bmp_stride = bmp_width * bmp_channels; + + while((bmp_stride % 4) != 0) // Ensure bmp_stride is DWORD aligned + bmp_stride++; + + BITMAPINFO bmp_info = {0}; + + // Initialize the parameters that we care about + bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmp_info.bmiHeader.biWidth = width; + bmp_info.bmiHeader.biHeight = height; + bmp_info.bmiHeader.biPlanes = 1; // Always equal 1 + bmp_info.bmiHeader.biBitCount = channels * 8; + bmp_info.bmiHeader.biCompression = BI_RGB; // No compression + bmp_info.bmiHeader.biClrUsed = 0; // Always equals 0 with a 24 or 32-bit .bmp + + // Create a DIBSection -- This returns us two things, an HBITMAP handle and + // a memory pointer (pointer to the pixels) in surface_bits + hbitmap = CreateDIBSection(temp_hdc, &bmp_info, DIB_RGB_COLORS, + (void**)&surface_bits, 0, 0); + + // Release our temporary HDC + DeleteDC(temp_hdc); + + // Error Check -- Make sure the call to CreateDIBSection() DID NOT fail + if(!hbitmap) + return false; + + return true; // We're sized :) + +} // end of set_size(int width, int height, int channels) + +bool DIB_BITMAP::loadBMP(const char *file_name) +{ + // If DIB_BITMAP has already been set -- clear it out first + FreeDIB_BMP(); + + // Error Check -- Make sure they passed in a valid file name + if(!file_name) + return false; + + FILE *bmp_file = fopen(file_name, "rb"); + + // Error Check -- Make sure the file could be opened + if(!bmp_file) + return false; + + BITMAPFILEHEADER bmp_fileheader; + + // Read the BITMAPFILEHEADER + if(!fread(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, bmp_file)) + { + fclose(bmp_file); + return false; + } + + // Check the type field to make sure we have a .bmp file + if(memcmp(&bmp_fileheader.bfType, "BM", 2)) + { + fclose(bmp_file); + return false; + } + + BITMAPINFOHEADER bmp_infoheader; + + // Read the BITMAPINFOHEADER. + if(!fread(&bmp_infoheader, sizeof(BITMAPINFOHEADER), 1, bmp_file)) + { + fclose(bmp_file); + return false; + } + + // We only support 24-bit and 32-bit .bmps so make sure that's what we have + if((bmp_infoheader.biBitCount != 24) && (bmp_infoheader.biBitCount != 32)) + { + fclose(bmp_file); + return false; + } + + // Set the size of our DIB_BITMAP, once we do this we're ready to store the pixel + // data in it + if(set_size(bmp_infoheader.biWidth,bmp_infoheader.biHeight,bmp_infoheader.biBitCount / 8) == false) + { + fclose(bmp_file); + return false; + } + + // Jump to the location where the pixel data is stored + if(fseek(bmp_file, bmp_fileheader.bfOffBits, SEEK_SET)) + { + fclose(bmp_file); + return false; + } + + unsigned int bytesPerLine = bmp_width * bmp_channels; // Bytes per line (number of bytes + // in a scan line) + + // Calculate how many "padding" bytes there are -- WE DO NOT want to read in the + // padding bytes (we will just skip over those) + // **Remember** Windows adds padding bytes to ensure ALL .bmps are DWORD aligned + // (divisible evenly by 4) + unsigned int padding = bmp_stride - bytesPerLine; + + // Loop over all the scan lines (all the rows of pixels in the image) + for(int y = bmp_height-1; y >= 0; y--) + { + // Get the "current" line pointer + uchar *LinePtr = getLinePtr(y); + + // Read the precise number of bytes that the scan line requires into the bitmap + if(!fread(LinePtr, bytesPerLine, 1, bmp_file)) + { + fclose(bmp_file); + return false; + } + + // Skip over any padding bytes. + if(fseek(bmp_file, padding, SEEK_CUR)) + { + fclose(bmp_file); + return false; + } + + } // end of for (int y = 0; y < bmp_infoheader.biHeight; y++) + + + fclose(bmp_file); + return true; // If we get here .bmp was read in successfully + +} // end of loadBMP(char *file_name, HDC hdc) + +// Returns the address in memory of the specified line. This gives you a pointer to at least +// width * channels bytes. Lines are numbered such that when the bitmap +// is displayed line zero is at the top. +uchar* DIB_BITMAP::getLinePtr(int which_line) +{ + return (surface_bits + bmp_stride * which_line); +} + +// Release the memory +void DIB_BITMAP::FreeDIB_BMP() +{ + // If we created an HBITMAP, delete it + if(hbitmap) + DeleteObject(hbitmap); + + // Zero out all data associated with DIB_BITMAP + hbitmap = NULL; + surface_bits = NULL; + bmp_width = bmp_height = bmp_channels = bmp_stride = 0; + return; +} + +// Deconstructor +DIB_BITMAP::~DIB_BITMAP() { FreeDIB_BMP(); } + diff --git a/api/bmplib.h b/api/bmplib.h new file mode 100644 index 0000000000..02385dda3e --- /dev/null +++ b/api/bmplib.h @@ -0,0 +1,57 @@ +#ifndef BITMAP_CLASS_H +#define BITMAP_CLASS_H + +typedef unsigned char uchar; // We're lazy so typedef "unsigned char" as "uchar" + +// We will use this class to load 24 and 32-bit .bmp for us +class DIB_BITMAP +{ + public: + + // Constructor() -- Zero's out DIB_BITMAP + DIB_BITMAP():hbitmap(NULL),surface_bits(NULL),bmp_width(0),bmp_height(0), + bmp_channels(0),bmp_stride(0) { GdiFlush(); /* Guarantee that writing to + DIB_BITMAP is okay */ } + + // Data Access Functions ************ + + inline int get_width() const { return bmp_width; } + inline int get_height() const { return bmp_height; } + inline int get_channels() const { return bmp_channels; } + inline int get_stride() const { return bmp_stride; } + + // ****** End of Data Access Functions + + // Creates a "empty" DIB_BITMAP with the "traits" of the parameters passed in + // Returns true for success -- false otherwise + // If set_size is called on a DIB_BITMAP that already has memory associated with it + // that memory is freed and the new size is implemented + bool set_size(int width, int height, int channels); + + // Loads a bmp with specified file_name -- Returns true on success, false otherwise + // If loadBMP() is called on a DIB_BITMAP that already has memory associated with + // it, that memory is freed and the .bmp is loaded + bool loadBMP(const char *file_name); + + uchar* getLinePtr(int which_line); // returns a pointer to the line passed in + + // Deconstructor(); + ~DIB_BITMAP(); + + + private: + + int bmp_width; // The width of the bitmap + int bmp_height; // The height of the bitmap + int bmp_channels; // How many channels is the bitmap (3 == 24-bit, 4 == 32-bit) + int bmp_stride; // The TRUE number of bytes in a scan line (in a line of pixels + // in memory) + + HBITMAP hbitmap; // This will be the handle to our bitmap + + uchar *surface_bits; // This is a pointer to the actual pixels of the bitmap + + void FreeDIB_BMP(); // Frees all memory associated with DIB_BITMAP +}; + +#endif diff --git a/api/tgalib.C b/api/tgalib.C new file mode 100644 index 0000000000..c8d457ca1f --- /dev/null +++ b/api/tgalib.C @@ -0,0 +1,239 @@ + + +#include "tgalib.h" + +tImageTGA *LoadTGA(const char *filename) +{ + tImageTGA *pImageData = NULL; // This stores our important image data + WORD width = 0, height = 0; // The dimensions of the image + byte length = 0; // The length in bytes to the pixels + byte imageType = 0; // The image type (RLE, RGB, Alpha...) + byte bits = 0; // The bits per pixel for the image (16, 24, 32) + FILE *pFile = NULL; // The file pointer + int channels = 0; // The channels of the image (3 = RGA : 4 = RGBA) + int stride = 0; // The stride (channels * width) + int i = 0; // A counter + + // This function loads in a TARGA (.TGA) file and returns its data to be + // used as a texture or what have you. This currently loads in a 16, 24 + // and 32-bit targa file, along with RLE compressed files. Eventually you + // will want to do more error checking to make it more robust. This is + // also a perfect start to go into a modular class for an engine. + // Basically, how it works is, you read in the header information, then + // move your file pointer to the pixel data. Before reading in the pixel + // data, we check to see the if it's an RLE compressed image. This is because + // we will handle it different. If it isn't compressed, then we need another + // check to see if we need to convert it from 16-bit to 24 bit. 24-bit and + // 32-bit textures are very similar, so there's no need to do anything special. + // We do, however, read in an extra bit for each color. + + // Open a file pointer to the targa file and check if it was found and opened + if((pFile = fopen(filename, "rb")) == NULL) + { + return NULL; + } + + // Allocate the structure that will hold our eventual image data (must free it!) + pImageData = (tImageTGA*)malloc(sizeof(tImageTGA)); + + // Read in the length in bytes from the header to the pixel data + fread(&length, sizeof(byte), 1, pFile); + + // Jump over one byte + fseek(pFile,1,SEEK_CUR); + + // Read in the imageType (RLE, RGB, etc...) + fread(&imageType, sizeof(byte), 1, pFile); + + // Skip past general information we don't care about + fseek(pFile, 9, SEEK_CUR); + + // Read the width, height and bits per pixel (16, 24 or 32) + fread(&width, sizeof(WORD), 1, pFile); + fread(&height, sizeof(WORD), 1, pFile); + fread(&bits, sizeof(byte), 1, pFile); + + // Now we move the file pointer to the pixel data + fseek(pFile, length + 1, SEEK_CUR); + + // Check if the image is RLE compressed or not + if(imageType != TGA_RLE) + { + // Check if the image is a 24 or 32-bit image + if(bits == 24 || bits == 32) + { + // Calculate the channels (3 or 4) - (use bits >> 3 for more speed). + // Next, we calculate the stride and allocate enough memory for the pixels. + channels = bits / 8; + stride = channels * width; + pImageData->data = new unsigned char[stride * height]; + + // Load in all the pixel data line by line + for(int y = 0; y < height; y++) + { + // Store a pointer to the current line of pixels + unsigned char *pLine = &(pImageData->data[stride * y]); + + // Read in the current line of pixels + fread(pLine, stride, 1, pFile); + + // Go through all of the pixels and swap the B and R values since TGA + // files are stored as BGR instead of RGB (or use GL_BGR_EXT verses GL_RGB) + for(i = 0; i < stride; i += channels) + { + int temp = pLine[i]; + pLine[i] = pLine[i + 2]; + pLine[i + 2] = temp; + } + } + } + // Check if the image is a 16 bit image (RGB stored in 1 unsigned short) + else if(bits == 16) + { + unsigned short pixels = 0; + int r=0, g=0, b=0; + + // Since we convert 16-bit images to 24 bit, we hardcode the channels to 3. + // We then calculate the stride and allocate memory for the pixels. + channels = 3; + stride = channels * width; + pImageData->data = new unsigned char[stride * height]; + + // Load in all the pixel data pixel by pixel + for(int i = 0; i < width*height; i++) + { + // Read in the current pixel + fread(&pixels, sizeof(unsigned short), 1, pFile); + + // To convert a 16-bit pixel into an R, G, B, we need to + // do some masking and such to isolate each color value. + // 0x1f = 11111 in binary, so since 5 bits are reserved in + // each unsigned short for the R, G and B, we bit shift and mask + // to find each value. We then bit shift up by 3 to get the full color. + b = (pixels & 0x1f) << 3; + g = ((pixels >> 5) & 0x1f) << 3; + r = ((pixels >> 10) & 0x1f) << 3; + + // This essentially assigns the color to our array and swaps the + // B and R values at the same time. + pImageData->data[i * 3 + 0] = r; + pImageData->data[i * 3 + 1] = g; + pImageData->data[i * 3 + 2] = b; + } + } + // Else return a NULL for a bad or unsupported pixel format + else + return NULL; + } + // Else, it must be Run-Length Encoded (RLE) + else + { + // First, let me explain real quickly what RLE is. + // For further information, check out Paul Bourke's intro article at: + // http://astronomy.swin.edu.au/~pbourke/dataformats/rle/ + // + // Anyway, we know that RLE is a basic type compression. It takes + // colors that are next to each other and then shrinks that info down + // into the color and a integer that tells how much of that color is used. + // For instance: + // aaaaabbcccccccc would turn into a5b2c8 + // Well, that's fine and dandy and all, but how is it down with RGB colors? + // Simple, you read in an color count (rleID), and if that number is less than 128, + // it does NOT have any optimization for those colors, so we just read the next + // pixels normally. Say, the color count was 28, we read in 28 colors like normal. + // If the color count is over 128, that means that the next color is optimized and + // we want to read in the same pixel color for a count of (colorCount - 127). + // It's 127 because we add 1 to the color count, as you'll notice in the code. + + // Create some variables to hold the rleID, current colors read, channels, & stride. + byte rleID = 0; + int colorsRead = 0; + channels = bits / 8; + stride = channels * width; + + // Next we want to allocate the memory for the pixels and create an array, + // depending on the channel count, to read in for each pixel. + pImageData->data = new unsigned char[stride * height]; + byte *pColors = new byte [channels]; + + // Load in all the pixel data + while(i < width*height) + { + // Read in the current color count + 1 + fread(&rleID, sizeof(byte), 1, pFile); + + // Check if we don't have an encoded string of colors + if(rleID < 128) + { + // Increase the count by 1 + rleID++; + + // Go through and read all the unique colors found + while(rleID) + { + // Read in the current color + fread(pColors, sizeof(byte) * channels, 1, pFile); + + // Store the current pixel in our image array + pImageData->data[colorsRead + 0] = pColors[2]; + pImageData->data[colorsRead + 1] = pColors[1]; + pImageData->data[colorsRead + 2] = pColors[0]; + + // If we have a 4 channel 32-bit image, assign one more for the alpha + if(bits == 32) + pImageData->data[colorsRead + 3] = pColors[3]; + + // Increase the current pixels read, decrease the amount + // of pixels left, and increase the starting index for the next pixel. + i++; + rleID--; + colorsRead += channels; + } + } + // Else, let's read in a string of the same character + else + { + // Minus the 128 ID + 1 (127) to get the color count that needs to be read + rleID -= 127; + + // Read in the current color, which is the same for a while + fread(pColors, sizeof(byte) * channels, 1, pFile); + + // Go and read as many pixels as are the same + while(rleID) + { + // Assign the current pixel to the current index in our pixel array + pImageData->data[colorsRead + 0] = pColors[2]; + pImageData->data[colorsRead + 1] = pColors[1]; + pImageData->data[colorsRead + 2] = pColors[0]; + + // If we have a 4 channel 32-bit image, assign one more for the alpha + if(bits == 32) + pImageData->data[colorsRead + 3] = pColors[3]; + + // Increase the current pixels read, decrease the amount + // of pixels left, and increase the starting index for the next pixel. + i++; + rleID--; + colorsRead += channels; + } + + } + + } + + // Free up pColors + delete[] pColors; + } + + // Close the file pointer that opened the file + fclose(pFile); + + // Fill in our tImageTGA structure to pass back + pImageData->channels = channels; + pImageData->sizeX = width; + pImageData->sizeY = height; + + // Return the TGA data (remember, you must free this data after you are done) + return pImageData; +} \ No newline at end of file diff --git a/api/tgalib.h b/api/tgalib.h new file mode 100644 index 0000000000..a6de515792 --- /dev/null +++ b/api/tgalib.h @@ -0,0 +1,22 @@ +#ifndef TGALIB_H +#define TGALIB_H + + +#include +#include + +#define TGA_RGB 2 // This tells us it's a normal RGB (really BGR) file +#define TGA_A 3 // This tells us it's a ALPHA file +#define TGA_RLE 10 // This tells us that the targa is Run-Length Encoded (RLE) + +struct tImageTGA +{ + int channels; // The channels in the image (3 = RGB : 4 = RGBA) + int sizeX; // The width of the image in pixels + int sizeY; // The height of the image in pixels + unsigned char *data; // The image pixel data +}; + +tImageTGA *LoadTGA(const char *filename); + +#endif \ No newline at end of file diff --git a/checkin_notes b/checkin_notes index 3b98aac23d..e44ea27b26 100755 --- a/checkin_notes +++ b/checkin_notes @@ -20926,3 +20926,11 @@ Rom 8 Dec 2004 clientgui/ BOINCBaseView.cpp + +David 8 Dec 2004 + - moved bmplib and tgalib from seti_boinc to boinc/api + + api/ + Makefile.am + bmplib.C,h (new) + tgalib.C,h (new) diff --git a/doc/boinc_dev.php b/doc/boinc_dev.php index 02a0c516b5..5adc63afea 100644 --- a/doc/boinc_dev.php +++ b/doc/boinc_dev.php @@ -51,15 +51,10 @@ before getting into the source code.
  • Core client/application interaction (graphics)
  • Disk space management -

    Scheduling server

    +

    Server programs

    -

    Back end

    -
      +
    • Work distribution policy
    • Backend state transitions
    • The logic of backend programs
    • Debugging server components diff --git a/doc/contact.php b/doc/contact.php index 89f472c38f..c7c9eb54a1 100644 --- a/doc/contact.php +++ b/doc/contact.php @@ -47,6 +47,7 @@ show_name("Gilson Laurent"); show_name("Bernd Machenschalk"); show_name("Sebastian Masch"); show_name("Kenichi Miyoshi"); +show_name("Kjell Nedrelid"); show_name("J.R. Oldroyd"); show_name("Jakob Pedersen"); show_name("Stephen Pellicer"); diff --git a/doc/links.php b/doc/links.php index a73a6ef556..258a284e04 100644 --- a/doc/links.php +++ b/doc/links.php @@ -106,6 +106,11 @@ show_link( "www.boinc.pl", "http://www.boinc.pl" ); +show_link( + "Portuguese", + "Portugal@home", + "http://portugalathome.pt.vu/" +); show_link( "Russian", "www.boinc.narod.ru", diff --git a/doc/sched_debug.php b/doc/sched_debug.php deleted file mode 100644 index 4981ff4e53..0000000000 --- a/doc/sched_debug.php +++ /dev/null @@ -1,25 +0,0 @@ - - -Here's a useful technique for troubleshooting scheduler problems: - -1) Copy the \"scheduler_request_X.xml\" file from a client to the - machine running the scheduler. (X = your project URL) - -2) Run the scheduler under the debugger, giving it this file as stdin, - i.e.: - - gdb cgi - (set a breakpoint) - r < scheduler_request_X.xml - -3) You may have to doctor the database as follows: - update host set rpc_seqno=0, rpc_time=0 where hostid=N - to keep the scheduler from rejecting the request. - -"; -page_tail(); -?> diff --git a/doc/sched_impl.php b/doc/sched_impl.php deleted file mode 100644 index 9c61bca9aa..0000000000 --- a/doc/sched_impl.php +++ /dev/null @@ -1,8 +0,0 @@ - -"; -page_tail(); -?> diff --git a/doc/sched_policy.php b/doc/sched_policy.php index 4f1437d48d..1fdf1cf12d 100644 --- a/doc/sched_policy.php +++ b/doc/sched_policy.php @@ -1,6 +1,6 @@ The scheduling server will attempt to send enough work to exceed a diff --git a/doc/server_debug.php b/doc/server_debug.php index 45e3479853..f1a4f84645 100644 --- a/doc/server_debug.php +++ b/doc/server_debug.php @@ -27,12 +27,28 @@ database-level problems.

      Scheduler single-stepping

      The scheduler is a CGI program. It reads from stdin and writes to stdout, -so you can also run it with a command-line debugger like gdb. -Direct a scheduler request file -(which you can copy from a client; -they're saved in files called sched_request_PROJECT.xml) -to stdin, set breakpoints, and start stepping through the code. -

      +so you can also run it with a command-line debugger like gdb: + +

        +
      • +Copy the \"scheduler_request_X.xml\" file from a client to the + machine running the scheduler. (X = your project URL) + +
      • +Run the scheduler under the debugger, giving it this file as stdin, + i.e.: + +
        +   gdb cgi
        +   (set a breakpoint)
        +   r < scheduler_request_X.xml
        +   
        + +
      • + You may have to doctor the database as follows: + update host set rpc_seqno=0, rpc_time=0 where hostid=N + to keep the scheduler from rejecting the request. +
      This is useful for figuring out why your project is generating 'no work available' messages. diff --git a/doc/tool_update_versions.php b/doc/tool_update_versions.php index 0e14162f62..e8366295b6 100644 --- a/doc/tool_update_versions.php +++ b/doc/tool_update_versions.php @@ -5,16 +5,17 @@ echo " The update_versions script releases new application versions. -It makes the needed database entries and copies files -to the download directory. +It creates database entries and copies files to the download directory.

      To use:

        -
      • Create an 'apps directory' under the project directory. -Add an ", htmlspecialchars(""), +
      • +If it doesn't already exit, +create an directory 'apps' under the project directory, +and add an ", htmlspecialchars(""), " element to config.xml giving the path of the apps directory.
      • Create a subdirectory for each application, -with the same name as the application. +with the short name of the application. Put new application versions here. update_versions scans these directories for new application versions. @@ -27,13 +28,14 @@ File names must be of the form NAME_VERSION_PLATFORM[.ext], e.g.: boinc_3.17_i686-pc-linux-gnu.gz astropulse_7.17_windows_intelx86.exe -The prefix name and extensions .gz, .exe, .sig are ignored.

        Important notes:

          -
        • Platform strings must match the names of platforms in the database. - If needed, add the platform to the DB. -
        • Your application must have the same major version number +
        • +Platform strings must match the names of platforms in the database. +If needed, add the platform to the DB. +
        • +Applications must have the same major version number as your BOINC server software.
        @@ -48,6 +50,14 @@ Recommended code-signing practices are described here. +

        +If a file of the form +

        +EXEC_FILENAME.file_ref_info
        +
        +is found, its contents will be added to the <file_info> +element describing the file +(you can use this for attributes like <copy_file>).

        Min/max core version

        Application versions have fields min_core_version and max_core_version which, if nonzero, @@ -55,7 +65,7 @@ indicates the range of core client version numbers to which the application version should be sent. Update_versions, by default, sets this to the largest core client version number in the database. -To change this, you can manually edit the app_version record. +To change this, you can manually update the app_version record.

        Multiple-file application versions