1 /****************************************************************************
2  * Copyright (C) 2008 by Matteo Franchin                                    *
3  *                                                                          *
4  * This file is part of Box.                                                *
5  *                                                                          *
6  *   Box is free software: you can redistribute it and/or modify it         *
7  *   under the terms of the GNU Lesser General Public License as published  *
8  *   by the Free Software Foundation, either version 3 of the License, or   *
9  *   (at your option) any later version.                                    *
10  *                                                                          *
11  *   Box is distributed in the hope that it will be useful,                 *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14  *   GNU Lesser General Public License for more details.                    *
15  *                                                                          *
16  *   You should have received a copy of the GNU Lesser General Public       *
17  *   License along with Box.  If not, see <http://www.gnu.org/licenses/>.   *
18  ****************************************************************************/
19 
20 /* Questo file contiene quanto basta per poter disegnare in bianco e nero(2 colori).
21  * Ho cercato di includervi solo le procedure dipendenti dal tipo di scrittura
22  * (1 bit per pixel), mentre procedure pi generali sono state incluse
23  * nel file graphic.c
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <math.h>
29 
30 #include "error.h"    /* Serve per la segnalazione degli errori */
31 #include "graphic.h"  /* Dichiaro alcune strutture grafiche generali */
32 #include "bmcommon.h"  /* Dichiarazioni delle procedure di bmcommon.c */
33 
34 /* Questa struttura contiene i dati della finestra che dipendono
35  * dal modo in cui viene memorizzato il disegno (numero bit per pixel)
36  */
37 typedef struct {
38   unsigned char *andmask;    /* Puntatore alla maschera and per il disegno di punti */
39   unsigned char *xormask;    /* Puntatore alla maschera xor per il disegno di punti */
40   unsigned char fandmask;    /* Maschera and per disegnare 8 punti alla volta */
41   unsigned char fxormask;    /* Maschera xor per disegnare 8 punti alla volta */
42 } gr1b_wrdep;
43 
44 /* Procedure definite in questo file */
45 static void gr1b_repair(BoxGWin *wd);
46 
47 /* Variabili locali */
48 static unsigned char xormask[2][8] = {
49   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
50   {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}
51 };
52 
53 static unsigned char andmask[2][8] = {
54   {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe},  /* cancella il pixel */
55   {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}  /* lascia il pixel */
56 };
57 
58 static unsigned char fxormask[2] = {0x00, 0xff};
59 static unsigned char fandmask[2] = {0x00, 0xff};
60 
61 /* Questa macro restituisce il segno di un double
62  * (1 se il numero �positivo, -1 se �negativo)
63  */
64 #define sign(x) (x < 0.0 ? -1.0 : 1.0)
65 
66 /* Questa macro viene usata per rendere pi leggibili i riferimenti
67  * ai dati della finestra dipendenti dai bit per pixel
68  */
69 #define WRDP(s)  ((gr1b_wrdep *) s->data)
70 
71 /***************************************************************************************/
72 /* PROCEDURE DI GESTIONE DELLA FINESTRA GRAFICA */
73 
74 /* DESCRIZIONE: Apre una finestra grafica di forma rettangolare
75  *  associando all'angolo in alto a sinistra le coordinate (ltx, lty)
76  *  e all'angolo in basso a destra le coordinate (rdx, rdy).
77  *  Tutte queste coordinate sono espresse in "unit� (che indichiamo con "u"
78  *  e 1 u = (1 * grp_tomm) millimetri, dove grp_tomm �definito nel file
79  *  "graphic.c"). Le risoluzioni orizzontale e verticale risx e risy
80  *  sono espresse in punti per unit�(che indichiamo con "ppu" e
81  *  1 ppu = (1/grp_tomm) punti per millimetro = (25.4/grp_tomm) dpi).
82  *  La funzione restituisce un puntatore ad una struttura contenente
83  *  i dati relativi alla nuova finestra creata, la quale viene utilizzata
84  *  per la gestione della finestra stessa.
85  *  In caso di errore invece restituisce 0.
86  */
BoxGWin_Create_BM1(BoxReal ltx,BoxReal lty,BoxReal rdx,BoxReal rdy,BoxReal resx,BoxReal resy)87 BoxGWin *BoxGWin_Create_BM1(BoxReal ltx, BoxReal lty, BoxReal rdx, BoxReal rdy,
88                             BoxReal resx, BoxReal resy) {
89   void *winptr;
90   BoxGWin *wd;
91   long numptx, numpty, bytesperline, windim;
92   BoxReal lx, ly, versox, versoy;
93 
94   wd = (BoxGWin *) malloc(sizeof(BoxGWin));
95   if (wd == NULL) {
96     ERRORMSG("BoxGWin_Create_BM1", "Memoria esaurita");
97     return NULL;
98   }
99 
100   wd->data = (gr1b_wrdep *) malloc(sizeof(gr1b_wrdep));
101   if (wd->data == NULL) {
102     ERRORMSG("BoxGWin_Create_BM1", "Memoria esaurita");
103     return NULL;
104   }
105 
106   lx = rdx - ltx;
107   ly = rdy - lty;
108 
109   /* Trovo i versori nelle due direzioni */
110   versox = sign(lx);
111   versoy = sign(ly);
112 
113   /* Trovo il numero di punti per lato */
114   numptx = fabs(lx) * resx;
115   numpty = fabs(ly) * resy;
116 
117   if ((numptx < 2) || (numpty < 2)) {
118     ERRORMSG("BoxGWin_Create_BM1", "Dimensioni della finestra troppo piccole");
119     return 0;
120   }
121 
122    /* Trovo quanti byte servono per contenere numptx pixel da 1 bit ciascuno */
123   bytesperline = (numptx + 7)/8;
124 
125   /* Trovo il numero di byte occupati dalla finestra */
126   windim = bytesperline * numpty;
127 
128   /* Creo la finestra e la svuoto */
129   if ( (winptr = (void *) calloc(windim+4, 1)) == 0 ) {
130     ERRORMSG("BoxGWin_Create_BM1", "Out of memory");
131     return 0;
132   }
133 
134   wd->ptr = winptr;
135   wd->ltx = ltx;
136   wd->lty = lty;
137   wd->rdx = rdx;
138   wd->rdy = rdy;
139 
140   if (lx > 0.0) {
141     wd->minx = wd->ltx;
142     wd->maxx = wd->rdx;
143   } else {
144     wd->minx = wd->rdx;
145      wd->maxx = wd->ltx;
146   }
147 
148   if (ly > 0.0) {
149     wd->miny = wd->lty;
150     wd->maxy = wd->rdy;
151   } else {
152     wd->miny = wd->rdy;
153     wd->maxy = wd->lty;
154   }
155 
156   wd->lx = fabs(lx);
157   wd->ly = fabs(ly);
158   wd->versox = versox;
159   wd->versoy = versoy;
160   wd->stepx = lx/(numptx-1);
161   wd->stepy = ly/(numpty-1);
162   wd->resx = fabs(1.0/(wd->stepx * grp_tomm));
163   wd->resy = fabs(1.0/(wd->stepy * grp_tomm));
164   wd->numptx = numptx;
165   wd->numpty = numpty;
166   wd->bitperpixel = 1;
167   wd->bytesperline = bytesperline;
168   wd->dim = windim;
169 
170   /* Costruisco una tavolazza di colori da associare a questa finestra */
171   wd->pal = grp_palette_build(2, 2, 3, 4);
172   if ( wd->pal == NULL ) return NULL;
173 
174   /* La prima richiesta di colore corrisponde all'indice di colore 0,
175    * cioe' all'indice dello sfondo della figura.
176    * Quindi setto il colore dello sfondo a RGB = {255, 255, 255} = bianco
177    */
178   wd->bgcol = grp_color_request( wd->pal, & ((color) {255, 255, 255}) );
179   if ( wd->bgcol == NULL ) return NULL;
180 
181   /* Setto il colore di primo piano a RGB = {0, 0, 0} = nero */
182   wd->fgcol = grp_color_request( wd->pal, & ((color) {0, 0, 0}) );
183   if ( wd->fgcol == NULL ) return NULL;
184 
185   WRDP(wd)->andmask = (unsigned char *) &andmask[0];
186   WRDP(wd)->xormask = (unsigned char *) &xormask[1];
187   WRDP(wd)->fandmask = fandmask[0];
188   WRDP(wd)->fxormask = fxormask[1];
189 
190   /* Ora do' le procedure per gestire la finestra */
191   wd->quiet = 0;
192   wd->repair = gr1b_repair;
193   wd->repair(wd);
194   wd->win_type_str = "bm1";
195   return wd;
196 }
197 
198 /* Chiude una finestra grafica aperta in precedenza
199  * con la funzione gr2b_open_win.
200  */
My_Finish(BoxGWin * w)201 static void My_Finish(BoxGWin *w) {
202   free(w->ptr);
203   free(w->data);
204   grp_palette_destroy(w->pal);
205 }
206 
207 /***************************************************************************************/
208 /* PROCEDURE DI GRAFICA ELEMENTARI
209  */
210 
211 /* Disegna un punto in posizione (ptx, pty)
212  * (espressa in coordinate fisiche, cio�numero riga,
213  * numero colonna)
214  */
My_Draw_Point(BoxGWin * w,BoxInt ptx,BoxInt pty)215 static void My_Draw_Point(BoxGWin *w, BoxInt ptx, BoxInt pty) {
216   long q, r;
217   char *ptr;
218 
219   if (   ptx < 0 || ptx >= w->numptx
220       || pty < 0 || pty >= w->numpty)
221     return;
222 
223   q = (long) (ptx >> 3);
224   r = (long) (ptx & 7);
225 
226   ptr = w->ptr + pty * w->bytesperline + q;
227 
228   *ptr &= WRDP(w)->andmask[r];
229   *ptr ^= WRDP(w)->xormask[r];
230 }
231 
232 /*Setta il colore di tracciatura.
233  * I colori disponibili sono 4:
234  *  0    sovrascrive i pixel col colore 0
235  *  1    sovrascrive i pixel col colore 1
236  *  -1    inverte il colore dei pixel
237  *  altro  non colora cioe' le procedure di tracciatura non hanno effetto.
238  */
My_Set_Color(BoxGWin * w,int col)239 static void My_Set_Color(BoxGWin *w, int col) {
240   switch (col) {
241    case 0:
242     WRDP(w)->andmask = (unsigned char *) &andmask[0];
243     WRDP(w)->fandmask = fandmask[0];
244     WRDP(w)->xormask = (unsigned char *) &xormask[0];
245     WRDP(w)->fxormask = fxormask[0];
246     break;
247 
248    case 1:
249     WRDP(w)->andmask = (unsigned char *) &andmask[0];
250     WRDP(w)->fandmask = fandmask[0];
251     WRDP(w)->xormask = (unsigned char *) &xormask[1];
252     WRDP(w)->fxormask = fxormask[1];
253     break;
254 
255    case -1:
256     WRDP(w)->andmask = (unsigned char *) &andmask[1];
257     WRDP(w)->fandmask = fandmask[1];
258     WRDP(w)->xormask = (unsigned char *) &xormask[1];
259     WRDP(w)->fxormask = fxormask[1];
260     break;
261 
262    default:
263     WRDP(w)->andmask = (unsigned char *) &andmask[1];
264     WRDP(w)->fandmask = fandmask[1];
265     WRDP(w)->xormask = (unsigned char *) &xormask[0];
266     WRDP(w)->fxormask = fxormask[0];
267     break;
268   }
269 }
270 
271 /***************************************************************************************/
272 /* PROCEDURE DI TRACCIATURA INTERMEDIE */
273 
274 /* Scrive una linea sulla riga y, da colonna x1 a x2
275  * (queste sono tutte coordinate intere).
276  */
My_Draw_Hor_Line(BoxGWin * w,BoxInt y,BoxInt x1,BoxInt x2)277 static void My_Draw_Hor_Line(BoxGWin *w, BoxInt y, BoxInt x1, BoxInt x2) {
278   long length, nbyte, xbyte, xpix, bl, i;
279   char *ptr;
280 
281   if (x1 < 0)
282     x1 = 0;
283 
284   if (x2 >= w->numptx)
285     x2 = w->numptx - 1;
286 
287   length = x2 - x1 + 1;
288   if (length <= 0 || y < 0 || y >= w->numpty)
289     return;
290 
291   xbyte = x1 >> 3;
292   xpix = x1 & 7;
293 
294   /* bl �il numero di pixel che mancano per completare il byte */
295   bl = (8 - xpix) & 7;
296 
297   /* Calcola l'indirizzo del byte che contiene il punto */
298   ptr = ((char *) w->ptr) + (w->bytesperline * y + xbyte);
299 
300   if (length > bl) {
301     if (bl > 0) {
302       /* Completo il byte corrente */
303       for (i=0; i<bl; i++) {
304         *ptr &= WRDP(w)->andmask[xpix];
305         *ptr ^= WRDP(w)->xormask[xpix];
306         ++xpix;
307       }
308       ++ptr;
309       length -= bl;
310     }
311 
312     /* Scrivo byte per byte */
313     nbyte = length >> 3;
314 
315     for (i=0; i<nbyte; i++) {
316       *ptr &= WRDP(w)->fandmask;
317       *ptr ^= WRDP(w)->fxormask;
318       ++ptr;
319     }
320 
321     /* Scrivo i pixel che restano */
322     bl = length & 7;
323     for (i=0; i<bl; i++) {
324       *ptr &= WRDP(w)->andmask[i];
325       *ptr ^= WRDP(w)->xormask[i];
326     }
327 
328   } else {
329     for (i=0; i<length; i++) {
330       *ptr &= WRDP(w)->andmask[xpix];
331       *ptr |= WRDP(w)->xormask[xpix];
332       ++xpix;
333     }
334   }
335 }
336 
337 /** Set the default methods to the gr1b window */
gr1b_repair(BoxGWin * wd)338 static void gr1b_repair(BoxGWin *wd) {
339   BoxGWin_Block(wd);
340   rst_repair(wd);
341   wd->save_to_file = grbm_save_to_bmp;
342 
343   wd->finish = My_Finish;
344   wd->set_color = My_Set_Color;
345   wd->draw_point = My_Draw_Point;
346   wd->draw_hor_line = My_Draw_Hor_Line;
347 }
348 
349