Add AI to the pong plugin, to allow single-player operation.
[kugel-rb.git] / apps / plugins / ppmviewer.c
blobe138692aef9c30c0eca214f899ab5bf0ba6fdc40
1 /*****************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// __ \_/ ___\| |/ /| __ \ / __ \ \/ /
5 * Jukebox | | ( (__) ) \___| ( | \_\ ( (__) ) (
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 Alexander Papst
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "lib/pluginlib_bmp.h"
25 /* Magic constants. */
26 #define PPM_MAGIC1 'P'
27 #define PPM_MAGIC2 '3'
28 #define RPPM_MAGIC2 '6'
29 #define PPM_FORMAT (PPM_MAGIC1 * 256 + PPM_MAGIC2)
30 #define RPPM_FORMAT (PPM_MAGIC1 * 256 + RPPM_MAGIC2)
32 #define PPM_OVERALLMAXVAL 65535
33 #define PPM_MAXSIZE (300*1024)/sizeof(fb_data)
35 #define ppm_error(...) rb->splashf(HZ*2, __VA_ARGS__ )
37 static fb_data *buffer, *lcd_buf;
39 int ppm_read_magic_number(int fd)
41 char i1, i2;
42 if(!rb->read(fd, &i1, 1) || !rb->read(fd, &i2, 1))
44 ppm_error( "Error reading magic number from ppm image stream. "\
45 "Most often, this means your input file is empty." );
46 return PLUGIN_ERROR;
48 return i1 * 256 + i2;
51 char ppm_getc(int fd)
53 char ch;
55 if (!rb->read(fd, &ch, 1)) {
56 ppm_error("EOF. Read error reading a byte");
57 return PLUGIN_ERROR;
60 if (ch == '#') {
61 do {
62 if (!rb->read(fd, &ch, 1)) {
63 ppm_error("EOF. Read error reading a byte");
64 return PLUGIN_ERROR;
66 } while (ch != '\n' && ch != '\r');
68 return ch;
71 int ppm_getuint(int fd)
73 char ch;
74 int i;
75 int digitVal;
77 do {
78 ch = ppm_getc(fd);
79 } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
81 if (ch < '0' || ch > '9') {
82 ppm_error("Junk (%c) in file where an integer should be.", ch);
83 return PLUGIN_ERROR;
86 i = 0;
88 do {
89 digitVal = ch - '0';
91 if (i > INT_MAX/10 - digitVal) {
92 ppm_error("ASCII decimal integer in file is "\
93 "too large to be processed.");
94 return PLUGIN_ERROR;
97 i = i * 10 + digitVal;
98 ch = ppm_getc(fd);
100 } while (ch >= '0' && ch <= '9');
102 return i;
105 int ppm_getrawbyte(int fd)
107 unsigned char by;
109 if (!rb->read(fd, &by, 1)) {
110 ppm_error("EOF. Read error while reading a one-byte sample.");
111 return PLUGIN_ERROR;
114 return (int)by;
117 int ppm_getrawsample(int fd, int const maxval)
119 if (maxval < 256) {
120 /* The sample is just one byte. Read it. */
121 return(ppm_getrawbyte(fd));
122 } else {
123 /* The sample is two bytes. Read both. */
124 unsigned char byte_pair[2];
126 if (!rb->read(fd, byte_pair, 2)) {
127 ppm_error("EOF. Read error while reading a long sample.");
128 return PLUGIN_ERROR;
130 return((byte_pair[0]<<8) | byte_pair[1]);
134 int read_ppm_init_rest(int fd,
135 int * const cols,
136 int * const rows,
137 int * const maxval)
139 /* Read size. */
140 *cols = ppm_getuint(fd);
141 *rows = ppm_getuint(fd);
143 if ((long unsigned int)(*cols * *rows) > PPM_MAXSIZE) {
144 ppm_error("Imagesize (%ld pixels) is too large. "\
145 "The maximum allowed is %ld.",
146 (long unsigned int)(*cols * *rows),
147 (long unsigned int)PPM_MAXSIZE);
148 return PLUGIN_ERROR;
151 /* Read maxval. */
152 *maxval = ppm_getuint(fd);
154 if (*maxval > PPM_OVERALLMAXVAL) {
155 ppm_error("maxval of input image (%u) is too large. "\
156 "The maximum allowed by the PPM is %u.",
157 *maxval, PPM_OVERALLMAXVAL);
158 return PLUGIN_ERROR;
160 if (*maxval == 0) {
161 ppm_error("maxval of input image is zero.");
162 return PLUGIN_ERROR;
164 return 1;
167 void read_ppm_init(int fd,
168 int * const cols,
169 int * const rows,
170 int * const maxval,
171 int * const format)
173 /* Check magic number. */
174 *format = ppm_read_magic_number( fd );
176 if (*format == PLUGIN_ERROR) return;
177 switch (*format) {
178 case PPM_FORMAT:
179 case RPPM_FORMAT:
180 if(read_ppm_init_rest(fd, cols, rows, maxval) == PLUGIN_ERROR) {
181 *format = PLUGIN_ERROR;
183 break;
185 default:
186 ppm_error( "Bad magic number - not a ppm or rppm file." );
187 *format = PLUGIN_ERROR;
191 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
192 #define BUFADDR(x, y, width, height) ( buffer + height*(x) + (y))
193 #else
194 #define BUFADDR(x, y, width, height) ( buffer + width*(y) + (x))
195 #endif
197 int read_ppm_row(int fd,
198 int const row,
199 int const cols,
200 int const rows,
201 int const maxval,
202 int const format)
204 #if !(defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE)
205 (void) rows;
206 #endif
208 int col;
209 int r, g, b;
210 switch (format) {
211 case PPM_FORMAT:
212 for (col = 0; col < cols; ++col) {
213 r = ppm_getuint(fd);
214 g = ppm_getuint(fd);
215 b = ppm_getuint(fd);
217 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
218 b == PLUGIN_ERROR)
220 return PLUGIN_ERROR;
222 *BUFADDR(col, row, cols, rows) = LCD_RGBPACK(
223 (255 / maxval) * r,
224 (255 / maxval) * g,
225 (255 / maxval) * b);
227 break;
229 case RPPM_FORMAT:
230 for (col = 0; col < cols; ++col) {
231 r = ppm_getrawsample(fd, maxval);
232 g = ppm_getrawsample(fd, maxval);
233 b = ppm_getrawsample(fd, maxval);
235 if (r == PLUGIN_ERROR || g == PLUGIN_ERROR ||
236 b == PLUGIN_ERROR)
238 return PLUGIN_ERROR;
240 *BUFADDR(col, row, cols, rows) = LCD_RGBPACK(
241 (255 / maxval) * r,
242 (255 / maxval) * g,
243 (255 / maxval) * b);
245 break;
247 default:
248 ppm_error("What?!");
249 return PLUGIN_ERROR;
251 return 1;
254 int read_ppm(int fd,
255 int * const cols,
256 int * const rows,
257 int * const maxval)
259 int row;
260 int format;
262 read_ppm_init(fd, cols, rows, maxval, &format);
264 if(format == PLUGIN_ERROR) {
265 return PLUGIN_ERROR;
268 for (row = 0; row < *rows; ++row) {
269 if( read_ppm_row(fd, row, *cols, *rows, *maxval, format) == PLUGIN_ERROR) {
270 return PLUGIN_ERROR;
273 return 1;
276 /* this is the plugin entry point */
277 enum plugin_status plugin_start(const void* parameter)
279 static char filename[MAX_PATH];
280 int fd;
282 int cols;
283 int rows;
284 int maxval;
286 int result;
288 struct bitmap small_bitmap, orig_bitmap;
290 if(!parameter) return PLUGIN_ERROR;
292 size_t buffer_size;
293 char *audiobuf = rb->plugin_get_buffer(&buffer_size);
294 if (buffer_size < PPM_MAXSIZE + LCD_WIDTH * LCD_HEIGHT + 1)
296 /* steal from audiobuffer if plugin buffer is too small */
297 audiobuf = rb->plugin_get_audio_buffer(&buffer_size);
299 if (buffer_size < PPM_MAXSIZE + LCD_WIDTH * LCD_HEIGHT + 1)
301 rb->splash(HZ, "Not enough memory");
302 return PLUGIN_ERROR;
306 /* align on 16 bits */
307 audiobuf = (char *)(((uintptr_t)audiobuf + 1) & ~1);
308 buffer = (fb_data *)audiobuf;
309 lcd_buf = (fb_data*) (audiobuf + PPM_MAXSIZE);
311 rb->strcpy(filename, parameter);
313 fd = rb->open(filename, O_RDONLY);
314 if (fd < 0)
316 ppm_error("Couldnt open file: %s, %d", filename, fd);
317 return PLUGIN_ERROR;
320 result = read_ppm(fd, &cols, &rows, &maxval);
322 rb->close(fd);
323 if(result == PLUGIN_ERROR) return PLUGIN_ERROR;
325 orig_bitmap.width = cols;
326 orig_bitmap.height = rows;
327 orig_bitmap.data = (char*)buffer;
329 if (cols > LCD_WIDTH || rows > LCD_HEIGHT)
331 if (cols > LCD_WIDTH) {
332 small_bitmap.width = LCD_WIDTH;
333 small_bitmap.height =
334 (int)(((float)LCD_WIDTH / (float)cols) * (float)rows);
336 } else { /* rows > LCD_HEIGHT */
338 small_bitmap.width =
339 (int)(((float)LCD_HEIGHT / (float)rows) * (float)cols);
340 small_bitmap.height = LCD_HEIGHT;
342 small_bitmap.data = (char*)lcd_buf;
344 smooth_resize_bitmap( &orig_bitmap, &small_bitmap );
346 rb->lcd_bitmap((fb_data*)small_bitmap.data, 0, 0,
347 small_bitmap.width, small_bitmap.height);
348 } else {
349 rb->lcd_bitmap((fb_data*)orig_bitmap.data, 0, 0, cols, rows);
351 rb->lcd_update();
352 rb->button_get(true);
354 return PLUGIN_OK;