File: edge.c

package info (click to toggle)
effectv 0.3.11-1
  • links: PTS
  • area: main
  • in suites: lenny, squeeze
  • size: 748 kB
  • ctags: 1,316
  • sloc: ansic: 12,575; makefile: 216; perl: 38
file content (158 lines) | stat: -rw-r--r-- 3,826 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 * EffecTV - Realtime Digital Video Effector
 * Copyright (C) 2001-2006 FUKUCHI Kentaro
 *
 * EdgeTV - detects edge and display it in good old computer way. 
 * Copyright (C) 2001-2002 FUKUCHI Kentaro
 *
 * The idea of EdgeTV is taken from Adrian Likins's effector script for GIMP,
 * `Predator effect.'
 *
 * The algorithm of the original script pixelizes the image at first, then
 * it adopts the edge detection filter to the image. It also adopts MaxRGB
 * filter to the image. This is not used in EdgeTV.
 * This code is highly optimized and employs many fake algorithms. For example,
 * it devides a value with 16 instead of using sqrt() in line 132-134. It is
 * too hard for me to write detailed comment in this code in English.
 */

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "EffecTV.h"
#include "utils.h"

static int start(void);
static int stop(void);
static int draw(RGB32 *src, RGB32 *dest);

static char *effectname = "EdgeTV";
static int stat;
static RGB32 *map;

static int map_width;
static int map_height;

static int video_width_margin;

effect *edgeRegister(void)
{
	effect *entry;
	
	map_width = video_width / 4;
	map_height = video_height / 4;
	video_width_margin = video_width - map_width * 4;

	sharedbuffer_reset();
	map = (RGB32 *)sharedbuffer_alloc(map_width*map_height*PIXEL_SIZE*2);
	if(map == NULL) {
		return NULL;
	}

	entry = (effect *)malloc(sizeof(effect));
	if(entry == NULL) {
		return NULL;
	}
	
	entry->name = effectname;
	entry->start = start;
	entry->stop = stop;
	entry->draw = draw;
	entry->event = NULL;

	return entry;
}

static int start(void)
{
	memset(map, 0, map_width * map_height * PIXEL_SIZE * 2);

	stat = 1;
	return 0;
}

static int stop(void)
{
	stat = 0;
	return 0;
}

static int draw(RGB32 *src, RGB32 *dest)
{
	int x, y;
	int r, g, b;
	RGB32 p, q;
	RGB32 v0, v1, v2, v3;

	src += video_width*4+4;
	dest += video_width*4+4;
	for(y=1; y<map_height-1; y++) {
		for(x=1; x<map_width-1; x++) {
			p = *src;
			q = *(src - 4);

/* difference between the current pixel and right neighbor. */
			r = ((int)(p & 0xff0000) - (int)(q & 0xff0000))>>16;
			g = ((int)(p & 0x00ff00) - (int)(q & 0x00ff00))>>8;
			b = ((int)(p & 0x0000ff) - (int)(q & 0x0000ff));
			r *= r; /* Multiply itself and divide it with 16, instead of */
			g *= g; /* using abs(). */
			b *= b;
			r = r>>5; /* To lack the lower bit for saturated addition,  */
			g = g>>5; /* devide the value with 32, instead of 16. It is */
			b = b>>4; /* same as `v2 &= 0xfefeff' */
			if(r>127) r = 127;
			if(g>127) g = 127;
			if(b>255) b = 255;
			v2 = (r<<17)|(g<<9)|b;

/* difference between the current pixel and upper neighbor. */
			q = *(src - video_width*4);
			r = ((int)(p & 0xff0000) - (int)(q & 0xff0000))>>16;
			g = ((int)(p & 0x00ff00) - (int)(q & 0x00ff00))>>8;
			b = ((int)(p & 0x0000ff) - (int)(q & 0x0000ff));
			r *= r;
			g *= g;
			b *= b;
			r = r>>5;
			g = g>>5;
			b = b>>4;
			if(r>127) r = 127;
			if(g>127) g = 127;
			if(b>255) b = 255;
			v3 = (r<<17)|(g<<9)|b;

			v0 = map[(y-1)*map_width*2+x*2];
			v1 = map[y*map_width*2+(x-1)*2+1];
			map[y*map_width*2+x*2] = v2;
			map[y*map_width*2+x*2+1] = v3;
			r = v0 + v1;
			g = r & 0x01010100;
			dest[0] = r | (g - (g>>8));
			r = v0 + v3;
			g = r & 0x01010100;
			dest[1] = r | (g - (g>>8));
			dest[2] = v3;
			dest[3] = v3;
			r = v2 + v1;
			g = r & 0x01010100;
			dest[video_width] = r | (g - (g>>8));
			r = v2 + v3;
			g = r & 0x01010100;
			dest[video_width+1] = r | (g - (g>>8));
			dest[video_width+2] = v3;
			dest[video_width+3] = v3;
			dest[video_width*2] = v2;
			dest[video_width*2+1] = v2;
			dest[video_width*3] = v2;
			dest[video_width*3+1] = v2;

			src += 4;
			dest += 4;
		}
		src += video_width*3+8+video_width_margin;
		dest += video_width*3+8+video_width_margin;
	}

	return 0;
}