Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Loading Subset of Image File  (Read 14314 times)

0 Members and 1 Guest are viewing this topic.

lzr

  • Newbie
  • *
  • Posts: 48
    • View Profile
    • http://lzr.cc
Loading Subset of Image File
« on: April 27, 2008, 11:49:35 pm »
There are many times in the game I'm porting in which the engine loads a part of an image. The image file to be loaded maybe 256x256, but the game may only load a 64x64 chunk located at (32,128). I can't find any way currently for the engine to do this. The function that comes closest is sf::Image::Resize, but this only let's one specify a size, not a position. This would be a very useful, and fairly easy, feature to program for the future.

Edit: I decided to code the feature myself. If you want, you can add it to the actual code.

Code: [Select]

////////////////////////////////////////////////////////////
/// Resize the image (no offset) - warning : this function does not scale the image,
/// it just adjusts size (add padding or remove pixels)
////////////////////////////////////////////////////////////
bool Image::Resize(unsigned int Width, unsigned int Height, const Color& Col)
{
    return Resize(0, 0, Width, Height, Col);
}

////////////////////////////////////////////////////////////
/// Resize the image (with offset) - warning : this function does not scale the image,
/// it just adjusts size (add padding or remove pixels) and translates the image based on an offset
////////////////////////////////////////////////////////////
bool Image::Resize(unsigned int OffsetX, unsigned int OffsetY, unsigned int Width, unsigned int Height, const Color& Col)
{
    // Check size
    if ((Width == 0) || (Height == 0))
    {
        std::cerr << "Invalid new size for image (width = " << Width << ", height = " << Height << ")" << std::endl;
        return false;
    }

    // Create a new pixel array with the desired size
    std::vector<Color> Pixels(Width * Height, Col);

    // Copy the old pixel buffer into the new one
    for (unsigned int i = OffsetX; i < std::min(Width+OffsetX, myWidth); ++i)
        for (unsigned int j = OffsetY; j < std::min(Height+OffsetY, myHeight); ++j)
            Pixels[(i-OffsetX) + (j-OffsetY) * Width] = myPixels[i + j * myWidth];
    Pixels.swap(myPixels);

    // Store the new texture dimensions
    myWidth  = Width;
    myHeight = Height;

    // We can create the texture
    if (CreateTexture())
    {
        return true;
    }
    else
    {
        // Oops... something failed
        Reset();
        return false;
    }
}

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Loading Subset of Image File
« Reply #1 on: April 28, 2008, 03:11:13 am »
Yep, I'm planning to add such function.

But I think I'd rather provide a subrect to the Load functions ; it would be more efficient.
Laurent Gomila - SFML developer

kolofsson

  • Full Member
  • ***
  • Posts: 100
    • View Profile
Loading Subset of Image File
« Reply #2 on: May 29, 2008, 11:58:33 am »
What you've done here Izr is I guess not RESIZE, but CLIP. Besides, your function has to load the whole image first and then it clips a part of it.

I guess it would be much more efficient and useful if we could specify the coordinates to extract from an image on the disk.

Would it be hard to implement huge image support in SFML? I mean an engine that would cut the image into rectangles for the openGL and take care of keeping all pieces in the right place when rotating or zooming?

Either loading part of an image or adding large image support would help me a lot. Thanks.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Loading Subset of Image File
« Reply #3 on: May 29, 2008, 10:06:55 pm »
Quote
Would it be hard to implement huge image support in SFML? I mean an engine that would cut the image into rectangles for the openGL and take care of keeping all pieces in the right place when rotating or zooming?

I won't be simple, but this is an important feature and I'll have to find a solution. This will be one of the priorities for the next version.
Laurent Gomila - SFML developer

lzr

  • Newbie
  • *
  • Posts: 48
    • View Profile
    • http://lzr.cc
Loading Subset of Image File
« Reply #4 on: June 21, 2008, 04:32:13 am »
Yeah, I know that clips not resizes. But the original Resize function also clipped, it just didn't let you choose which part of the image to clip from. The syntax of the load function and the Resize function is very similar, yet for some reason, I can't get the code functioning properly in the load function. There's probably some stupid thing I'm missing, maybe you could take a look at it and figure it out. Giving a value of 0 for the Width or the Height gives the image the original width and height.

Code: [Select]

////////////////////////////////////////////////////////////
/// Load pixels from an image file in memory
////////////////////////////////////////////////////////////
bool ImageLoader::LoadImageFromMemory(const char* Data, std::size_t SizeInBytes, std::vector<Color>& Pixels, unsigned int X, unsigned int Y, unsigned int& Width, unsigned int& Height)
{
    // Clear the array (just in case)
    Pixels.clear();

    // Load the image and get a pointer to the pixels in memory
    const unsigned char* Buffer = reinterpret_cast<const unsigned char*>(Data);
    int Size = static_cast<int>(SizeInBytes);
    int ImgWidth, ImgHeight, ImgChannels;
unsigned int uimgWidth,uimgHeight;
    unsigned char* PixelsPtr = SOIL_load_image_from_memory(Buffer, Size, &ImgWidth, &ImgHeight, &ImgChannels, SOIL_LOAD_RGBA);

    if (PixelsPtr)
    {
        // Assign the image properties
uimgWidth=ImgWidth, uimgHeight=ImgHeight;

if(Width==0) Width  = ImgWidth-X;
        if(Height==0) Height = ImgHeight-Y;

        // Copy the loaded pixels to the pixel buffer
        Pixels.reserve(Width * Height);
for (unsigned int x = X; x < std::min<unsigned int>(Width+X, uimgWidth); ++x)
for (unsigned int y = Y; y < std::min<unsigned int>(Height+Y, uimgHeight); ++y)
            {
                Uint8* Pixel = PixelsPtr + (y + x * uimgHeight) * 4;
                Pixels.push_back(Color(Pixel[0], Pixel[1], Pixel[2], Pixel[3]));
            }

        // Free the loaded pixels (they are now in our own pixel buffer)
        SOIL_free_image_data(PixelsPtr);

        return true;
    }
    else
    {
        // Error, failed to load the image
        std::cerr << "Failed to load image from memory. Reason : " << SOIL_last_result() << std::endl;

        return false;
    }
}


In my old engine, which was DirectX based, I made a class that did basically what you described. It was a separate class from the regular Picture class and it would load an image of any size and split it into an Array of pictures, which could then be drawn.