xref: /plan9/sys/src/cmd/gs/src/gxshade4.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gxshade4.c,v 1.30 2005/04/19 12:22:08 igor Exp $ */
18 /* Rendering for Gouraud triangle shadings */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsmatrix.h"		/* for gscoord.h */
24 #include "gscoord.h"
25 #include "gsptype2.h"
26 #include "gxcspace.h"
27 #include "gxdcolor.h"
28 #include "gxdevcli.h"
29 #include "gxistate.h"
30 #include "gxpath.h"
31 #include "gxshade.h"
32 #include "gxshade4.h"
33 #include "vdtrace.h"
34 
35 #define VD_TRACE_TRIANGLE_PATCH 1
36 
37 /* Initialize the fill state for triangle shading. */
38 int
mesh_init_fill_state(mesh_fill_state_t * pfs,const gs_shading_mesh_t * psh,const gs_fixed_rect * rect_clip,gx_device * dev,gs_imager_state * pis)39 mesh_init_fill_state(mesh_fill_state_t * pfs, const gs_shading_mesh_t * psh,
40 		     const gs_fixed_rect * rect_clip, gx_device * dev,
41 		     gs_imager_state * pis)
42 {
43     shade_init_fill_state((shading_fill_state_t *) pfs,
44 			  (const gs_shading_t *)psh, dev, pis);
45     pfs->pshm = psh;
46     pfs->rect = *rect_clip;
47     return 0;
48 }
49 
50 /* ---------------- Gouraud triangle shadings ---------------- */
51 
52 private int
Gt_next_vertex(const gs_shading_mesh_t * psh,shade_coord_stream_t * cs,shading_vertex_t * vertex)53 Gt_next_vertex(const gs_shading_mesh_t * psh, shade_coord_stream_t * cs,
54 	       shading_vertex_t * vertex)
55 {
56     int code = shade_next_vertex(cs, vertex);
57 
58     if (code >= 0 && psh->params.Function) {
59 	vertex->c.t[0] = vertex->c.cc.paint.values[0];
60 	vertex->c.t[1] = 0;
61 	/* Decode the color with the function. */
62 	code = gs_function_evaluate(psh->params.Function, vertex->c.t,
63 				    vertex->c.cc.paint.values);
64     }
65     return code;
66 }
67 
68 inline private int
Gt_fill_triangle(mesh_fill_state_t * pfs,const shading_vertex_t * va,const shading_vertex_t * vb,const shading_vertex_t * vc)69 Gt_fill_triangle(mesh_fill_state_t * pfs, const shading_vertex_t * va,
70 		 const shading_vertex_t * vb, const shading_vertex_t * vc)
71 {
72     patch_fill_state_t pfs1;
73     int code = 0;
74 
75     memcpy(&pfs1, (shading_fill_state_t *)pfs, sizeof(shading_fill_state_t));
76     pfs1.Function = pfs->pshm->params.Function;
77     pfs1.rect = pfs->rect;
78     code = init_patch_fill_state(&pfs1);
79     if (code < 0)
80 	return code;
81     if (INTERPATCH_PADDING) {
82 	code = mesh_padding(&pfs1, &va->p, &vb->p, &va->c, &vb->c);
83 	if (code >= 0)
84 	    code = mesh_padding(&pfs1, &vb->p, &vc->p, &vb->c, &vc->c);
85 	if (code >= 0)
86 	    code = mesh_padding(&pfs1, &vc->p, &va->p, &vc->c, &va->c);
87     }
88     if (code >= 0)
89 	code = mesh_triangle(&pfs1, va, vb, vc);
90     term_patch_fill_state(&pfs1);
91     return code;
92 }
93 
94 int
gs_shading_FfGt_fill_rectangle(const gs_shading_t * psh0,const gs_rect * rect,const gs_fixed_rect * rect_clip,gx_device * dev,gs_imager_state * pis)95 gs_shading_FfGt_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
96 			       const gs_fixed_rect * rect_clip,
97 			       gx_device * dev, gs_imager_state * pis)
98 {
99     const gs_shading_FfGt_t * const psh = (const gs_shading_FfGt_t *)psh0;
100     mesh_fill_state_t state;
101     shade_coord_stream_t cs;
102     int num_bits = psh->params.BitsPerFlag;
103     int flag;
104     shading_vertex_t va, vb, vc;
105     int code;
106 
107     if (VD_TRACE_TRIANGLE_PATCH && vd_allowed('s')) {
108 	vd_get_dc('s');
109 	vd_set_shift(0, 0);
110 	vd_set_scale(0.01);
111 	vd_set_origin(0, 0);
112     }
113     code = mesh_init_fill_state(&state, (const gs_shading_mesh_t *)psh, rect_clip,
114 			 dev, pis);
115     if (code < 0)
116 	return code;
117     shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
118 		    pis);
119     while ((flag = shade_next_flag(&cs, num_bits)) >= 0) {
120 	switch (flag) {
121 	    default:
122 		return_error(gs_error_rangecheck);
123 	    case 0:
124 		if ((code = Gt_next_vertex(state.pshm, &cs, &va)) < 0 ||
125 		    (code = shade_next_flag(&cs, num_bits)) < 0 ||
126 		    (code = Gt_next_vertex(state.pshm, &cs, &vb)) < 0 ||
127 		    (code = shade_next_flag(&cs, num_bits)) < 0
128 		    )
129 		    return code;
130 		goto v2;
131 	    case 1:
132 		va = vb;
133 	    case 2:
134 		vb = vc;
135 v2:		if ((code = Gt_next_vertex(state.pshm, &cs, &vc)) < 0)
136 		    return code;
137 		if ((code = Gt_fill_triangle(&state, &va, &vb, &vc)) < 0)
138 		    return code;
139 	}
140     }
141     if (VD_TRACE_TRIANGLE_PATCH && vd_allowed('s'))
142 	vd_release_dc;
143     if (!cs.is_eod(&cs))
144 	return_error(gs_error_rangecheck);
145     return 0;
146 }
147 
148 int
gs_shading_LfGt_fill_rectangle(const gs_shading_t * psh0,const gs_rect * rect,const gs_fixed_rect * rect_clip,gx_device * dev,gs_imager_state * pis)149 gs_shading_LfGt_fill_rectangle(const gs_shading_t * psh0, const gs_rect * rect,
150 			       const gs_fixed_rect * rect_clip,
151 			       gx_device * dev, gs_imager_state * pis)
152 {
153     const gs_shading_LfGt_t * const psh = (const gs_shading_LfGt_t *)psh0;
154     mesh_fill_state_t state;
155     shade_coord_stream_t cs;
156     shading_vertex_t *vertex;
157     shading_vertex_t next;
158     int per_row = psh->params.VerticesPerRow;
159     int i, code;
160 
161     if (VD_TRACE_TRIANGLE_PATCH && vd_allowed('s')) {
162 	vd_get_dc('s');
163 	vd_set_shift(0, 0);
164 	vd_set_scale(0.01);
165 	vd_set_origin(0, 0);
166     }
167     code = mesh_init_fill_state(&state, (const gs_shading_mesh_t *)psh, rect_clip,
168 			 dev, pis);
169     if (code < 0)
170 	return code;
171     shade_next_init(&cs, (const gs_shading_mesh_params_t *)&psh->params,
172 		    pis);
173     vertex = (shading_vertex_t *)
174 	gs_alloc_byte_array(pis->memory, per_row, sizeof(*vertex),
175 			    "gs_shading_LfGt_render");
176     if (vertex == 0)
177 	return_error(gs_error_VMerror);
178     for (i = 0; i < per_row; ++i)
179 	if ((code = Gt_next_vertex(state.pshm, &cs, &vertex[i])) < 0)
180 	    goto out;
181     while (!seofp(cs.s)) {
182 	code = Gt_next_vertex(state.pshm, &cs, &next);
183 	if (code < 0)
184 	    goto out;
185 	for (i = 1; i < per_row; ++i) {
186 	    code = Gt_fill_triangle(&state, &vertex[i - 1], &vertex[i], &next);
187 	    if (code < 0)
188 		goto out;
189 	    vertex[i - 1] = next;
190 	    code = Gt_next_vertex(state.pshm, &cs, &next);
191 	    if (code < 0)
192 		goto out;
193 	    code = Gt_fill_triangle(&state, &vertex[i], &vertex[i - 1], &next);
194 	    if (code < 0)
195 		goto out;
196 	}
197 	vertex[per_row - 1] = next;
198     }
199 out:
200     if (VD_TRACE_TRIANGLE_PATCH && vd_allowed('s'))
201 	vd_release_dc;
202     gs_free_object(pis->memory, vertex, "gs_shading_LfGt_render");
203     return code;
204 }
205