如何在 OpenGL 中截取屏幕截图

发布于 2024-11-04 10:43:20 字数 255 浏览 4 评论 0原文

如何使用 C++ 截取 OpenGL 窗口的屏幕截图并将其保存到文件。

我找到了 glReadPixels()函数, 但我不知道下一步该做什么。例如,我可以在哪里设置文件的路径?

如果不难的话,请写代码。

How to take a screenshot of an OpenGL window in C++ and save it to file.

I found the glReadPixels() function,
but I don't know what to do next. Where I can set path to a file, for example?

If not difficult, write code, please.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

心碎无痕… 2024-11-11 10:43:20

这段代码捕获 OpenGL 窗口并导出到 BMP 文件。您必须有 FreeImage 库才能运行它。

// Make the BYTE array, factor of 3 because it's RBG.
BYTE* pixels = new BYTE[3 * width * height];

glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);

// Convert to FreeImage format & save to file
FIBITMAP* image = FreeImage_ConvertFromRawBits(pixels, width, height, 3 * width, 24, 0x0000FF, 0xFF0000, 0x00FF00, false);
FreeImage_Save(FIF_BMP, image, "C:/test.bmp", 0);

// Free resources
FreeImage_Unload(image);
delete [] pixels;

This piece of code captures the OpenGL window and export to a BMP file. You must have FreeImage library to run it.

// Make the BYTE array, factor of 3 because it's RBG.
BYTE* pixels = new BYTE[3 * width * height];

glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);

// Convert to FreeImage format & save to file
FIBITMAP* image = FreeImage_ConvertFromRawBits(pixels, width, height, 3 * width, 24, 0x0000FF, 0xFF0000, 0x00FF00, false);
FreeImage_Save(FIF_BMP, image, "C:/test.bmp", 0);

// Free resources
FreeImage_Unload(image);
delete [] pixels;
我要还你自由 2024-11-11 10:43:20

glReadPixels 将复制位写入您提供的内存缓冲区中。您必须手动格式化数据(为您选择的图像格式)并将其写入磁盘glReadPixels 返回。

glReadPixels will copy the bits into a memory buffer that you supply. You have to manually format the data (to the image format of your choice) and write it to disk after glReadPixels returns.

最美不过初阳 2024-11-11 10:43:20

可运行示例

每次在窗口上单击鼠标时,都会使用当前屏幕截图创建一个 tmpX.ppm 文件。

您可以在 Linux 上使用 eog 查看此文件,并使用文本编辑器检查它。

要在不显示窗口的情况下进行渲染,请参阅:如何使用GLUT/OpenGL 渲染到文件?

#include <math.h>
#include <stdlib.h>
#include <stdio.h>

#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glext.h>

static GLubyte *pixels = NULL;
static const GLenum FORMAT = GL_RGBA;
static const GLuint FORMAT_NBYTES = 4;
static const unsigned int HEIGHT = 500;
static const unsigned int WIDTH = 500;
static unsigned int nscreenshots = 0;
static unsigned int time;

/* Model. */
static double angle = 0;
static double angle_speed = 45;

static void init(void)  {
    glReadBuffer(GL_BACK);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glViewport(0, 0, WIDTH, HEIGHT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);

    pixels = malloc(FORMAT_NBYTES * WIDTH * HEIGHT);
    time = glutGet(GLUT_ELAPSED_TIME);
}

static void deinit(void)  {
    free(pixels);
}

static void create_ppm(char *prefix, int frame_id, unsigned int width, unsigned int height,
        unsigned int color_max, unsigned int pixel_nbytes, GLubyte *pixels) {
    size_t i, j, k, cur;
    enum Constants { max_filename = 256 };
    char filename[max_filename];
    snprintf(filename, max_filename, "%s%d.ppm", prefix, frame_id);
    FILE *f = fopen(filename, "w");
    fprintf(f, "P3\n%d %d\n%d\n", width, HEIGHT, 255);
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            cur = pixel_nbytes * ((height - i - 1) * width + j);
            fprintf(f, "%3d %3d %3d ", pixels[cur], pixels[cur + 1], pixels[cur + 2]);
        }
        fprintf(f, "\n");
    }
    fclose(f);
}

static void draw_scene() {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glRotatef(angle, 0.0f, 0.0f, -1.0f);
    glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f( 0.0f,  0.5f, 0.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, 0.0f);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f( 0.5f, -0.5f, 0.0f);
    glEnd();
}

static void display(void) {
    draw_scene();
    glutSwapBuffers();
    glReadPixels(0, 0, WIDTH, HEIGHT, FORMAT, GL_UNSIGNED_BYTE, pixels);
}

static void idle(void) {
    int new_time = glutGet(GLUT_ELAPSED_TIME);
    angle += angle_speed * (new_time - time) / 1000.0;
    angle = fmod(angle, 360.0);
    time = new_time;
    glutPostRedisplay();
}

void mouse(int button, int state, int x, int y) {
    if (state == GLUT_DOWN) {
        puts("screenshot");
        create_ppm("tmp", nscreenshots, WIDTH, HEIGHT, 255, FORMAT_NBYTES, pixels);
        nscreenshots++;
    }
}

int main(int argc, char **argv) {
    GLint glut_display;
    glutInit(&argc, argv);
    glutInitWindowSize(WIDTH, HEIGHT);
    glutInitWindowPosition(100, 100);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    glutMouseFunc(mouse);
    atexit(deinit);
    glutMainLoop();
    return EXIT_SUCCESS;
}

编译:

gcc main.c -lm -lGL -lGLU -lglut

在 Ubuntu 15.10、OpenGL 4.5.0 NVIDIA 352.63 上测试。

Vulkan

这个例子刚刚工作:https ://github.com/SaschaWillems/Vulkan/blob/b9f0ac91d2adccc3055a904d3a8f6553b10ff6cd/examples/screenshot/screenshot.cpp 如何运行它:是否可以在 Vulkan 中不使用 Surface 进行离屏渲染?

在此处输入图像描述

Runnable example

Each time you click with the mouse on the window, a tmpX.ppm file is created with the current screenshot.

You can view this file for example with eog on Linux, and inspect it with a text editor.

To render without showing a window, see: How to use GLUT/OpenGL to render to a file?

#include <math.h>
#include <stdlib.h>
#include <stdio.h>

#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glext.h>

static GLubyte *pixels = NULL;
static const GLenum FORMAT = GL_RGBA;
static const GLuint FORMAT_NBYTES = 4;
static const unsigned int HEIGHT = 500;
static const unsigned int WIDTH = 500;
static unsigned int nscreenshots = 0;
static unsigned int time;

/* Model. */
static double angle = 0;
static double angle_speed = 45;

static void init(void)  {
    glReadBuffer(GL_BACK);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glViewport(0, 0, WIDTH, HEIGHT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);

    pixels = malloc(FORMAT_NBYTES * WIDTH * HEIGHT);
    time = glutGet(GLUT_ELAPSED_TIME);
}

static void deinit(void)  {
    free(pixels);
}

static void create_ppm(char *prefix, int frame_id, unsigned int width, unsigned int height,
        unsigned int color_max, unsigned int pixel_nbytes, GLubyte *pixels) {
    size_t i, j, k, cur;
    enum Constants { max_filename = 256 };
    char filename[max_filename];
    snprintf(filename, max_filename, "%s%d.ppm", prefix, frame_id);
    FILE *f = fopen(filename, "w");
    fprintf(f, "P3\n%d %d\n%d\n", width, HEIGHT, 255);
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            cur = pixel_nbytes * ((height - i - 1) * width + j);
            fprintf(f, "%3d %3d %3d ", pixels[cur], pixels[cur + 1], pixels[cur + 2]);
        }
        fprintf(f, "\n");
    }
    fclose(f);
}

static void draw_scene() {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glRotatef(angle, 0.0f, 0.0f, -1.0f);
    glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f( 0.0f,  0.5f, 0.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, 0.0f);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f( 0.5f, -0.5f, 0.0f);
    glEnd();
}

static void display(void) {
    draw_scene();
    glutSwapBuffers();
    glReadPixels(0, 0, WIDTH, HEIGHT, FORMAT, GL_UNSIGNED_BYTE, pixels);
}

static void idle(void) {
    int new_time = glutGet(GLUT_ELAPSED_TIME);
    angle += angle_speed * (new_time - time) / 1000.0;
    angle = fmod(angle, 360.0);
    time = new_time;
    glutPostRedisplay();
}

void mouse(int button, int state, int x, int y) {
    if (state == GLUT_DOWN) {
        puts("screenshot");
        create_ppm("tmp", nscreenshots, WIDTH, HEIGHT, 255, FORMAT_NBYTES, pixels);
        nscreenshots++;
    }
}

int main(int argc, char **argv) {
    GLint glut_display;
    glutInit(&argc, argv);
    glutInitWindowSize(WIDTH, HEIGHT);
    glutInitWindowPosition(100, 100);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    glutMouseFunc(mouse);
    atexit(deinit);
    glutMainLoop();
    return EXIT_SUCCESS;
}

Compile with:

gcc main.c -lm -lGL -lGLU -lglut

Tested on Ubuntu 15.10, OpenGL 4.5.0 NVIDIA 352.63.

Vulkan

This example just worked: https://github.com/SaschaWillems/Vulkan/blob/b9f0ac91d2adccc3055a904d3a8f6553b10ff6cd/examples/screenshot/screenshot.cpp how to run it: Is it possible to do offscreen rendering without Surface in Vulkan?

enter image description here

酒几许 2024-11-11 10:43:20

一个简单快速的解决方案。

  • 输出 TARGA 文件,但可以轻松转换为 PNG(提供脚本)。
  • 不需要额外的库。
  • 可以与 C 和 C++ 一起使用(有一些细微的变化)。
  • 注意:输出文件应具有tga 文件扩展名。

下面是代码:

void saveScreenshotToFile(std::string filename, int windowWidth, int windowHeight) {    
    const int numberOfPixels = windowWidth * windowHeight * 3;
    unsigned char pixels[numberOfPixels];

    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glReadBuffer(GL_FRONT);
    glReadPixels(0, 0, windowWidth, windowHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);

    FILE *outputFile = fopen(filename.c_str(), "w");
    short header[] = {0, 2, 0, 0, 0, 0, (short) windowWidth, (short) windowHeight, 24};

    fwrite(&header, sizeof(header), 1, outputFile);
    fwrite(pixels, numberOfPixels, 1, outputFile);
    fclose(outputFile);

    printf("Finish writing to file.\n");
}

并调用函数:

saveScreenshotToFile("test.tga", 1200, 900);

将 TARGA 文件转换为 PNG 的 bash 脚本:

for oldFileName in *.tga; do
    [ -f "$oldFileName" ] || break         # Break out if no .tga files found.
    newFileName=${oldFileName//.tga/.png}
    convert $oldFileName $newFileName
    rm $oldFileName
    echo "Converted $oldFileName to $newFileName"
done

A simple and quick solution.

  • Outputs a TARGA file but can easily be converted to PNG (script provided).
  • No extra libraries required.
  • Will work with both C and C++ (with some minor changes).
  • Note: The output file should have the tga file extension.

Here is the code:

void saveScreenshotToFile(std::string filename, int windowWidth, int windowHeight) {    
    const int numberOfPixels = windowWidth * windowHeight * 3;
    unsigned char pixels[numberOfPixels];

    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glReadBuffer(GL_FRONT);
    glReadPixels(0, 0, windowWidth, windowHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);

    FILE *outputFile = fopen(filename.c_str(), "w");
    short header[] = {0, 2, 0, 0, 0, 0, (short) windowWidth, (short) windowHeight, 24};

    fwrite(&header, sizeof(header), 1, outputFile);
    fwrite(pixels, numberOfPixels, 1, outputFile);
    fclose(outputFile);

    printf("Finish writing to file.\n");
}

And calling the function:

saveScreenshotToFile("test.tga", 1200, 900);

A bash script to convert TARGA files to PNG:

for oldFileName in *.tga; do
    [ -f "$oldFileName" ] || break         # Break out if no .tga files found.
    newFileName=${oldFileName//.tga/.png}
    convert $oldFileName $newFileName
    rm $oldFileName
    echo "Converted $oldFileName to $newFileName"
done
滿滿的愛 2024-11-11 10:43:20

将该数据保存到文件中要么必须自己完成,要么使用第三方库 - OpenGL 没有这样的功能。

如果您想自己动手,Windows .bmp 可能是最简单的 - 维基百科有一个关于文件格式。否则,您可以使用图像保存/加载库:libpng、libjpeg 等进行低级控制,或 devIL (还有其他库,但这是我最喜欢的,它是一个非常通用的库,与 GL 配合良好)用于高级“Just do it”图像 I/O。

Saving that data to a file is something you'll either have to do yourself or use a third-party library for - OpenGL has no such feature.

Windows .bmp is probably the easiest if you're looking to do it yourself - Wikipedia has a pretty good explanation of the file format. Otherwise you can use image saving/loading libraries: libpng, libjpeg, etc. for low-level control, or devIL (there are others, but this is my favorite, and it's an extremely versatile library that goes well with GL) for high-level "just do it" image i/o.

咽泪装欢 2024-11-11 10:43:20

您可以使用@Rafael的答案和OpenCV保存屏幕截图:

void Game::saveScreenshotToFile(std::string filename, int windowWidth, int windowHeight) {    

    cv::Mat img(windowHeight, windowWidth, CV_8UC3);
    glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4);

    glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());
    glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);
    cv::flip(img, img, 0);
    //cv::imshow("Image",img);
    //cv::waitKey(0);
    cv::imwrite(filename, img);
    }

感谢OpenCV:https://stackoverflow.com/a/9098883/10152334

You can save screenshot with @Rafael's answer and OpenCV:

void Game::saveScreenshotToFile(std::string filename, int windowWidth, int windowHeight) {    

    cv::Mat img(windowHeight, windowWidth, CV_8UC3);
    glPixelStorei(GL_PACK_ALIGNMENT, (img.step & 3) ? 1 : 4);

    glPixelStorei(GL_PACK_ROW_LENGTH, img.step/img.elemSize());
    glReadPixels(0, 0, img.cols, img.rows, GL_BGR, GL_UNSIGNED_BYTE, img.data);
    cv::flip(img, img, 0);
    //cv::imshow("Image",img);
    //cv::waitKey(0);
    cv::imwrite(filename, img);
    }

Thanks for OpenCV: https://stackoverflow.com/a/9098883/10152334

沫雨熙 2024-11-11 10:43:20

一般来说,OpenGL不提供保存图像的函数。我认为最快、最简单的方法是保存为 .PPM 格式。然而,这种格式是未压缩的,这意味着它的文件大小会非常大。目前只有相当多的程序可以支持它。

我更喜欢将图像保存为 .png 文件,该文件经过压缩但也提供无损图像并受到许多浏览器的支持。要将 OpenGL 保存为 .png 格式,我首先推荐 PNGwriter。它非常简单且易于使用。例如,要在位置 (x, y) 保存颜色为 (R, G, B) 的图像像素,您的代码将为(请参阅 PNGwriter 网站中的“快速入门”):

pngwriter PNG(width, height, 1.0, fileName); // "1.0" stand for the white background
PNG.plot(x, y, R, G, B);
PNG.close();

请注意,由于 PNGwriter 保存每个像素从图像的左上角开始,而从 glReadPixels() 获取的数组从窗口的左下角开始,保存整个图像的代码可能如下所示:

GLfloat* pixels = new GLfloat[nPixels];
glReadPixels(0.0, 0.0, width, height,GL_RGB, GL_FLOAT, pixels);
pngwriter PNG(width, height, 1.0, fileName);
size_t x = 1;   
size_t y = 1;
double R, G, B;
for(size_t i=0; i<npixels; i++) // "i" is the index for array "pixels"
{
      switch(i%3)
     {
           case 2:
                 B = static_cast<double>(pixels[i]); break;
           case 1:
                 G = static_cast<double>(pixels[i]); break;
           case 0:
                 R = static_cast<double>(pixels[i]);
                 PNG.plot(x, y, R, G, B);     // set pixel to position (x, y)
                 if( x == width )             // Move to the next row of image
                 {
                       x=1;
                       y++;
                  }
                  else                       // To the next pixel
                  { x++; }
                  break;
     }
}
PNG.close();

Generally, OpenGL don't provide functions to save image. I think the fastest and simplest way to do this is save to .PPM format. However, this kind of format is uncompressed which means it's file size would be very large. And it can be support only by quite a few programs nowadays.

I prefer to save image to .png file which is compressed but also gives lossless image and supported by many browsers. To save the OpenGL to .png format, I first recommend the PNGwriter. It's pretty simple and easy to use. For example, to save a pixel of a image with color (R, G, B) in the position (x, y), your code will be(see "quickstart" in the PNGwriter website):

pngwriter PNG(width, height, 1.0, fileName); // "1.0" stand for the white background
PNG.plot(x, y, R, G, B);
PNG.close();

Note that, since the PNGwriter save each pixel starting from the top-left corner of the image, while the array get from glReadPixels() start from the bottom-left of the window, your code to save the whole image might probably look like this:

GLfloat* pixels = new GLfloat[nPixels];
glReadPixels(0.0, 0.0, width, height,GL_RGB, GL_FLOAT, pixels);
pngwriter PNG(width, height, 1.0, fileName);
size_t x = 1;   
size_t y = 1;
double R, G, B;
for(size_t i=0; i<npixels; i++) // "i" is the index for array "pixels"
{
      switch(i%3)
     {
           case 2:
                 B = static_cast<double>(pixels[i]); break;
           case 1:
                 G = static_cast<double>(pixels[i]); break;
           case 0:
                 R = static_cast<double>(pixels[i]);
                 PNG.plot(x, y, R, G, B);     // set pixel to position (x, y)
                 if( x == width )             // Move to the next row of image
                 {
                       x=1;
                       y++;
                  }
                  else                       // To the next pixel
                  { x++; }
                  break;
     }
}
PNG.close();
雨落星ぅ辰 2024-11-11 10:43:20

我修改了 Ciro Santilli OurBigBook.com 的答案,以包括线程和更好的性能。

#include <thread>
#include <Windows.h>
#define GL_GLEXT_PROTOTYPES 1
#include <GL\GL.h>
#include <GL\GLU.h>
#include <glut.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>


static GLubyte *pixels = NULL;
static const GLenum FORMAT = GL_RGBA;
static const GLuint FORMAT_NBYTES = 4;
static const unsigned int HEIGHT = 500;
static const unsigned int WIDTH = 500;
static unsigned int nscreenshots = 0;
static unsigned int gameTime;
static bool grabScreen = false;
static bool threadRunning = false;


/* Model. */
static double angle = 0;
static double angle_speed = 45;

static void init(void)  {
    glReadBuffer(GL_BACK);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glViewport(0, 0, WIDTH, HEIGHT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);

    pixels = (GLubyte*)malloc(FORMAT_NBYTES * WIDTH * HEIGHT);
    gameTime = glutGet(GLUT_ELAPSED_TIME);
}

static void deinit(void)  {
    free(pixels);
}

static void create_ppm(char *prefix, int frame_id, unsigned int width, unsigned int height,
    unsigned int color_max, unsigned int pixel_nbytes, GLubyte *pixels) {
    size_t i, j, k, cur;
    enum Constants { max_filename = 256 };
    char filename[max_filename];
    sprintf(filename, "%s%d.ppm", prefix, frame_id);
    FILE *f = fopen(filename, "w");
    fprintf(f, "P3\n%d %d\n%d\n", width, HEIGHT, 255);
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            cur = pixel_nbytes * ((height - i - 1) * width + j);
            fprintf(f, "%3d %3d %3d ", pixels[cur], pixels[cur + 1], pixels[cur + 2]);
        }
        fprintf(f, "\n");
    }
    fclose(f);
}

static void draw_scene() {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glRotatef(angle, 0.0f, 0.0f, -1.0f);
    glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.5f, 0.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, 0.0f);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(0.5f, -0.5f, 0.0f);
    glEnd();
}

static void savepixels()
{
    threadRunning = true;
    create_ppm("tmp", nscreenshots, WIDTH, HEIGHT, 255, FORMAT_NBYTES, pixels);
    nscreenshots++;
    threadRunning = false;
}

static void display(void) {
    draw_scene();
    glutSwapBuffers();
    if (grabScreen){
        grabScreen = false;
        if (threadRunning){
            printf("Thread running\n");
        }
        else{
            glReadPixels(0, 0, WIDTH, HEIGHT, FORMAT, GL_UNSIGNED_BYTE, pixels);
            puts("screenshot");
            std::thread t{ savepixels };
            t.detach();
        }
    }
}

static void idle(void) {
    int new_gameTime = glutGet(GLUT_ELAPSED_TIME);
    angle += angle_speed * (new_gameTime - gameTime) / 1000.0;
    angle = fmod(angle, 360.0);
    gameTime = new_gameTime;
    glutPostRedisplay();
}

void mouse(int button, int state, int x, int y) {
    if (state == GLUT_DOWN && grabScreen == false) {
        grabScreen = true;
    }
}

int main(int argc, char **argv) {
    GLint glut_display;
    glutInit(&argc, argv);
    glutInitWindowSize(WIDTH, HEIGHT);
    glutInitWindowPosition(100, 100);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    glutMouseFunc(mouse);
    atexit(deinit);
    glutMainLoop();
    return EXIT_SUCCESS;
}

I have modified Ciro Santilli OurBigBook.com 's answer to include threading and better performance.

#include <thread>
#include <Windows.h>
#define GL_GLEXT_PROTOTYPES 1
#include <GL\GL.h>
#include <GL\GLU.h>
#include <glut.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>


static GLubyte *pixels = NULL;
static const GLenum FORMAT = GL_RGBA;
static const GLuint FORMAT_NBYTES = 4;
static const unsigned int HEIGHT = 500;
static const unsigned int WIDTH = 500;
static unsigned int nscreenshots = 0;
static unsigned int gameTime;
static bool grabScreen = false;
static bool threadRunning = false;


/* Model. */
static double angle = 0;
static double angle_speed = 45;

static void init(void)  {
    glReadBuffer(GL_BACK);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glViewport(0, 0, WIDTH, HEIGHT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);

    pixels = (GLubyte*)malloc(FORMAT_NBYTES * WIDTH * HEIGHT);
    gameTime = glutGet(GLUT_ELAPSED_TIME);
}

static void deinit(void)  {
    free(pixels);
}

static void create_ppm(char *prefix, int frame_id, unsigned int width, unsigned int height,
    unsigned int color_max, unsigned int pixel_nbytes, GLubyte *pixels) {
    size_t i, j, k, cur;
    enum Constants { max_filename = 256 };
    char filename[max_filename];
    sprintf(filename, "%s%d.ppm", prefix, frame_id);
    FILE *f = fopen(filename, "w");
    fprintf(f, "P3\n%d %d\n%d\n", width, HEIGHT, 255);
    for (i = 0; i < height; i++) {
        for (j = 0; j < width; j++) {
            cur = pixel_nbytes * ((height - i - 1) * width + j);
            fprintf(f, "%3d %3d %3d ", pixels[cur], pixels[cur + 1], pixels[cur + 2]);
        }
        fprintf(f, "\n");
    }
    fclose(f);
}

static void draw_scene() {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glRotatef(angle, 0.0f, 0.0f, -1.0f);
    glBegin(GL_TRIANGLES);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.5f, 0.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, 0.0f);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(0.5f, -0.5f, 0.0f);
    glEnd();
}

static void savepixels()
{
    threadRunning = true;
    create_ppm("tmp", nscreenshots, WIDTH, HEIGHT, 255, FORMAT_NBYTES, pixels);
    nscreenshots++;
    threadRunning = false;
}

static void display(void) {
    draw_scene();
    glutSwapBuffers();
    if (grabScreen){
        grabScreen = false;
        if (threadRunning){
            printf("Thread running\n");
        }
        else{
            glReadPixels(0, 0, WIDTH, HEIGHT, FORMAT, GL_UNSIGNED_BYTE, pixels);
            puts("screenshot");
            std::thread t{ savepixels };
            t.detach();
        }
    }
}

static void idle(void) {
    int new_gameTime = glutGet(GLUT_ELAPSED_TIME);
    angle += angle_speed * (new_gameTime - gameTime) / 1000.0;
    angle = fmod(angle, 360.0);
    gameTime = new_gameTime;
    glutPostRedisplay();
}

void mouse(int button, int state, int x, int y) {
    if (state == GLUT_DOWN && grabScreen == false) {
        grabScreen = true;
    }
}

int main(int argc, char **argv) {
    GLint glut_display;
    glutInit(&argc, argv);
    glutInitWindowSize(WIDTH, HEIGHT);
    glutInitWindowPosition(100, 100);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutIdleFunc(idle);
    glutMouseFunc(mouse);
    atexit(deinit);
    glutMainLoop();
    return EXIT_SUCCESS;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文