Esempio n. 1
0
static void save_screenshot_of_opengl_framebuffer(const char *path) {
#if 0
    static int count = 0;
    count += 1;

    time_t t = time(NULL);
#ifdef WINDOWS
    struct tm *tm_p = localtime(&t);
#else
    struct tm tm_struct;
    struct tm *tm_p = &tm_struct;
    localtime_r(&t, tm_p);
#endif
    char strbuf[20];
    strftime(strbuf, 20, "%Y-%m-%d-%H-%M", tm_p);
    char *name = g_strdup_printf("%s-%s-%03d.png",
            g_fs_ml_video_screenshots_prefix,
            strbuf, g_fs_ml_video_screenshot);
    char *path = g_build_filename(g_fs_ml_video_screenshots_dir, name, NULL);
#endif
    fs_log("writing screenshot to %s\n", path);

    int w = fs_ml_video_width();
    int h = fs_ml_video_height();
    fs_log("reading opengl frame buffer (%d x %d)\n", w, h);
    void *out_data = g_malloc(w * h * 4);

    // when using GL_RGB, remeber to temporarily set GL_UNPACK_ALIGNMENT so
    // all rows will be contiguous (the OpenGL default is to align rows on
    // 4-byte boundaries
    //GLint unpack_alignment;
    //glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
    //glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, out_data);
    //glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment);

    // flip image vertically
    int stride = w * 4;
    void *tmp = g_malloc(stride);
    void *line1 = out_data;
    void *line2 = out_data + stride * (h - 1);
    for (int i = 0; i < h / 2; i++) {
        memcpy(tmp, line1, stride);
        memcpy(line1, line2, stride);
        memcpy(line2, tmp, stride);
        line1 += stride;
        line2 -= stride;
    }
    g_free(tmp);

    int result = fs_image_save_data(path, out_data, w, h, 4);
    if (result) {
        fs_log("saved screenshot\n");
    }
    else {
        fs_log("error saving screenshot\n");
    }
    g_free(out_data);
#if 0
    g_free(name);
    g_free(path);
#endif
}
Esempio n. 2
0
static void update_texture() {
    fs_emu_video_buffer *buffer = fs_emu_lock_video_buffer();
    // unlocked in fs_emu_video_after_update

    uint8_t *frame = buffer->data;
    if (frame == NULL) {
    	return;
    }
    int is_new_frame = 1;
    static int last_seq_no = -1;
    if (buffer->seq == last_seq_no + 1) {
        // normal
    }
    else if (buffer->seq == last_seq_no) {
        //fs_log("WARNING: repeated frame %d\n", info->seq_no);
        g_fs_emu_repeated_frames++;
        if (g_fs_emu_repeated_frames > 9999) {
            g_fs_emu_repeated_frames = 9999;
        }
        is_new_frame = 0;
    }
    else {
        int lost_frame_count = buffer->seq - last_seq_no - 1;
        g_fs_emu_lost_frames += lost_frame_count;
        //fs_log("lost %d frame(s)\n", lost_frame_count);
    }
    last_seq_no = buffer->seq;

    int width = buffer->width;
    int height = buffer->height;
    int bpp = buffer->bpp;

    if (g_fs_emu_screenshot) {
        static int count = 1;
        g_fs_emu_screenshot = 0;
        gchar *name, *path;
        time_t t = time(NULL);
        struct tm *tm_struct = localtime(&t);
        char strbuf[20];
        strftime(strbuf, 20, "%Y-%m-%d_%H-%M-%S", tm_struct);
        name = g_strdup_printf("%s_%d.png", strbuf, count);
        count += 1;
        path = g_build_filename(
                g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP),
                name, NULL);
        fs_log("writing screenshot to %s\n", path);
        int len = width * height * bpp;
        uint8_t *out_data = malloc(width * height * 3);
        uint8_t *op = out_data;

        if (fs_emu_get_video_format() == FS_EMU_VIDEO_FORMAT_BGRA) {
            for (int x = 0; x < len; x += 4) {
                *op++ = frame[x + 2];
                *op++ = frame[x + 1];
                *op++ = frame[x + 0];
            }
        }
        else {
            for (int x = 0; x < len; x += 4) {
                *op++ = frame[x + 0];
                *op++ = frame[x + 1];
                *op++ = frame[x + 2];
            }
        }
        int result = fs_image_save_data(path, out_data, width, height, 3);
        if (result) {
            fs_log("saved screenshot\n");
        }
        else {
            fs_log("error saving screenshot\n");
        }
        g_free(name);
        g_free(path);
    }

    int format = 0;
    if (bpp == 3) {
        format = GL_RGB;
    }
    else if (bpp == 4) {
#if 0
        if (fs_emu_get_video_format() == GL_BGRA) {
            format = GL_BGRA;
        }
        else {
            format = GL_RGBA;
        }
#endif
        format = fs_emu_get_video_format();
    }
    else {
        //fs_log("na..\n");
        return;
        //fs_emu_fatal("bpp is neither 3 nor 4\n");
    }
    if (g_fs_emu_video_crop_mode) {
        g_crop = buffer->crop;
        if (g_crop.w == 0) {
            g_crop.w = width;
        }
        if (g_crop.h == 0) {
            g_crop.h = height;
        }
    }
    else {
        g_crop.x = 0;
        g_crop.y = 0;
        g_crop.w = buffer->width;
        g_crop.h = buffer->height;
    }

    int upload_x, upload_y, upload_w, upload_h;
    g_effective_viewport_mode = g_viewport_mode;
    if (buffer->flags & FS_EMU_FORCE_VIEWPORT_CROP_FLAG) {
        g_effective_viewport_mode = FS_EMU_VIEWPORT_MODE_CROP;
    }

    if (g_effective_viewport_mode == FS_EMU_VIEWPORT_MODE_CROP) {
        fix_border(buffer, &upload_x, &upload_y, &upload_w, &upload_h);
    }
    else {
        upload_x = 0;
        upload_y = 0;
        upload_w = buffer->width;
        upload_h = buffer->height;
    }

    if (g_fs_emu_scanlines &&
            (buffer->flags & FS_EMU_NO_SCANLINES_FLAG) == 0) {
        //printf("new frame? %d\n", is_new_frame);
        if (is_new_frame) {
            if (g_scanline_buffer_width != buffer->width ||
                    g_scanline_buffer_height != buffer->height) {
                if (g_scanline_buffer) {
                    free(g_scanline_buffer);
                }
                g_scanline_buffer = malloc(buffer->width * buffer->height * 4);
                g_scanline_buffer_width = buffer->width;
                g_scanline_buffer_height = buffer->height;
            }
            fs_emu_render_scanlines(g_scanline_buffer, buffer,
                    upload_x, upload_y, upload_w, upload_h,
                    g_fs_emu_scanlines_dark, g_fs_emu_scanlines_light);
        }
        if (g_scanline_buffer) {
            frame = g_scanline_buffer;
        }
    }

    //fs_log("%d %d %d %d %d %d %d\n", width, height, bpp,
    //        g_crop.x, g_crop.y, g_crop.w, g_crop.h);
    g_frame_width = width;
    g_frame_height = height;
    g_frame_aspect = buffer->aspect;

    create_texture_if_needed(width, height);
    fs_gl_bind_texture(g_frame_texture);

    uint8_t *data_start = frame + ((upload_y * width) + upload_x) * 4;
#ifndef HAVE_GLES
    fs_gl_unpack_row_length(width);
    glTexSubImage2D(GL_TEXTURE_2D, 0, upload_x, upload_y,
    		upload_w, upload_h, format,
            GL_UNSIGNED_BYTE, data_start);
#else
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, upload_w, upload_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_start);

    for (int y = 0; y < upload_h; y++) {
        char *row = data_start + ((y + upload_y)*width + upload_x) * 4;
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, upload_y, upload_w, 1, GL_RGBA, GL_UNSIGNED_BYTE, row);
    }
#endif
    CHECK_GL_ERROR();

#if 1
    int hq_border = 2;
    if (hq_border >= 1) {
        if (upload_y > 0) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, upload_y - 1, width, 1,
                    format, GL_UNSIGNED_BYTE,
                    frame + (upload_y) * width * bpp);
            CHECK_GL_ERROR();
        }

        if (upload_y + upload_h < g_frame_texture_height) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, upload_y + upload_h,
                    width, 1, format, GL_UNSIGNED_BYTE,
                    frame + (upload_y + upload_h - 1) * width * bpp);
            CHECK_GL_ERROR();
        }

        if (upload_x > 0) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, upload_x - 1, upload_y,
                    1, upload_h, format, GL_UNSIGNED_BYTE, frame +
                    ((upload_y) * width + upload_x) * bpp);
            CHECK_GL_ERROR();
        }

        if (upload_x + upload_w < g_frame_texture_width) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, upload_x + upload_w,
                    upload_y, 1, upload_h, format,
                    GL_UNSIGNED_BYTE, frame +
                    ((upload_y) * width + upload_x + upload_w - 1) * bpp);
            CHECK_GL_ERROR();
        }
    }
#if 0
    if (hq_border >= 2) {
        if (upload_y + upload_h < g_frame_texture.height - 1) {
            //printf("1\n");
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, upload_y + upload_h + 1,
                    width, 1, format, GL_UNSIGNED_BYTE,
                    frame + (upload_y + upload_h - 1) * width * bpp);
                    //frame + (upload_y + upload_h - 2) * width * bpp);
        }

        if (upload_x + upload_w < g_frame_texture.width - 1) {
            glTexSubImage2D(GL_TEXTURE_2D, 0, upload_x + upload_w + 1,
                    upload_y, 1, upload_h, format,
                    GL_UNSIGNED_BYTE, frame +
                    ((upload_y) * width + upload_x + upload_w - 1) * bpp);
        }
    }
#endif
#endif
}