-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFrameGrabber.cpp
181 lines (150 loc) · 4.99 KB
/
FrameGrabber.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
* FrameGrabber.cpp
*
* Class to grab OpenGL frames and output to image files at HD resolution
*
* Created by Don House on 11/30/10.
* Copyright 2010 Clemson University. All rights reserved.
*
*/
#include "FrameGrabber.h"
#include <Magick++.h>
#include <cstdlib>
#include <iostream>
#ifdef __APPLE__
# include <GLUT/glut.h>
#else
# define GL_GLEXT_PROTOTYPES 1
# include <GL/glut.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
using namespace std;
using namespace Magick;
//
// Helper function to convert a frame number to a 4 digit string
//
string makeframenumber(int f){
string fnum;
int n;
for(int i = 0; i < 4; i++){
n = f % 10;
fnum = fnum.insert(0, 1, '0' + n);
f = f / 10;
}
return fnum;
}
FrameGrabber::FrameGrabber(const string &path, const string &filename, int w, int h, int f){
setsize(w, h);
setframe(f);
setfilename(path, filename);
FBid = Textureid = DBid = 0;
}
FrameGrabber::~FrameGrabber(){
}
void FrameGrabber::setfilename(const string &path, const string &filename){
Filename = path;
if(Filename.size() > 0){
// if no such directory as indicated by path, then create one
char * mypath = new char[path.length() + 1];
strcpy(mypath, path.c_str());
struct stat mystat;
if (!(stat(mypath, &mystat) == 0) || (((mystat.st_mode) & S_IFMT) != S_IFDIR)) {
string mkdir = "mkdir " + path;
char * cmkdir = new char[mkdir.length() + 1];
strcpy(cmkdir, mkdir.c_str());
int err = system(cmkdir);
if(err){
cerr << "Failed to create frames directory: " << path << endl;
exit(1);
}
delete cmkdir;
}
delete mypath;
if(Filename[Filename.size() - 1] != '/') // make sure that path ends in '/'
Filename.push_back('/');
Filename = Filename + filename; // concatenate path and filename base
}
else
Filename = filename;
}
void FrameGrabber::setfilename(const string &filename){
Filename = filename;
}
//
// Initialize the framegrabber by creating a texture image for the image,
// a renderbuffer for the depth buffer, and a frame buffer object that holds
// the image and the depth buffer. Code modified from that in:
// http://www.songho.ca/opengl/gl_fbo.html
//
void FrameGrabber::Initialize(){
// create a texture image for the frame buffer object (FBO) to draw to
glGenTextures(1, (GLuint *)&Textureid);
glBindTexture(GL_TEXTURE_2D, Textureid);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// create a renderbuffer object to use as the depth buffer
GLuint rboId;
glGenRenderbuffersEXT(1, (GLuint *)&DBid);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DBid);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, W, H);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// create the FBO and attach the texture image to it
glGenFramebuffersEXT(1, (GLuint *)&FBid);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBid);
// attach the texture and the depth buffer to the FBO
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, Textureid, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, DBid);
// If the FBO status is bad, warn user and ignore FBO
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(status != GL_FRAMEBUFFER_COMPLETE_EXT){
cout << "bad framebuffer!" << endl;
FBid = 0;
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
void FrameGrabber::recordimage(void (*drawingprocedure)()){
int savevp[4];
// only create texture and frame buffer objects once
if(FBid == 0)
Initialize();
// save viewport, and set focus to FBO, with full screen viewport
glGetIntegerv(GL_VIEWPORT, savevp);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBid);
glViewport(0, 0, W, H);
// draw the scene offscreen to the texture in the FBO
drawingprocedure();
glFlush();
// capture the image and write the next animation frame file
writeimage();
// restore the OpenGL framebuffer and viewport
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glViewport(savevp[0], savevp[1], savevp[2], savevp[3]);
}
/*
Routine to write the current framebuffer to an image file
*/
void FrameGrabber::writeimage(){
string framenumber, outfilename;
unsigned char pixmap[4 * W * H];
// add the frame number to the file name and .png
framenumber = makeframenumber(Frame);
outfilename = Filename + "." + framenumber + ".png";
cout << outfilename << endl;
// fetch the current frame from the texture object into a pixmap
glBindTexture(GL_TEXTURE_2D, Textureid);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap);
glBindTexture(GL_TEXTURE_2D, 0);
// create an ImageMagick image from the pixmap
// and flip it or it will be upside down in the image file
Image image(W, H, "RGBA", CharPixel, (void *)pixmap);
image.flip();
// output the frame as an image file
image.write(outfilename);
// increment the frame number
Frame++;
}