Download code

Jump to: navigation, search

Back to Linear_gradient_(C)

Download for Windows: zip

Download for UNIX: zip, tar.gz, tar.bz2

gradient_v1.h

 1 /* The authors of this work have released all rights to it and placed it
 2 in the public domain under the Creative Commons CC0 1.0 waiver
 3 (http://creativecommons.org/publicdomain/zero/1.0/).
 4 
 5 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 6 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 7 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 8 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 9 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
11 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 
13 Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
14 */
15 
16 
17 #ifndef LINEAR_GRADIENT_H
18 #define LINEAR_GRADIENT_H
19 
20 typedef struct Image_t *       Image;
21 typedef uint8_t *              DATA8;
22 
23 struct Image_t
24 {
25 	int   width, height, bpp;
26 	int   stride;
27 	DATA8 bitmap;
28 };
29 
30 typedef struct ColorStop_t *   ColorStop;
31 
32 struct ColorStop_t
33 {
34 	uint8_t rgba[4];
35 	int     dist;
36 };
37 
38 int LinearGradient(Image img, int x1, int y1, int x2, int y2, ColorStop cs, int count);
39 #endif
40 


hijacker
hijacker
hijacker
hijacker

gradient_v1.c

  1 /* The authors of this work have released all rights to it and placed it
  2 in the public domain under the Creative Commons CC0 1.0 waiver
  3 (http://creativecommons.org/publicdomain/zero/1.0/).
  4 
  5 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  6 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  7 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  8 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  9 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 10 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 11 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 12 
 13 Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
 14 */
 15 
 16 #include <stdlib.h>
 17 #include <SDL/SDL.h>
 18 #include "gradient_v1.h"
 19 
 20 typedef struct Iter_t          Iter;
 21 
 22 struct Iter_t
 23 {
 24 	int x, y, xe, ye;
 25 	int dx, dy, err, sx, sy, oldy;
 26 };
 27 
 28 
 29 void InitDDA(Iter * iter, int xs, int xe, int ys, int ye)
 30 {
 31 	/* Pre-condition: xe > xs >= 0 */
 32 	div_t q = div(iter->dy = ye - ys, xe);
 33 	iter->y   = ys;
 34 	iter->ye  = ye;
 35 	iter->x   = xs;
 36 	iter->xe  = xe;
 37 	iter->err = xe >> 1;
 38 	iter->dx  = abs(q.rem);
 39 	iter->sx  = q.quot;
 40 	iter->sy  = (ys < ye ? 1 : -1);
 41 	iter->oldy = -1;
 42 	if (xs > 0)
 43 	{
 44 		q = div(xs * iter->dy + (xe >> 1), xe);
 45 		iter->y   = ys + q.quot;
 46 		iter->err = xe - q.rem;
 47 	}
 48 }
 49 
 50 static inline void IterDDA(Iter * iter)
 51 {
 52 	iter->oldy = iter->y;
 53 	iter->x ++;
 54 	iter->y += iter->sx;
 55 	iter->err -= iter->dx;
 56 	if (iter->err < 0) iter->y += iter->sy, iter->err += iter->xe;
 57 }
 58 #define ISDDAEND(iter) ((iter).x >= (iter).xe)
 59 
 60 static void DrawScanline(Image img, int x, int y, ColorStop cs, int count, int max);
 61 
 62 
 63 int LinearGradient(Image img, int x1, int y1, int x2, int y2, ColorStop cs, int count)
 64 {
 65 	int adj, opp, g, i;
 66 
 67 	/* Check for sane parameters */
 68 	if (x1 == x2 && y1 == y2) return 0;
 69 	if (count < 2) return 0;
 70 
 71 	adj = x2 - x1;
 72 	opp = y2 - y1;
 73 	g = (adj*adj+opp*opp) / adj;
 74 
 75 	/* Adjust range of cs.dist for each color from [0, 100] to [0, g] */
 76 	for (i = 0; i < count; i ++)
 77 	{
 78 		int dist;
 79 		if (i == 0) dist = 0; else
 80 		if (i == count-1) dist = g; else
 81 		if (cs[i].dist == 0) dist = i * g / (count-1);
 82 		else dist = cs[i].dist * g / 100;
 83 		cs[i].dist = dist;
 84 	}
 85 
 86 	Iter pos;
 87 	InitDDA(&pos, 0, y1, x1 + y1 * opp / adj, x1);
 88 	while (pos.x < img->height)
 89 	{
 90 		DrawScanline(img, pos.y, pos.x, cs, count, g);
 91 		IterDDA(&pos);
 92 	}
 93 
 94 	return 1;
 95 }
 96 
 97 #define SETU32(dst, src)      * (uint32_t *) (dst) = * (uint32_t *) (src)
 98 
 99 
100 /* Draw scanline 'y', starting gradient at column 'x', over 'max' pixels */
101 static void DrawScanline(Image img, int x, int y, ColorStop cs, int count, int max)
102 {
103 	DATA8 p = img->bitmap + img->stride * y;
104 	ColorStop c = cs;
105 	Iter r, g, b, a;
106 	int i, w = img->width;
107 
108 	if (x > 0) {
109 		/* Set first iter->x px to color c0 */
110 		uint8_t rgb[4];
111 		memcpy(rgb, c->rgba, 4);
112 		for (i = x; i > 0; SETU32(p, rgb), p += 4, i --);
113 	}
114 
115 	/* Skip first -x px */
116 	if (x < 0) {
117 		for (c ++, i = 1; -x > c->dist && i < count; c ++, i ++);
118 		if (i < count) x += c[-1].dist;
119 		i = -x; x = 0;
120 	}
121 	else i = 0, c++;
122 
123 	/* Draw gradient */
124 	do {
125 		int len = c->dist - c[-1].dist;
126 		InitDDA(&r, i, len, c[-1].rgba[3], c->rgba[3]);
127 		InitDDA(&g, i, len, c[-1].rgba[2], c->rgba[2]);
128 		InitDDA(&b, i, len, c[-1].rgba[1], c->rgba[1]);
129 		InitDDA(&a, i, len, c[-1].rgba[0], c->rgba[0]);
130 
131 		do {
132 			p[3] = r.y; IterDDA(&r);
133 			p[2] = g.y; IterDDA(&g);
134 			p[1] = b.y; IterDDA(&b);
135 			p[0] = a.y; IterDDA(&a); x ++; p += img->bpp;
136 			if (ISDDAEND(r)) {
137 				if (c->dist == max) {
138 					/* Keep using the last color, up to the end of line */
139 					r.sx = r.err = r.dx = 0;
140 					g.sx = g.err = g.dx = 0;
141 					b.sx = b.err = b.dx = 0;
142 					a.sx = a.err = a.dx = 0;
143 					r.xe = 1<<30;
144 					if (x < w) continue;
145 				}
146 				else c ++;
147 				break;
148 			}
149 		}
150 		while (x < w);
151 	} while (x < w);
152 }
153 
154 int main (int argc, char * argv[])
155 {
156 	if (SDL_Init(SDL_INIT_VIDEO) < 0)
157 		return 1;
158 
159 	atexit(SDL_Quit);
160 
161 	SDL_Surface * screen = SDL_SetVideoMode(500, 400, 32, SDL_HWSURFACE|SDL_ANYFORMAT);
162 	if (! screen) return 1;
163 
164 	struct Image_t img = {
165 		.bitmap = screen->pixels, .stride = screen->pitch, .width = screen->w, .height = screen->h,
166 		.bpp = screen->format->BytesPerPixel
167 	};
168 
169 	/* Simple red to blue gradient */
170 	#define  NBCOL     2
171 	struct ColorStop_t colors[NBCOL] = {{{255, 0, 0}}, {{0, 20, 255}}};
172 	int i;
173 
174 	/* We need to convert colors into native format */
175 	for (i = 0; i < NBCOL; i ++)
176 	{
177 		DATA8    rgba = colors[i].rgba;
178 		uint32_t col = SDL_MapRGBA(screen->format, rgba[0], rgba[1], rgba[2], rgba[3]);
179 		SETU32(colors[i].rgba, &col);
180 	}
181 
182 	LinearGradient(&img, 50, 100, 450, 350, colors, NBCOL);
183 	SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
184 
185 	while (1)
186 	{
187 		SDL_Event event;
188 		while (SDL_WaitEvent(&event))
189 		{
190 			switch (event.type) {
191 			case SDL_QUIT: return 0;
192 			case SDL_KEYDOWN:
193 				if (event.key.keysym.sym == SDLK_ESCAPE) return 0;
194 			}
195 		}
196 	}
197 	return 0;
198 }
199 


hijacker
hijacker
hijacker
hijacker

build_and_run_v1.sh

 1 # The authors of this work have released all rights to it and placed it
 2 # in the public domain under the Creative Commons CC0 1.0 waiver
 3 # (http://creativecommons.org/publicdomain/zero/1.0/).
 4 # 
 5 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 6 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 7 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 8 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 9 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
11 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 # 
13 # Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
14 
15 gcc gradient_v1.c -o gradient_v1 `sdl-config --cflags --libs`
16 ./gradient_v1


hijacker
hijacker
hijacker
hijacker

build_and_run_with_GradState.sh

 1 # The authors of this work have released all rights to it and placed it
 2 # in the public domain under the Creative Commons CC0 1.0 waiver
 3 # (http://creativecommons.org/publicdomain/zero/1.0/).
 4 # 
 5 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 6 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 7 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 8 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 9 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
11 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 # 
13 # Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
14 
15 gcc gradient_with_GradState.c -o gradient_with_GradState `sdl-config --cflags --libs`
16 ./gradient_with_GradState


hijacker
hijacker
hijacker
hijacker

build.log

 1 /tmp/litprog7150220/gradient_v1.c:17:21: fatal error: SDL/SDL.h: No such file or directory
 2 compilation terminated.
 3 /tmp/litprog7150220/gradtest.c:16:21: fatal error: SDL/SDL.h: No such file or directory
 4 compilation terminated.
 5 /tmp/litprog7150220/gradient_with_GradState.c:17:21: fatal error: SDL/SDL.h: No such file or directory
 6 compilation terminated.
 7 /tmp/litprog7150220/gradient_general.c:43:15: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'void'
 8 /tmp/litprog7150220/gradient_general.c: In function 'LinearGradient':
 9 /tmp/litprog7150220/gradient_general.c:79:2: warning: implicit declaration of function 'alloca' [-Wimplicit-function-declaration]
10 /tmp/litprog7150220/gradient_general.c:79:13: warning: assignment makes pointer from integer without a cast [enabled by default]
11 /tmp/litprog7150220/gradient_general.c:90:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
12 /tmp/litprog7150220/gradient_general.c:90:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
13 /tmp/litprog7150220/gradient_general.c:132:4: warning: implicit declaration of function 'IterDDA' [-Wimplicit-function-declaration]
14 /tmp/litprog7150220/gradient_general.c: In function 'DrawScanline':
15 /tmp/litprog7150220/gradient_general.c:226:4: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]


hijacker
hijacker
hijacker
hijacker

gradtest.c

 1 /* The authors of this work have released all rights to it and placed it
 2 in the public domain under the Creative Commons CC0 1.0 waiver
 3 (http://creativecommons.org/publicdomain/zero/1.0/).
 4 
 5 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 6 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 7 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 8 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 9 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
11 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 
13 Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
14 */
15 
16 #include <SDL/SDL.h>
17 #include <math.h>
18 #include "gradient_general.h"
19 
20 #define WINW   500
21 #define WINH   400
22 #define NBCOL  2
23 static struct ColorStop_t colors[NBCOL] = {{{255, 0, 0}}, {{20, 20, 255}}};
24 SDL_Surface * screen;
25 int angle;
26 
27 static Uint32 push_ticks(Uint32 interval, void *param)
28 {
29 	SDL_Event event = {.type = SDL_USEREVENT};
30 	SDL_PushEvent(&event);
31 	return interval;
32 }
33 
34 static void reset(Image img)
35 {
36 	angle ++;
37 
38 	int x = cos(angle * M_PI / 180) * 220;
39 	int y = sin(angle * M_PI / 180) * 220;
40 	memset(img->bitmap, 0, img->stride * img->height);
41 	LinearGradient(img, WINW/2-x, WINH/2-y, WINW/2+x, WINH/2+y, colors, NBCOL);
42 	SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
43 }
44 
45 int main (int argc, char * argv[])
46 {
47 	if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) < 0)
48 		return 1;
49 
50 	atexit(SDL_Quit);
51 
52 	screen = SDL_SetVideoMode(WINW, WINH, 32, SDL_HWSURFACE|SDL_ANYFORMAT);
53 	if (! screen) return 1;
54 
55 	struct Image_t img = {
56 		.bitmap = screen->pixels, .stride = screen->pitch, .width = screen->w, .height = screen->h,
57 		.bpp = screen->format->BytesPerPixel
58 	};
59 
60 	int i;
61 
62 	/* We need to convert colors into native format */
63 	for (i = 0; i < NBCOL; i ++)
64 	{
65 		DATA8    rgba = colors[i].rgba;
66 		uint32_t col = SDL_MapRGBA(screen->format, rgba[0], rgba[1], rgba[2], rgba[3]);
67 		SETU32(colors[i].rgba, &col);
68 	}
69 
70 	SDL_AddTimer(10, push_ticks, NULL);
71 
72 	while (1)
73 	{
74 		SDL_Event event;
75 		while (SDL_WaitEvent(&event))
76 		{
77 			switch (event.type) {
78 			case SDL_USEREVENT: reset(&img); break;
79 			case SDL_QUIT: return 0;
80 			case SDL_KEYDOWN:
81 				if (event.key.keysym.sym == SDLK_ESCAPE) return 0;
82 			}
83 		}
84 	}
85 	return 0;
86 }
87 
88 #ifdef WIN32
89 #include <windows.h>
90 int WINAPI WinMain (HINSTANCE instance,
91                     HINSTANCE previnst,
92                     LPSTR args,
93                     int wndState)
94 {
95 	return main(0, NULL);
96 }
97 #endif
98 


hijacker
hijacker
hijacker
hijacker

gradient_with_GradState.c

  1 /* The authors of this work have released all rights to it and placed it
  2 in the public domain under the Creative Commons CC0 1.0 waiver
  3 (http://creativecommons.org/publicdomain/zero/1.0/).
  4 
  5 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  6 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  7 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  8 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  9 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 10 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 11 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 12 
 13 Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
 14 */
 15 
 16 #include <stdlib.h>
 17 #include <SDL/SDL.h>
 18 #include "gradient_v1.h"
 19 
 20 typedef struct Iter_t          Iter;
 21 
 22 struct Iter_t
 23 {
 24 	int x, y, xe, ye;
 25 	int dx, dy, err, sx, sy, oldy;
 26 };
 27 
 28 
 29 void InitDDA(Iter * iter, int xs, int xe, int ys, int ye)
 30 {
 31 	/* Pre-condition: xe > xs >= 0 */
 32 	div_t q = div(iter->dy = ye - ys, xe);
 33 	iter->y   = ys;
 34 	iter->ye  = ye;
 35 	iter->x   = xs;
 36 	iter->xe  = xe;
 37 	iter->err = xe >> 1;
 38 	iter->dx  = abs(q.rem);
 39 	iter->sx  = q.quot;
 40 	iter->sy  = (ys < ye ? 1 : -1);
 41 	iter->oldy = -1;
 42 	if (xs > 0)
 43 	{
 44 		q = div(xs * iter->dy + (xe >> 1), xe);
 45 		iter->y   = ys + q.quot;
 46 		iter->err = xe - q.rem;
 47 	}
 48 }
 49 
 50 static inline void IterDDA(Iter * iter)
 51 {
 52 	iter->oldy = iter->y;
 53 	iter->x ++;
 54 	iter->y += iter->sx;
 55 	iter->err -= iter->dx;
 56 	if (iter->err < 0) iter->y += iter->sy, iter->err += iter->xe;
 57 }
 58 #define ISDDAEND(iter) ((iter).x >= (iter).xe)
 59 
 60 typedef struct GradState_t     GradState;
 61 
 62 struct GradState_t
 63 {
 64 	Iter r, g, b, a, pos;
 65 	int step, dir, err;
 66 	ColorStop c;
 67 };
 68 
 69 static void DrawScanline(Image img, GradState * state, int max);
 70 
 71 
 72 int LinearGradient(Image img, int x1, int y1, int x2, int y2, ColorStop cs, int count)
 73 {
 74 	int adj, opp, g, i;
 75 
 76 	/* Check for sane parameters */
 77 	if (x1 == x2 && y1 == y2) return 0;
 78 	if (count < 2) return 0;
 79 
 80 	adj = x2 - x1;
 81 	opp = y2 - y1;
 82 	g = (adj*adj+opp*opp) / adj;
 83 
 84 	/* Adjust range of cs.dist for each color from [0, 100] to [0, g] */
 85 	for (i = 0; i < count; i ++)
 86 	{
 87 		int dist;
 88 		if (i == 0) dist = 0; else
 89 		if (i == count-1) dist = g; else
 90 		if (cs[i].dist == 0) dist = i * g / (count-1);
 91 		else dist = cs[i].dist * g / 100;
 92 		cs[i].dist = dist;
 93 	}
 94 
 95 	/* Draw the gradient: init DDA to scan perpendicular values */
 96 	GradState state;
 97 	state.c = cs;
 98 	state.step = count;
 99 	InitDDA(&state.pos, 0, y1, x1 + y1 * opp / adj, x1);
100 	while (state.pos.x < img->height)
101 	{
102 		DrawScanline(img, &state, g);
103 		IterDDA(&state.pos);
104 	}
105 
106 	return 1;
107 }
108 
109 #define SETU32(dst, src)      * (uint32_t *) (dst) = * (uint32_t *) (src)
110 
111 
112 static void DrawScanline(Image img, GradState * state, int max)
113 {
114 	DATA8 p = img->bitmap + img->stride * state->pos.x;
115 	ColorStop c = state->c;
116 	int i, diff, w = img->width, chan = img->bpp;
117 	int x = state->pos.y;
118 
119 	/* Horizontal predictor */
120 	if (state->pos.x > 0)
121 	{
122 		int size;
123 		diff = state->pos.y - state->pos.oldy;
124 		w    = abs(diff);
125 		size = (img->width - w) * chan;
126 		if (diff < 0) {
127 			memcpy(p, p - img->stride + chan, size);
128 			p += (img->width - 1) * chan;
129 		}
130 		else memcpy(p + chan * diff, p - img->stride, size);
131 		/* No differences between this line and the previous one */
132 		if (w == 0) return;
133 		x = 0;
134 	}
135 	else /* First line */
136 	{
137 		if (x > 0)
138 			/* Set first iter->x px to color c0 */
139 			for (i = x; i > 0; SETU32(p, c->rgba), p += 4, i --);
140 
141 		/* Skip first -x px */
142 		if (x < 0) {
143 			for (c ++, i = state->step-1; -x > c->dist && i > 0; c ++, i --);
144 			x += c[-1].dist;
145 			i = -x; x = 0;
146 		}
147 		else i = 0, c++;
148 
149 		diff = c->dist - c[-1].dist;
150 		InitDDA(&state->r, i, diff, c[-1].rgba[3], c->rgba[3]);
151 		InitDDA(&state->g, i, diff, c[-1].rgba[2], c->rgba[2]);
152 		InitDDA(&state->b, i, diff, c[-1].rgba[1], c->rgba[1]);
153 		InitDDA(&state->a, i, diff, c[-1].rgba[0], c->rgba[0]);
154 	}
155 
156 	/* Draw gradient */
157 	do {
158 		p[3] = state->r.y; IterDDA(&state->r);
159 		p[2] = state->g.y; IterDDA(&state->g);
160 		p[1] = state->b.y; IterDDA(&state->b);
161 		p[0] = state->a.y; IterDDA(&state->a); x ++; p += 4;
162 		if (ISDDAEND(state->r)) {
163 			if (c->dist == max) {
164 				/* Keep using the last color, up to the end of line */
165 				state->r.sx = state->r.err = state->r.dx = 0;
166 				state->g.sx = state->g.err = state->g.dx = 0;
167 				state->b.sx = state->b.err = state->b.dx = 0;
168 				state->a.sx = state->a.err = state->a.dx = 0;
169 				state->r.xe = 1<<30;
170 				if (x < w) continue; else break;
171 			}
172 			else c ++;
173 			/* Next color stop */
174 			diff = c->dist - c[-1].dist;
175 			InitDDA(&state->r, 0, diff, c[-1].rgba[3], c->rgba[3]);
176 			InitDDA(&state->g, 0, diff, c[-1].rgba[2], c->rgba[2]);
177 			InitDDA(&state->b, 0, diff, c[-1].rgba[1], c->rgba[1]);
178 			InitDDA(&state->a, 0, diff, c[-1].rgba[0], c->rgba[0]);
179 		}
180 	} while (x < w);
181 	state->c = c;
182 }
183 
184 int main (int argc, char * argv[])
185 {
186 	if (SDL_Init(SDL_INIT_VIDEO) < 0)
187 		return 1;
188 
189 	atexit(SDL_Quit);
190 
191 	SDL_Surface * screen = SDL_SetVideoMode(500, 400, 32, SDL_HWSURFACE|SDL_ANYFORMAT);
192 	if (! screen) return 1;
193 
194 	struct Image_t img = {
195 		.bitmap = screen->pixels, .stride = screen->pitch, .width = screen->w, .height = screen->h,
196 		.bpp = screen->format->BytesPerPixel
197 	};
198 
199 	/* Simple red to blue gradient */
200 	#define  NBCOL     2
201 	struct ColorStop_t colors[NBCOL] = {{{255, 0, 0}}, {{0, 20, 255}}};
202 	int i;
203 
204 	/* We need to convert colors into native format */
205 	for (i = 0; i < NBCOL; i ++)
206 	{
207 		DATA8    rgba = colors[i].rgba;
208 		uint32_t col = SDL_MapRGBA(screen->format, rgba[0], rgba[1], rgba[2], rgba[3]);
209 		SETU32(colors[i].rgba, &col);
210 	}
211 
212 	LinearGradient(&img, 50, 100, 450, 350, colors, NBCOL);
213 	SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
214 
215 	while (1)
216 	{
217 		SDL_Event event;
218 		while (SDL_WaitEvent(&event))
219 		{
220 			switch (event.type) {
221 			case SDL_QUIT: return 0;
222 			case SDL_KEYDOWN:
223 				if (event.key.keysym.sym == SDLK_ESCAPE) return 0;
224 			}
225 		}
226 	}
227 	return 0;
228 }
229 


hijacker
hijacker
hijacker
hijacker

build_and_run_general.sh

 1 # The authors of this work have released all rights to it and placed it
 2 # in the public domain under the Creative Commons CC0 1.0 waiver
 3 # (http://creativecommons.org/publicdomain/zero/1.0/).
 4 # 
 5 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 6 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 7 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 8 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 9 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
11 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 # 
13 # Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
14 
15 gcc gradtest.c gradient_general.c -o gradient_general `sdl-config --cflags --libs`
16 ./gradient_general
17 


hijacker
hijacker
hijacker
hijacker

gradient_general.h

 1 /* The authors of this work have released all rights to it and placed it
 2 in the public domain under the Creative Commons CC0 1.0 waiver
 3 (http://creativecommons.org/publicdomain/zero/1.0/).
 4 
 5 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 6 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 7 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 8 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 9 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
11 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 
13 Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
14 */
15 
16 #ifndef LINEAR_GRADIENT_H
17 #define LINEAR_GRADIENT_H
18 
19 typedef struct Image_t *       Image;
20 typedef uint8_t *              DATA8;
21 
22 struct Image_t
23 {
24 	int   width, height, bpp;
25 	int   stride;
26 	DATA8 bitmap;
27 };
28 
29 typedef struct ColorStop_t *   ColorStop;
30 
31 struct ColorStop_t
32 {
33 	uint8_t rgba[4];
34 	int     dist;
35 };
36 
37 typedef struct Iter_t          Iter;
38 
39 struct Iter_t
40 {
41 	int x, y, xe, ye;
42 	int dx, dy, err, sx, sy, oldy;
43 };
44 
45 
46 typedef struct GradState_t     GradState;
47 
48 struct GradState_t
49 {
50 	Iter r, g, b, a, pos;
51 	int step, dir, err;
52 	ColorStop c;
53 };
54 
55 int LinearGradient(Image img, int x1, int y1, int x2, int y2, ColorStop cs, int count);
56 
57 #ifndef SETU32
58 #define SETU32(dst, src)      * (uint32_t *) (dst) = * (uint32_t *) (src)
59 
60 #endif
61 #ifndef swap
62 #define swap(a, b) do { int temp = a; a = b; b = temp; } while(0)
63 #endif
64 
65 #endif


hijacker
hijacker
hijacker
hijacker

gradient_general.c

  1 /* The authors of this work have released all rights to it and placed it
  2 in the public domain under the Creative Commons CC0 1.0 waiver
  3 (http://creativecommons.org/publicdomain/zero/1.0/).
  4 
  5 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  6 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  7 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  8 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  9 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 10 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 11 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 12 
 13 Retrieved from: http://en.literateprograms.org/Linear_gradient_(C)?oldid=19179
 14 */
 15 
 16 #include <stdlib.h>
 17 #include <stdint.h>
 18 #include <string.h>
 19 #include <malloc.h>
 20 #include "gradient_general.h"
 21 
 22 void InitDDA(Iter * iter, int xs, int xe, int ys, int ye)
 23 {
 24 	/* Pre-condition: xe > xs >= 0 */
 25 	div_t q = div(iter->dy = ye - ys, xe);
 26 	iter->y   = ys;
 27 	iter->ye  = ye;
 28 	iter->x   = xs;
 29 	iter->xe  = xe;
 30 	iter->err = xe >> 1;
 31 	iter->dx  = abs(q.rem);
 32 	iter->sx  = q.quot;
 33 	iter->sy  = (ys < ye ? 1 : -1);
 34 	iter->oldy = -1;
 35 	if (xs > 0)
 36 	{
 37 		q = div(xs * iter->dy + (xe >> 1), xe);
 38 		iter->y   = ys + q.quot;
 39 		iter->err = xe - q.rem;
 40 	}
 41 }
 42 
 43 static inline void IterDDA(Iter * iter)
 44 {
 45 	iter->oldy = iter->y;
 46 	iter->x ++;
 47 	iter->y += iter->sx;
 48 	iter->err -= iter->dx;
 49 	if (iter->err < 0) iter->y += iter->sy, iter->err += iter->xe;
 50 }
 51 #define ISDDAEND(iter) ((iter).x >= (iter).xe)
 52 
 53 static void DrawScanline(Image img, GradState * state, int max);
 54 static void AntiAlias(Image img, int err, int pos);
 55 static void AntiAliasV(Image img, int err, int pos, DATA8 src);
 56 
 57 int LinearGradient(Image img, int x1, int y1, int x2, int y2, ColorStop cs, int count)
 58 {
 59 	int adj, opp, g, i, horz, inc;
 60 	ColorStop colors, c;
 61 	GradState state;
 62 
 63 	/* Check for sane parameters */
 64 	if (x1 == x2 && y1 == y2) return 0;
 65 	if (count < 2) return 0;
 66 
 67 	adj = x2 - x1;
 68 	opp = y2 - y1;
 69 	horz = abs(adj) >= abs(opp);
 70 	state.dir = img->bpp;
 71 	if (! horz) { swap(opp, adj); swap(x1, y1); swap(x2, y2); }
 72 	if (opp * adj < 0) {
 73 		state.dir = - state.dir;
 74 		i = horz ? img->width : img->height;
 75 		x1 = i - x1; x2 = i - x2;
 76 		adj = x2 - x1;
 77 	}
 78 	g = (adj*adj+opp*opp) / adj;
 79 	c = colors = alloca(sizeof *c * count);
 80 	inc = 1;
 81 	state.c = c;
 82 	state.step = count;
 83 	if (g < 0) c += count-1, inc = -1, c->dist = abs(g);
 84 	else colors->dist = 0;
 85 
 86 	/* Adjust range of cs.dist for each color from [0, 100] to [0, g] */
 87 	for (i = 0; i < count; i ++, c += inc)
 88 	{
 89 		int dist;
 90 		SETU32(c->rgba, cs[i].rgba);
 91 		if (i == 0) dist = 0; else
 92 		if (i == count-1) dist = g; else
 93 		if (cs[i].dist == 0) dist = i * g / (count-1);
 94 		else dist = cs[i].dist * g / 100;
 95 		if (inc > 0)
 96 		{
 97 			if (dist < 0) dist = -dist;
 98 		} else {
 99 			if (g < 0) dist -= g;
100 			else dist = g - dist;
101 		}
102 		c->dist = dist;
103 	}
104 
105 	/* Draw the gradient: init DDA to scan perpendicular values */
106 	if (y1 == y2)
107 	{
108 		/* Horizontal gradient, handle special case where y1 == y2 == 0 */
109 		InitDDA(&state.pos, 0, 1, x1, x1);
110 	}
111 	/* Use ref point the farther away from y = 0, for extra precision */
112 	else if (abs(y1) < abs(y2))
113 	{
114 		int x0 = x1 + y1 * opp / adj;
115 		InitDDA(&state.pos, 0, y2, x0, x0 - opp * y2 / adj);
116 	}
117 	else InitDDA(&state.pos, 0, y1, x1 + y1 * opp / adj, x1);
118 	state.pos.err = state.pos.xe;
119 	state.err = state.dir * state.pos.sy;
120 	if (horz)
121 	{
122 		int err[2], pos = 0, error;
123 		while (state.pos.x < img->height)
124 		{
125 			if (state.err < 0) error = (state.pos.err << 16) / state.pos.xe;
126 			else               error = ((state.pos.xe - state.pos.err) << 16) / state.pos.xe;
127 			err[state.pos.x&1] = error;
128 
129 			DrawScanline(img, &state, g);
130 			if (state.pos.x > 0)
131 				AntiAlias(img, error = err[(state.pos.x-1)&1], pos), pos += img->stride;
132 			IterDDA(&state.pos);
133 		}
134 	}
135 	else /* iterate over vertical axis */
136 	{
137 		int   chan = img->bpp, max = img->width, error, pos;
138 		Image imgtmp = malloc(sizeof *img + img->height * chan * 2);
139 		DATA8 line;
140 		if (imgtmp == NULL) return 0;
141 
142 		memcpy(imgtmp, img, sizeof *img);
143 		imgtmp->bitmap = line = (DATA8) (imgtmp+1);
144 		imgtmp->width  = img->height;
145 		imgtmp->height = img->width;
146 		imgtmp->stride = img->height * chan;
147 		pos = 0;
148 		do {
149 			if (state.err < 0) error = (state.pos.err << 16) / state.pos.xe;
150 			else               error = ((state.pos.xe - state.pos.err) << 16) / state.pos.xe;
151 			DrawScanline(imgtmp, &state, g);
152 			AntiAliasV(img, error, pos, line); pos += chan;
153 			if (state.pos.x > 0)
154 				memcpy(imgtmp->bitmap, line = imgtmp->bitmap + imgtmp->stride, imgtmp->stride);
155 			IterDDA(&state.pos); state.pos.x = 1; max --;
156 		}
157 		while (max > 0);
158 		free(imgtmp);
159 	}
160 	return 1;
161 }
162 
163 static void AntiAlias(Image img, int err, int pos)
164 {
165 	DATA8 p = img->bitmap + pos;
166 	int   c = img->bpp;
167 	int   i = img->width-1;
168 	if (err == 0) return;
169 	for (p += i*c, c = -c; i > 0; i --, p += c) {
170 		p[0] = ((65536 - err) * p[0] + err * p[c]   + 65536/2) >> 16;
171 		p[1] = ((65536 - err) * p[1] + err * p[c+1] + 65536/2) >> 16;
172 		p[2] = ((65536 - err) * p[2] + err * p[c+2] + 65536/2) >> 16;
173 		p[3] = ((65536 - err) * p[3] + err * p[c+3] + 65536/2) >> 16;
174 	}
175 }
176 
177 /* Copy scanline into column and apply anti-aliasing */
178 static void AntiAliasV(Image img, int err, int pos, DATA8 src)
179 {
180 	DATA8 p = img->bitmap + pos;
181 	int   c = img->stride, inc = - img->bpp;
182 	int   i = img->height-1;
183 	for (p += i*c, c = -c, src += i * -inc; i > 0; i --, p += c, src += inc) {
184 		p[0] = ((65536 - err) * src[0] + err * src[inc]   + 65536/2) >> 16;
185 		p[1] = ((65536 - err) * src[1] + err * src[inc+1] + 65536/2) >> 16;
186 		p[2] = ((65536 - err) * src[2] + err * src[inc+2] + 65536/2) >> 16;
187 		p[3] = ((65536 - err) * src[3] + err * src[inc+3] + 65536/2) >> 16;
188 	}
189 	SETU32(p, src);
190 }
191 
192 /* Draw scanline 'pos.x', starting gradient at column 'pos.y', over 'max' pixels */
193 static void DrawScanline(Image img, GradState * state, int max)
194 {
195 	DATA8 p = img->bitmap + img->stride * state->pos.x;
196 	ColorStop c = state->c;
197 	int i, diff, w = img->width, chan = img->bpp;
198 	int x = state->pos.y;
199 
200 	if (max < 0) x += max, max = -max;
201 	if (state->pos.sy < 0 && state->pos.err > 0) x --;
202 
203 	/* Horizontal predictor */
204 	if (state->pos.x > 0)
205 	{
206 		int size;
207 		diff = state->pos.y - state->pos.oldy;
208 		w    = abs(diff);
209 		size = (img->width - w) * chan;
210 		if (state->dir < 0) diff = - diff;
211 		if (diff < 0) {
212 			memcpy(p, p - img->stride + chan, size);
213 			p += (img->width - 1) * chan;
214 		}
215 		else memcpy(p + chan * diff, p - img->stride, size);
216 		/* No differences between this line and the previous one */
217 		if (w == 0) return;
218 		x = 0; chan = state->dir;
219 	}
220 	else /* First line */
221 	{
222 		chan = state->dir;
223 		if (chan < 0) p += (img->width - 1) * -chan;
224 		if (x > 0)
225 			/* Set first iter->x px to color c0 */
226 			for (i = x; i > 0; SETU32(p, c->rgba), p += chan, i --);
227 
228 		/* Skip first -x px */
229 		if (x < 0) {
230 			for (c ++, i = state->step-1; -x > c->dist && i > 0; c ++, i --);
231 			x += c[-1].dist;
232 			i = -x; x = 0;
233 		}
234 		else i = 0, c++;
235 
236 		diff = c->dist - c[-1].dist;
237 		InitDDA(&state->r, i, diff, c[-1].rgba[3], c->rgba[3]);
238 		InitDDA(&state->g, i, diff, c[-1].rgba[2], c->rgba[2]);
239 		InitDDA(&state->b, i, diff, c[-1].rgba[1], c->rgba[1]);
240 		InitDDA(&state->a, i, diff, c[-1].rgba[0], c->rgba[0]);
241 	}
242 
243 	/* Draw gradient */
244 	do {
245 		p[3] = state->r.y; IterDDA(&state->r);
246 		p[2] = state->g.y; IterDDA(&state->g);
247 		p[1] = state->b.y; IterDDA(&state->b);
248 		p[0] = state->a.y; IterDDA(&state->a); x ++; p += chan;
249 		if (ISDDAEND(state->r)) {
250 			if (c->dist == max) {
251 				/* Keep using the last color, up to the end of line */
252 				state->r.sx = state->r.err = state->r.dx = 0;
253 				state->g.sx = state->g.err = state->g.dx = 0;
254 				state->b.sx = state->b.err = state->b.dx = 0;
255 				state->a.sx = state->a.err = state->a.dx = 0;
256 				state->r.xe = 1<<30;
257 				if (x < w) continue; else break;
258 			}
259 			else c ++;
260 			/* Next color stop */
261 			diff = c->dist - c[-1].dist;
262 			InitDDA(&state->r, 0, diff, c[-1].rgba[3], c->rgba[3]);
263 			InitDDA(&state->g, 0, diff, c[-1].rgba[2], c->rgba[2]);
264 			InitDDA(&state->b, 0, diff, c[-1].rgba[1], c->rgba[1]);
265 			InitDDA(&state->a, 0, diff, c[-1].rgba[0], c->rgba[0]);
266 		}
267 	} while (x < w);
268 	state->c = c;
269 }
270 


hijacker
hijacker
hijacker
hijacker