Skip to content

Commit dcca311

Browse files
committed
Finished v1.0 of documentation.
Finished v1.0 of documentation.
1 parent 922d5de commit dcca311

File tree

3 files changed

+249
-0
lines changed

3 files changed

+249
-0
lines changed

doc/gb_camera_doc.odt

4.34 KB
Binary file not shown.

doc/gb_camera_doc_v1_0.pdf

428 KB
Binary file not shown.

doc/sample_code.c

+249
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
2+
//--------------------------------------------------------------------
3+
4+
// The actual sensor image is 128x126 or so.
5+
#define GBCAM_SENSOR_EXTRA_LINES (8)
6+
#define GBCAM_SENSOR_W (128)
7+
#define GBCAM_SENSOR_H (112+GBCAM_SENSOR_EXTRA_LINES)
8+
9+
#define GBCAM_W (128)
10+
#define GBCAM_H (112)
11+
12+
#define BIT(n) (1<<(n))
13+
14+
// Webcam image
15+
static int gb_camera_webcam_output[GBCAM_SENSOR_W][GBCAM_SENSOR_H];
16+
// Image processed by sensor chip
17+
static int gb_cam_retina_output_buf[GBCAM_SENSOR_W][GBCAM_SENSOR_H];
18+
19+
//--------------------------------------------------------------------
20+
21+
static inline int clamp(int min, int value, int max)
22+
{
23+
if(value < min) return min;
24+
if(value > max) return max;
25+
return value;
26+
}
27+
28+
static inline int min(int a, int b) { return (a < b) ? a : b; }
29+
30+
static inline int max(int a, int b) { return (a > b) ? a : b; }
31+
32+
//--------------------------------------------------------------------
33+
34+
static inline u32 gb_cam_matrix_process(u32 value, u32 x, u32 y)
35+
{
36+
x = x & 3;
37+
y = y & 3;
38+
39+
int base = 6 + (y*4 + x) * 3;
40+
41+
u32 r0 = CAM_REG[base+0];
42+
u32 r1 = CAM_REG[base+1];
43+
u32 r2 = CAM_REG[base+2];
44+
45+
if(value < r0) return 0x00;
46+
else if(value < r1) return 0x40;
47+
else if(value < r2) return 0x80;
48+
return 0xC0;
49+
}
50+
51+
static void GB_CameraTakePicture(void)
52+
{
53+
int i, j;
54+
55+
//------------------------------------------------
56+
57+
// Get webcam image
58+
// ----------------
59+
60+
GB_CameraWebcamCapture();
61+
62+
//------------------------------------------------
63+
64+
// Get configuration
65+
// -----------------
66+
67+
// Register 0
68+
u32 P_bits = 0;
69+
u32 M_bits = 0;
70+
71+
switch( (CAM_REG[0]>>1)&3 )
72+
{
73+
case 0: P_bits = 0x00; M_bits = 0x01; break;
74+
case 1: P_bits = 0x01; M_bits = 0x00; break;
75+
case 2: case 3: P_bits = 0x01; M_bits = 0x02; break;
76+
default: break;
77+
}
78+
79+
// Register 1
80+
u32 N_bit = (CAM_REG[1] & BIT(7)) >> 7;
81+
u32 VH_bits = (CAM_REG[1] & (BIT(6)|BIT(5))) >> 5;
82+
83+
// Registers 2 and 3
84+
u32 EXPOSURE_bits = CAM_REG[3] | (CAM_REG[2]<<8);
85+
86+
// Register 4
87+
const float edge_ratio_lut[8] = { 0.50, 0.75, 1.00, 1.25, 2.00, 3.00, 4.00, 5.00 };
88+
89+
float EDGE_alpha = edge_ratio_lut[(CAM_REG[4] & 0x70)>>4];
90+
91+
u32 E3_bit = (CAM_REG[4] & BIT(7)) >> 7;
92+
u32 I_bit = (CAM_REG[4] & BIT(3)) >> 3;
93+
94+
//------------------------------------------------
95+
96+
// Calculate timings
97+
// -----------------
98+
99+
CAM_CLOCKS_LEFT = 4 * ( 32446 + ( N_bit ? 0 : 512 ) + 16 * EXPOSURE_bits );
100+
101+
//------------------------------------------------
102+
103+
// Sensor handling
104+
// ---------------
105+
106+
//Copy webcam buffer to sensor buffer applying color correction
107+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
108+
{
109+
int value = gb_camera_webcam_output[i][j];
110+
value = 128 + 0.75f*(float)(value-128);
111+
gb_cam_retina_output_buf[i][j] = clamp(0,value,255);
112+
}
113+
114+
// Apply exposure time (with a reference of 0x0100)
115+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
116+
{
117+
int result = gb_cam_retina_output_buf[i][j];
118+
result = ( (result * EXPOSURE_bits ) / 0x0100 );
119+
gb_cam_retina_output_buf[i][j] = clamp(0,result,255);
120+
}
121+
122+
if(I_bit) // Invert image
123+
{
124+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
125+
gb_cam_retina_output_buf[i][j] ^= 255;
126+
}
127+
128+
int temp_buf[GBCAM_SENSOR_W][GBCAM_SENSOR_H];
129+
130+
u32 filtering_mode = (N_bit<<3) | (VH_bits<<1) | E3_bit;
131+
switch(filtering_mode)
132+
{
133+
case 0x0: // 1-D filtering
134+
{
135+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
136+
{
137+
temp_buf[i][j] = gb_cam_retina_output_buf[i][j];
138+
}
139+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
140+
{
141+
int ms = temp_buf[i][min(j+1,GBCAM_SENSOR_H-1)];
142+
int px = temp_buf[i][j];
143+
144+
int value = 0;
145+
if(P_bits&BIT(0)) value += px;
146+
if(P_bits&BIT(1)) value += ms;
147+
if(M_bits&BIT(0)) value -= px;
148+
if(M_bits&BIT(1)) value -= ms;
149+
gb_cam_retina_output_buf[i][j] = clamp(0,value,255);
150+
}
151+
break;
152+
}
153+
case 0x2: //1-D filtering + Horiz. enhancement : P + {2P-(MW+ME)} * alpha
154+
{
155+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
156+
{
157+
int mw = gb_cam_retina_output_buf[max(0,i-1)][j];
158+
int me = gb_cam_retina_output_buf[min(i+1,GBCAM_SENSOR_W-1)][j];
159+
int px = gb_cam_retina_output_buf[i][j];
160+
161+
temp_buf[i][j] = clamp(0,px+((2*px-mw-me)*EDGE_alpha),255);
162+
}
163+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
164+
{
165+
int ms = temp_buf[i][min(j+1,GBCAM_SENSOR_H-1)];
166+
int px = temp_buf[i][j];
167+
168+
int value = 0;
169+
if(P_bits&BIT(0)) value += px;
170+
if(P_bits&BIT(1)) value += ms;
171+
if(M_bits&BIT(0)) value -= px;
172+
if(M_bits&BIT(1)) value -= ms;
173+
gb_cam_retina_output_buf[i][j] = clamp(0,value,255);
174+
}
175+
break;
176+
}
177+
case 0xE: //2D enhancement : P + {4P-(MN+MS+ME+MW)} * alpha
178+
{
179+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
180+
{
181+
int ms = gb_cam_retina_output_buf[i][min(j+1,GBCAM_SENSOR_H-1)];
182+
int mn = gb_cam_retina_output_buf[i][max(0,j-1)];
183+
int mw = gb_cam_retina_output_buf[max(0,i-1)][j];
184+
int me = gb_cam_retina_output_buf[min(i+1,GBCAM_SENSOR_W-1)][j];
185+
int px = gb_cam_retina_output_buf[i][j];
186+
187+
temp_buf[i][j] = clamp(0,px+((4*px-mw-me-mn-ms)*EDGE_alpha),255);
188+
}
189+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
190+
{
191+
gb_cam_retina_output_buf[i][j] = temp_buf[i][j];
192+
}
193+
break;
194+
}
195+
case 0x1:
196+
{
197+
// In my GB Camera cartridge this is always the same color.
198+
// The datasheet of the sensor doesn't have this configuration
199+
// documented. Maybe this is a bug?
200+
for(i = 0; i < GBCAM_SENSOR_W; i++) for(j = 0; j < GBCAM_SENSOR_H; j++)
201+
{
202+
gb_cam_retina_output_buf[i][j] = 0x80;
203+
}
204+
break;
205+
}
206+
default:
207+
{
208+
// Ignore filtering
209+
printf("Unsupported GB Cam mode: 0x%X\n"
210+
"%02X %02X %02X %02X %02X %02X",
211+
filtering_mode,
212+
CAM_REG[0],CAM_REG[1],CAM_REG[2],
213+
CAM_REG[3],CAM_REG[4],CAM_REG[5]);
214+
break;
215+
}
216+
}
217+
218+
//------------------------------------------------
219+
220+
// Controller handling
221+
// -------------------
222+
223+
int fourcolorsbuffer[GBCAM_W][GBCAM_H]; // buffer after controller matrix
224+
225+
// Convert to Game Boy colors using the controller matrix
226+
for(i = 0; i < GBCAM_W; i++) for(j = 0; j < GBCAM_H; j++)
227+
fourcolorsbuffer[i][j] =
228+
gb_cam_matrix_process(
229+
gb_cam_retina_output_buf[i][j+(GBCAM_SENSOR_EXTRA_LINES/2)],i,j);
230+
231+
// Convert to tiles
232+
u8 finalbuffer[14][16][16]; // final buffer
233+
memset(finalbuffer,0,sizeof(finalbuffer));
234+
for(i = 0; i < GBCAM_W; i++) for(j = 0; j < GBCAM_H; j++)
235+
{
236+
u8 outcolor = 3 - (fourcolorsbuffer[i][j] >> 6);
237+
238+
u8 * tile_base = finalbuffer[j>>3][i>>3];
239+
tile_base = &tile_base[(j&7)*2];
240+
241+
if(outcolor & 1) tile_base[0] |= 1<<(7-(7&i));
242+
if(outcolor & 2) tile_base[1] |= 1<<(7-(7&i));
243+
}
244+
245+
// Copy to cart ram...
246+
memcpy(&(SRAM[0][0x0100]),finalbuffer,sizeof(finalbuffer));
247+
}
248+
249+
//--------------------------------------------------------------------

0 commit comments

Comments
 (0)