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