libcaca  0.99.beta19
About: libcaca is a graphics library that outputs text instead of pixels, so that it can work on older video cards or text terminals (something like an advanced AAlib library).
  Fossies Dox: libcaca-0.99.beta19.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

canvas.c
Go to the documentation of this file.
1 /*
2  * libcaca Colour ASCII-Art library
3  * Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
4  * All Rights Reserved
5  *
6  * This library is free software. It comes without any warranty, to
7  * the extent permitted by applicable law. You can redistribute it
8  * and/or modify it under the terms of the Do What the Fuck You Want
9  * to Public License, Version 2, as published by Sam Hocevar. See
10  * http://www.wtfpl.net/ for more details.
11  */
12 
13 /*
14  * This file contains the main functions used by \e libcaca applications
15  * to initialise a drawing context.
16  */
17 
18 #include "config.h"
19 
20 #if !defined(__KERNEL__)
21 # include <stdio.h>
22 # include <stdlib.h>
23 # include <string.h>
24 # include <time.h>
25 # include <sys/types.h>
26 # if defined(HAVE_UNISTD_H)
27 # include <unistd.h>
28 # endif
29 #endif
30 
31 #include "caca.h"
32 #include "caca_internals.h"
33 
34 static int caca_resize(caca_canvas_t *, int, int);
35 
54 caca_canvas_t * caca_create_canvas(int width, int height)
55 {
57 
58  if(width < 0 || height < 0)
59  {
60  seterrno(EINVAL);
61  return NULL;
62  }
63 
64  cv = malloc(sizeof(caca_canvas_t));
65 
66  if(!cv)
67  goto nomem;
68 
69  cv->refcount = 0;
70  cv->autoinc = 0;
71  cv->resize_callback = NULL;
72  cv->resize_data = NULL;
73 
74  cv->frame = 0;
75  cv->framecount = 1;
76  cv->frames = malloc(sizeof(struct caca_frame));
77  if(!cv->frames)
78  {
79  free(cv);
80  goto nomem;
81  }
82 
83  cv->frames[0].width = cv->frames[0].height = 0;
84  cv->frames[0].chars = NULL;
85  cv->frames[0].attrs = NULL;
86  cv->frames[0].x = cv->frames[0].y = 0;
87  cv->frames[0].handlex = cv->frames[0].handley = 0;
88  cv->frames[0].curattr = 0;
89  cv->frames[0].name = strdup("frame#00000000");
90 
93 
94  cv->ndirty = 0;
95  cv->dirty_disabled = 0;
96  cv->ff = NULL;
97 
98  if(caca_resize(cv, width, height) < 0)
99  {
100  int saved_errno = geterrno();
101  free(cv->frames[0].name);
102  free(cv->frames);
103  free(cv);
104  seterrno(saved_errno);
105  return NULL;
106  }
107 
108  return cv;
109 
110 nomem:
111  seterrno(ENOMEM);
112  return NULL;
113 }
114 
133 int caca_manage_canvas(caca_canvas_t *cv, int (*callback)(void *), void *p)
134 {
135  if(cv->refcount)
136  {
137  seterrno(EBUSY);
138  return -1;
139  }
140 
141  cv->resize_callback = callback;
142  cv->resize_data = p;
143  cv->refcount = 1;
144 
145  return 0;
146 }
147 
167 int caca_unmanage_canvas(caca_canvas_t *cv, int (*callback)(void *), void *p)
168 {
169  if(!cv->refcount
170  || cv->resize_callback != callback || cv->resize_data != p)
171  {
172  seterrno(EINVAL);
173  return -1;
174  }
175 
176  cv->refcount = 0;
177 
178  return 0;
179 }
180 
212 int caca_set_canvas_size(caca_canvas_t *cv, int width, int height)
213 {
214  if(width < 0 || height < 0)
215  {
216  seterrno(EINVAL);
217  return -1;
218  }
219 
220  if(cv->refcount && cv->resize_callback
222  {
223  seterrno(EBUSY);
224  return -1;
225  }
226 
227  return caca_resize(cv, width, height);
228 }
229 
240 {
241  return cv->width;
242 }
243 
254 {
255  return cv->height;
256 }
257 
272 uint32_t const * caca_get_canvas_chars(caca_canvas_t const *cv)
273 {
274  return (uint32_t const *)cv->chars;
275 }
276 
291 uint32_t const * caca_get_canvas_attrs(caca_canvas_t const *cv)
292 {
293  return (uint32_t const *)cv->attrs;
294 }
295 
309 {
310  int f;
311 
312  if(cv->refcount)
313  {
314  seterrno(EBUSY);
315  return -1;
316  }
317 
318  for(f = 0; f < cv->framecount; f++)
319  {
320  free(cv->frames[f].chars);
321  free(cv->frames[f].attrs);
322  free(cv->frames[f].name);
323  }
324 
326 
327  free(cv->frames);
328  free(cv);
329 
330  return 0;
331 }
332 
344 static caca_timer_t timer = {0, 0};
345 
346 int caca_rand(int min, int max)
347 {
348  static int need_init = 1;
349 
350  if(need_init)
351  {
352  srand(getpid() + _caca_getticks(&timer));
353  need_init = 0;
354  }
355 
356  return min + (int)((1.0 * (max - min)) * rand() / (RAND_MAX + 1.0));
357 }
358 
359 
360 /*
361  * XXX: The following functions are local.
362  */
363 
364 int caca_resize(caca_canvas_t *cv, int width, int height)
365 {
366  int x, y, f, old_width, old_height, new_size, old_size;
367 
368  old_width = cv->width;
369  old_height = cv->height;
370  old_size = old_width * old_height;
371 
373 
374  /* Preload new width and height values into the canvas to optimise
375  * dirty rectangle handling */
376  cv->width = width;
377  cv->height = height;
378  new_size = width * height;
379 
380  /* If width or height is smaller (or both), we have the opportunity to
381  * reduce or even remove dirty rectangles */
382  if(width < old_width || height < old_height)
384 
385  /* Step 1: if new area is bigger, resize the memory area now. */
386  if(new_size > old_size)
387  {
388  for(f = 0; f < cv->framecount; f++)
389  {
390  cv->frames[f].chars = realloc(cv->frames[f].chars,
391  new_size * sizeof(uint32_t));
392  cv->frames[f].attrs = realloc(cv->frames[f].attrs,
393  new_size * sizeof(uint32_t));
394  if(new_size && (!cv->frames[f].chars || !cv->frames[f].attrs))
395  {
396  seterrno(ENOMEM);
397  return -1;
398  }
399  }
400  }
401 
402  /* Step 2: move line data if necessary. */
403  if(width == old_width)
404  {
405  /* Width did not change, which means we do not need to move data. */
406  ;
407  }
408  else if(width > old_width)
409  {
410  /* New width is bigger than old width, which means we need to
411  * copy lines starting from the bottom of the screen otherwise
412  * we will overwrite information. */
413  for(f = 0; f < cv->framecount; f++)
414  {
415  uint32_t *chars = cv->frames[f].chars;
416  uint32_t *attrs = cv->frames[f].attrs;
417 
418  for(y = height < old_height ? height : old_height; y--; )
419  {
420  uint32_t attr = cv->frames[f].curattr;
421 
422  for(x = old_width; x--; )
423  {
424  chars[y * width + x] = chars[y * old_width + x];
425  attrs[y * width + x] = attrs[y * old_width + x];
426  }
427 
428  /* Zero the end of the line */
429  for(x = width - old_width; x--; )
430  {
431  chars[y * width + old_width + x] = (uint32_t)' ';
432  attrs[y * width + old_width + x] = attr;
433  }
434  }
435  }
436 
437  if(!cv->dirty_disabled)
438  caca_add_dirty_rect(cv, old_width, 0,
439  width - old_width, old_height);
440  }
441  else
442  {
443  /* New width is smaller. Copy as many lines as possible. Ignore
444  * the first line, it is already in place. */
445  int lines = height < old_height ? height : old_height;
446 
447  for(f = 0; f < cv->framecount; f++)
448  {
449  uint32_t *chars = cv->frames[f].chars;
450  uint32_t *attrs = cv->frames[f].attrs;
451 
452  for(y = 1; y < lines; y++)
453  {
454  for(x = 0; x < width; x++)
455  {
456  chars[y * width + x] = chars[y * old_width + x];
457  attrs[y * width + x] = attrs[y * old_width + x];
458  }
459  }
460  }
461  }
462 
463  /* Step 3: fill the bottom of the new screen if necessary. */
464  if(height > old_height)
465  {
466  for(f = 0; f < cv->framecount; f++)
467  {
468  uint32_t *chars = cv->frames[f].chars;
469  uint32_t *attrs = cv->frames[f].attrs;
470  uint32_t attr = cv->frames[f].curattr;
471 
472  /* Zero the bottom of the screen */
473  for(x = (height - old_height) * width; x--; )
474  {
475  chars[old_height * width + x] = (uint32_t)' ';
476  attrs[old_height * width + x] = attr;
477  }
478  }
479 
480  if(!cv->dirty_disabled)
481  caca_add_dirty_rect(cv, 0, old_height,
482  old_width, height - old_height);
483  }
484 
485  /* If both width and height are larger, there is a new dirty rectangle
486  * that needs to be created in the lower right corner. */
487  if(!cv->dirty_disabled &&
488  width > old_width && height > old_height)
489  caca_add_dirty_rect(cv, old_width, old_height,
490  width - old_width, height - old_height);
491 
492  /* Step 4: if new area is smaller, resize memory area now. */
493  if(new_size < old_size)
494  {
495  for(f = 0; f < cv->framecount; f++)
496  {
497  cv->frames[f].chars = realloc(cv->frames[f].chars,
498  new_size * sizeof(uint32_t));
499  cv->frames[f].attrs = realloc(cv->frames[f].attrs,
500  new_size * sizeof(uint32_t));
501  if(new_size && (!cv->frames[f].chars || !cv->frames[f].attrs))
502  {
503  seterrno(ENOMEM);
504  return -1;
505  }
506  }
507  }
508 
509  /* Set new size */
510  for(f = 0; f < cv->framecount; f++)
511  {
512  if(cv->frames[f].x > (int)width)
513  cv->frames[f].x = width;
514  if(cv->frames[f].y > (int)height)
515  cv->frames[f].y = height;
516 
517  cv->frames[f].width = width;
518  cv->frames[f].height = height;
519  }
520 
521  /* Reset the current frame shortcuts */
523 
524  return 0;
525 }
526 
527 /*
528  * XXX: The following functions are aliases.
529  */
530 
532 int cucul_manage_canvas(cucul_canvas_t *, int (*)(void *), void *)
534 int cucul_unmanage_canvas(cucul_canvas_t *, int (*)(void *), void *)
536 int cucul_set_canvas_size(cucul_canvas_t *, int, int)
542 uint32_t const * cucul_get_canvas_chars(cucul_canvas_t const *)
544 uint32_t const * cucul_get_canvas_attrs(cucul_canvas_t const *)
547 int cucul_rand(int, int) CACA_ALIAS(caca_rand);
548 
caca_canvas::resize_callback
int(* resize_callback)(void *)
Definition: caca_internals.h:59
CACA_ALIAS
#define CACA_ALIAS(x)
Definition: caca.h:689
caca_canvas_set_figfont
int caca_canvas_set_figfont(caca_canvas_t *, char const *)
load a figfont and attach it to a canvas
Definition: figfont.c:60
caca_canvas::frame
int frame
Definition: caca_internals.h:53
caca_frame::handley
int handley
Definition: caca_internals.h:40
y
static int y
Definition: cacadraw.c:27
caca_frame
Definition: caca_internals.h:29
caca_rand
int caca_rand(int min, int max)
Definition: canvas.c:346
caca_create_canvas
caca_canvas_t * caca_create_canvas(int width, int height)
Initialise a libcaca canvas.
Definition: canvas.c:54
_caca_load_frame_info
void _caca_load_frame_info(caca_canvas_t *)
Definition: frame.c:257
caca_free_canvas
int caca_free_canvas(caca_canvas_t *cv)
Free a libcaca canvas.
Definition: canvas.c:308
caca_timer
Definition: caca_internals.h:140
caca_get_canvas_attrs
const uint32_t * caca_get_canvas_attrs(caca_canvas_t const *cv)
Get the canvas attribute array.
Definition: canvas.c:291
caca_get_canvas_height
int caca_get_canvas_height(caca_canvas_t const *cv)
Get the canvas height.
Definition: canvas.c:253
cucul_free_canvas
#define cucul_free_canvas
Definition: caca.h:831
caca_canvas::frames
struct caca_frame * frames
Definition: caca_internals.h:54
cucul_get_canvas_chars
#define cucul_get_canvas_chars
Definition: caca.h:829
cucul_manage_canvas
#define cucul_manage_canvas
Definition: caca.h:824
caca_get_canvas_width
int caca_get_canvas_width(caca_canvas_t const *cv)
Get the canvas width.
Definition: canvas.c:239
caca_canvas::attrs
uint32_t * attrs
Definition: caca_internals.h:73
cucul_get_canvas_attrs
#define cucul_get_canvas_attrs
Definition: caca.h:830
cucul_get_canvas_width
#define cucul_get_canvas_width
Definition: caca.h:827
caca_canvas::chars
uint32_t * chars
Definition: caca_internals.h:72
caca_frame::name
char * name
Definition: caca_internals.h:44
CACA_TRANSPARENT
Definition: caca.h:88
cucul_unmanage_canvas
#define cucul_unmanage_canvas
Definition: caca.h:825
caca_frame::curattr
uint32_t curattr
Definition: caca_internals.h:41
seterrno
#define seterrno(x)
Definition: caca_stubs.h:27
caca_canvas::ndirty
int ndirty
Definition: caca_internals.h:63
caca_unmanage_canvas
int caca_unmanage_canvas(caca_canvas_t *cv, int(*callback)(void *), void *p)
unmanage a canvas.
Definition: canvas.c:167
caca_add_dirty_rect
int caca_add_dirty_rect(caca_canvas_t *, int, int, int, int)
Add an area to the canvas's dirty rectangle list.
Definition: dirty.c:164
geterrno
#define geterrno(x)
Definition: caca_stubs.h:28
caca_frame::height
int height
Definition: caca_internals.h:32
cucul_canvas_t
#define cucul_canvas_t
Definition: caca.h:763
caca_frame::x
int x
Definition: caca_internals.h:39
cv
caca_canvas_t * cv
Definition: cacaview.c:45
caca_canvas::framecount
int framecount
Definition: caca_internals.h:53
_caca_getticks
int _caca_getticks(caca_timer_t *)
Definition: time.c:47
caca_canvas::dirty_disabled
int dirty_disabled
Definition: caca_internals.h:63
CACA_DEFAULT
Definition: caca.h:87
caca_resize
static int caca_resize(caca_canvas_t *, int, int)
Definition: canvas.c:364
caca_frame::chars
uint32_t * chars
Definition: caca_internals.h:35
caca_internals.h
min
#define min(x, y)
Definition: aafire.c:201
caca_manage_canvas
int caca_manage_canvas(caca_canvas_t *cv, int(*callback)(void *), void *p)
Manage a canvas.
Definition: canvas.c:133
_caca_save_frame_info
void _caca_save_frame_info(caca_canvas_t *)
Definition: frame.c:249
caca_canvas::ff
caca_charfont_t * ff
Definition: caca_internals.h:77
caca_frame::y
int y
Definition: caca_internals.h:39
caca_frame::handlex
int handlex
Definition: caca_internals.h:40
caca_canvas::width
int width
Definition: caca_internals.h:71
caca.common.rand
def rand(range_min, range_max)
Definition: common.py:230
cucul_set_canvas_size
#define cucul_set_canvas_size
Definition: caca.h:826
caca_canvas::refcount
int refcount
Definition: caca_internals.h:57
caca_set_color_ansi
int caca_set_color_ansi(caca_canvas_t *cv, uint8_t fg, uint8_t bg)
Set the default colour pair for text (ANSI version).
Definition: attr.c:234
caca_set_canvas_size
int caca_set_canvas_size(caca_canvas_t *cv, int width, int height)
Resize a canvas.
Definition: canvas.c:212
caca.h
The libcaca public header.
timer
static caca_timer_t timer
Generate a random integer within a range.
Definition: canvas.c:344
config.h
cucul_create_canvas
#define cucul_create_canvas
Definition: caca.h:823
cucul_get_canvas_height
#define cucul_get_canvas_height
Definition: caca.h:828
caca_get_canvas_chars
const uint32_t * caca_get_canvas_chars(caca_canvas_t const *cv)
Get the canvas character array.
Definition: canvas.c:272
caca_frame::attrs
uint32_t * attrs
Definition: caca_internals.h:36
caca_canvas::height
int height
Definition: caca_internals.h:71
_caca_clip_dirty_rect_list
void _caca_clip_dirty_rect_list(caca_canvas_t *)
Definition: dirty.c:362
cucul_rand
#define cucul_rand
Definition: caca.h:832
caca_canvas::resize_data
void * resize_data
Definition: caca_internals.h:60
caca_canvas::autoinc
int autoinc
Definition: caca_internals.h:58
caca_canvas
Definition: caca_internals.h:47
caca_frame::width
int width
Definition: caca_internals.h:32
x
static int x
Definition: cacadraw.c:27