示例#1
0
文件: Util.cpp 项目: krichter722/0ad
// <extension> identifies the file format that is to be written
// (case-insensitive). examples: "bmp", "png", "jpg".
// BMP is good for quick output at the expense of large files.
void WriteScreenshot(const VfsPath& extension)
{
    // get next available numbered filename
    // note: %04d -> always 4 digits, so sorting by filename works correctly.
    const VfsPath basenameFormat(L"screenshots/screenshot%04d");
    const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension);
    VfsPath filename;
    vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);

    const size_t w = (size_t)g_xres, h = (size_t)g_yres;
    const size_t bpp = 24;
    GLenum fmt = GL_RGB;
    int flags = TEX_BOTTOM_UP;
    // we want writing BMP to be as fast as possible,
    // so read data from OpenGL in BMP format to obviate conversion.
    if(extension == L".bmp")
    {
#if !CONFIG2_GLES // GLES doesn't support BGR
        fmt = GL_BGR;
        flags |= TEX_BGR;
#endif
    }

    // Hide log messages and re-render
    RenderLogger(false);
    Render();
    RenderLogger(true);

    const size_t img_size = w * h * bpp/8;
    const size_t hdr_size = tex_hdr_size(filename);
    shared_ptr<u8> buf;
    AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
    GLvoid* img = buf.get() + hdr_size;
    Tex t;
    if(t.wrap(w, h, bpp, flags, buf, hdr_size) < 0)
        return;
    glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img);

    if (tex_write(&t, filename) == INFO::OK)
    {
        OsPath realPath;
        g_VFS->GetRealPath(filename, realPath);

        LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());

        debug_printf(
            CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
            realPath.string8().c_str());
    }
    else
        LOGERROR("Error writing screenshot to '%s'", filename.string8());
}
示例#2
0
		/**
		 * Debug function for AI scripts to dump 2D array data (e.g. terrain tile weights).
		 */
		static void DumpImage(void* UNUSED(cbdata), std::wstring name, std::vector<u32> data, u32 w, u32 h, u32 max)
		{
			// TODO: this is totally not threadsafe.

			VfsPath filename = L"screenshots/aidump/" + name;

			if (data.size() != w*h)
			{
				debug_warn(L"DumpImage: data size doesn't match w*h");
				return;
			}

			if (max == 0)
			{
				debug_warn(L"DumpImage: max must not be 0");
				return;
			}

			const size_t bpp = 8;
			int flags = TEX_BOTTOM_UP|TEX_GREY;

			const size_t img_size = w * h * bpp/8;
			const size_t hdr_size = tex_hdr_size(filename);
			shared_ptr<u8> buf;
			AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
			Tex t;
			if (tex_wrap(w, h, bpp, flags, buf, hdr_size, &t) < 0)
				return;

			u8* img = buf.get() + hdr_size;
			for (size_t i = 0; i < data.size(); ++i)
				img[i] = (u8)((data[i] * 255) / max);

			tex_write(&t, filename);
			tex_free(&t);
		}
示例#3
0
文件: Util.cpp 项目: krichter722/0ad
// Similar to WriteScreenshot, but generates an image of size 640*tiles x 480*tiles.
void WriteBigScreenshot(const VfsPath& extension, int tiles)
{
    // If the game hasn't started yet then use WriteScreenshot to generate the image.
    if(g_Game == NULL) {
        WriteScreenshot(L".bmp");
        return;
    }

    // get next available numbered filename
    // note: %04d -> always 4 digits, so sorting by filename works correctly.
    const VfsPath basenameFormat(L"screenshots/screenshot%04d");
    const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension);
    VfsPath filename;
    vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);

    // Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and
    // hope the screen is actually large enough for that.
    const int tile_w = 640, tile_h = 480;
    ENSURE(g_xres >= tile_w && g_yres >= tile_h);

    const int img_w = tile_w*tiles, img_h = tile_h*tiles;
    const int bpp = 24;
    GLenum fmt = GL_RGB;
    int flags = TEX_BOTTOM_UP;
    // we want writing BMP to be as fast as possible,
    // so read data from OpenGL in BMP format to obviate conversion.
    if(extension == L".bmp")
    {
#if !CONFIG2_GLES // GLES doesn't support BGR
        fmt = GL_BGR;
        flags |= TEX_BGR;
#endif
    }

    const size_t img_size = img_w * img_h * bpp/8;
    const size_t tile_size = tile_w * tile_h * bpp/8;
    const size_t hdr_size = tex_hdr_size(filename);
    void* tile_data = malloc(tile_size);
    if(!tile_data)
    {
        WARN_IF_ERR(ERR::NO_MEM);
        return;
    }
    shared_ptr<u8> img_buf;
    AllocateAligned(img_buf, hdr_size+img_size, maxSectorSize);

    Tex t;
    GLvoid* img = img_buf.get() + hdr_size;
    if(t.wrap(img_w, img_h, bpp, flags, img_buf, hdr_size) < 0)
    {
        free(tile_data);
        return;
    }

    ogl_WarnIfError();

    // Resize various things so that the sizes and aspect ratios are correct
    {
        g_Renderer.Resize(tile_w, tile_h);
        SViewPort vp = { 0, 0, tile_w, tile_h };
        g_Game->GetView()->GetCamera()->SetViewPort(vp);
        g_Game->GetView()->SetCameraProjection();
    }

#if !CONFIG2_GLES
    // Temporarily move everything onto the front buffer, so the user can
    // see the exciting progress as it renders (and can tell when it's finished).
    // (It doesn't just use SwapBuffers, because it doesn't know whether to
    // call the SDL version or the Atlas version.)
    GLint oldReadBuffer, oldDrawBuffer;
    glGetIntegerv(GL_READ_BUFFER, &oldReadBuffer);
    glGetIntegerv(GL_DRAW_BUFFER, &oldDrawBuffer);
    glDrawBuffer(GL_FRONT);
    glReadBuffer(GL_FRONT);
#endif

    // Hide the cursor
    CStrW oldCursor = g_CursorName;
    g_CursorName = L"";

    // Render each tile
    for (int tile_y = 0; tile_y < tiles; ++tile_y)
    {
        for (int tile_x = 0; tile_x < tiles; ++tile_x)
        {
            // Adjust the camera to render the appropriate region
            g_Game->GetView()->GetCamera()->SetProjectionTile(tiles, tile_x, tile_y);

            RenderLogger(false);
            RenderGui(false);
            Render();
            RenderGui(true);
            RenderLogger(true);

            // Copy the tile pixels into the main image
            glReadPixels(0, 0, tile_w, tile_h, fmt, GL_UNSIGNED_BYTE, tile_data);
            for (int y = 0; y < tile_h; ++y)
            {
                void* dest = (char*)img + ((tile_y*tile_h + y) * img_w + (tile_x*tile_w)) * bpp/8;
                void* src = (char*)tile_data + y * tile_w * bpp/8;
                memcpy(dest, src, tile_w * bpp/8);
            }
        }
    }

    // Restore the old cursor
    g_CursorName = oldCursor;

#if !CONFIG2_GLES
    // Restore the buffer settings
    glDrawBuffer(oldDrawBuffer);
    glReadBuffer(oldReadBuffer);
#endif

    // Restore the viewport settings
    {
        g_Renderer.Resize(g_xres, g_yres);
        SViewPort vp = { 0, 0, g_xres, g_yres };
        g_Game->GetView()->GetCamera()->SetViewPort(vp);
        g_Game->GetView()->SetCameraProjection();
        g_Game->GetView()->GetCamera()->SetProjectionTile(1, 0, 0);
    }

    if (tex_write(&t, filename) == INFO::OK)
    {
        OsPath realPath;
        g_VFS->GetRealPath(filename, realPath);

        LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());

        debug_printf(
            CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
            realPath.string8().c_str());
    }
    else
        LOGERROR("Error writing screenshot to '%s'", filename.string8());

    free(tile_data);
}