2 * kmscon - Console Management
3 * Written 2011 by David Herrmann <dh.herrmann@googlemail.com>
8 * This provides the console drawing and manipulation functions. It does not
9 * provide the terminal emulation. It is just an abstraction layer to draw text
10 * to a framebuffer as used by terminals and consoles.
14 * TODO: Avoid using this hack and instead retrieve GL extension
15 * pointers dynamically on initialization.
17 #define GL_GLEXT_PROTOTYPES
30 struct kmscon_char *ch;
33 struct kmscon_console {
41 cairo_surface_t *surf;
42 unsigned char *surf_buf;
46 struct kmscon_cell *cells;
48 struct kmscon_font *font;
51 int kmscon_console_new(struct kmscon_console **out)
53 struct kmscon_console *con;
59 con = malloc(sizeof(*con));
63 memset(con, 0, sizeof(*con));
66 ret = kmscon_console_resize(con, 80, 24);
70 glGenTextures(1, &con->tex);
80 void kmscon_console_ref(struct kmscon_console *con)
88 static void console_free_cells(struct kmscon_console *con)
93 size = con->lines_x * con->lines_y;
95 for (i = 0; i < size; ++i)
96 kmscon_char_free(con->cells[i].ch);
103 * Drops one reference. If this is the last reference, the whole console is
104 * freed and the associated render-images are destroyed.
106 void kmscon_console_unref(struct kmscon_console *con)
108 if (!con || !con->ref)
115 cairo_destroy(con->cr);
116 cairo_surface_destroy(con->surf);
120 kmscon_font_unref(con->font);
121 console_free_cells(con);
122 glDeleteTextures(1, &con->tex);
127 * This resets the resolution used for drawing operations. It is recommended to
128 * set this to the size of your framebuffer, howevr, you can set this to
130 * This image-resolution is used internally to render the console fonts. The
131 * kmscon_console_map() function can map this image to any framebuffer size you
132 * want. Therefore, this screen resolution is just a performance and quality
134 * This function must be called before drawing the console, though. Returns 0 on
135 * success, -EINVAL if con, x or y is 0/NULL and -ENOMEM on out-of-mem errors.
137 int kmscon_console_set_res(struct kmscon_console *con, uint32_t x, uint32_t y)
141 cairo_surface_t *surface;
143 cairo_format_t format = CAIRO_FORMAT_ARGB32;
145 if (!con || !x || !y)
148 stride = cairo_format_stride_for_width(format, x);
150 buf = malloc(stride * y);
154 surface = cairo_image_surface_create_for_data(buf, format, x, y,
156 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
161 cr = cairo_create(surface);
162 if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
168 cairo_destroy(con->cr);
169 cairo_surface_destroy(con->surf);
179 glBindTexture(GL_TEXTURE_RECTANGLE, con->tex);
180 glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, con->res_x, con->res_y,
181 0, GL_BGRA, GL_UNSIGNED_BYTE, con->surf_buf);
182 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
189 cairo_surface_destroy(surface);
195 * This redraws the console. It does not clip/copy the image onto any
196 * framebuffer. You must use kmscon_console_map() to do this.
197 * This allows to draw the console once and then map it onto multiple
198 * framebuffers so it is displayed on multiple monitors with different screen
200 * You must have called kmscon_console_set_res() before.
202 void kmscon_console_draw(struct kmscon_console *con)
204 if (!con || !con->cr)
209 cairo_set_operator(con->cr, CAIRO_OPERATOR_OVER);
210 cairo_scale(con->cr, con->res_x, con->res_y);
211 cairo_set_source_rgba(con->cr, 0.0, 0.0, 0.0, 0.0);
212 cairo_paint(con->cr);
214 // TODO: draw console here
216 cairo_restore(con->cr);
220 * This maps the console onto the current GL framebuffer. It expects the
221 * framebuffer to have 0/0 in the middle, -1/-1 in the upper left and 1/1 in the
222 * lower right (default GL settings).
223 * This does not clear the screen, nor does it paint the background. Instead the
224 * background is transparent and blended on top of the framebuffer.
226 * You must have called kmscon_console_draw() before, otherwise this will map an
227 * empty image onto the screen.
229 void kmscon_console_map(struct kmscon_console *con)
231 if (!con || !con->cr)
235 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
236 glEnable(GL_TEXTURE_RECTANGLE);
237 glBindTexture(GL_TEXTURE_RECTANGLE, con->tex);
240 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
242 glTexCoord2f(0.0f, 0.0f);
243 glVertex2f(-1.0f, -1.0f);
245 glTexCoord2f(con->res_x, 0.0f);
246 glVertex2f(1.0f, -1.0f);
248 glTexCoord2f(con->res_x, con->res_y);
249 glVertex2f(1.0f, 1.0f);
251 glTexCoord2f(0.0f, con->res_y);
252 glVertex2f(-1.0f, 1.0f);
257 * Resize console. x/y must not be 0.
258 * This resizes the whole console buffer and recreates all cells. It tries to
259 * preserve as many content from the previous buffer as possible.
261 int kmscon_console_resize(struct kmscon_console *con, uint32_t x, uint32_t y)
263 struct kmscon_cell *cells;
264 struct kmscon_font *font;
269 if (!con || !size || size < x || size < y)
272 ret = kmscon_font_new(&font);
276 cells = malloc(sizeof(*cells) * size);
282 memset(cells, 0, sizeof(*cells) * size);
284 for (i = 0; i < size; ++i) {
285 ret = kmscon_char_new(&cells[i].ch);
287 for (j = 0; j < i; ++j)
288 kmscon_char_free(cells[j].ch);
293 kmscon_font_unref(con->font);
296 console_free_cells(con);
306 kmscon_font_unref(font);