1 /*
2  * libtilemcore - Graphing calculator emulation library
3  *
4  * Copyright (C) 2011 Benjamin Moody
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include "tilem.h"
28 
tilem_lcd_buffer_new()29 TilemLCDBuffer* tilem_lcd_buffer_new()
30 {
31 	return tilem_new0(TilemLCDBuffer, 1);
32 }
33 
tilem_lcd_buffer_free(TilemLCDBuffer * buf)34 void tilem_lcd_buffer_free(TilemLCDBuffer *buf)
35 {
36 	tilem_free(buf->data);
37 	tilem_free(buf->tmpbuf);
38 	tilem_free(buf);
39 }
40 
tilem_lcd_get_frame(TilemCalc * restrict calc,TilemLCDBuffer * restrict buf)41 void tilem_lcd_get_frame(TilemCalc * restrict calc,
42                          TilemLCDBuffer * restrict buf)
43 {
44 	byte * restrict bp;
45 	byte * restrict op;
46 	int dwidth = calc->hw.lcdwidth;
47 	int dheight = calc->hw.lcdheight;
48 	unsigned int size;
49 	int bwidth = ((calc->hw.lcdwidth + 7) / 8);
50 	int i, j;
51 
52 	if (TILEM_UNLIKELY(buf->height != dheight
53 	                   || buf->rowstride != bwidth * 8)) {
54 		/* reallocate data buffer */
55 		tilem_free(buf->data);
56 		buf->data = tilem_new_atomic(byte, dwidth * bwidth * 8);
57 		buf->rowstride = bwidth * 8;
58 		buf->height = dheight;
59 	}
60 
61 	size = bwidth * dheight * sizeof(byte);
62 	if (TILEM_UNLIKELY(buf->tmpbufsize < size)) {
63 		/* reallocate temp buffer */
64 		tilem_free(buf->tmpbuf);
65 		buf->tmpbuf = tilem_malloc_atomic(size);
66 		buf->tmpbufsize = size;
67 	}
68 
69 	buf->width = dwidth;
70 
71 	buf->stamp = calc->z80.lastlcdwrite;
72 
73 	if (!calc->lcd.active || (calc->z80.halted && !calc->poweronhalt)) {
74 		/* screen is turned off */
75 		buf->contrast = 0;
76 		return;
77 	}
78 
79 	buf->contrast = calc->lcd.contrast;
80 
81 	bp = buf->tmpbuf;
82 	op = buf->data;
83 	(*calc->hw.get_lcd)(calc, bp);
84 
85 	for (i = 0; i < bwidth * dheight; i++) {
86 		for (j = 0; j < 8; j++) {
87 			*op = (*bp << j) & 0x80;
88 			op++;
89 		}
90 		bp++;
91 	}
92 }
93 
94 /* Do the same thing as tilem_lcd_get_frame, but output is only 0 and 1 */
tilem_lcd_get_frame1(TilemCalc * restrict calc,TilemLCDBuffer * restrict buf)95 void tilem_lcd_get_frame1(TilemCalc * restrict calc,
96                          TilemLCDBuffer * restrict buf)
97 {
98 	byte * restrict bp;
99 	byte * restrict op;
100 	int dwidth = calc->hw.lcdwidth;
101 	int dheight = calc->hw.lcdheight;
102 	unsigned int size;
103 	int bwidth = ((calc->hw.lcdwidth + 7) / 8);
104 	int i, j;
105 
106 	if (TILEM_UNLIKELY(buf->height != dheight
107 	                   || buf->rowstride != bwidth * 8)) {
108 		/* reallocate data buffer */
109 		tilem_free(buf->data);
110 		buf->data = tilem_new_atomic(byte, dwidth * bwidth * 8);
111 		buf->rowstride = bwidth * 8;
112 		buf->height = dheight;
113 	}
114 
115 	size = bwidth * dheight * sizeof(byte);
116 	if (TILEM_UNLIKELY(buf->tmpbufsize < size)) {
117 		/* reallocate temp buffer */
118 		tilem_free(buf->tmpbuf);
119 		buf->tmpbuf = tilem_malloc_atomic(size);
120 		buf->tmpbufsize = size;
121 	}
122 
123 	buf->width = dwidth;
124 
125 	buf->stamp = calc->z80.lastlcdwrite;
126 
127 	if (!calc->lcd.active || (calc->z80.halted && !calc->poweronhalt)) {
128 		/* screen is turned off */
129 		buf->contrast = 0;
130 		return;
131 	}
132 
133 	buf->contrast = calc->lcd.contrast;
134 
135 	bp = buf->tmpbuf;
136 	op = buf->data;
137 	(*calc->hw.get_lcd)(calc, bp);
138 
139 	for (i = 0; i < bwidth * dheight; i++) {
140 		for (j = 0; j < 8; j++) {
141 			*op = (*bp << j) & 0x80;
142 			if(*op != 0)
143 				*op = 1;
144 			op++;
145 		}
146 		bp++;
147 	}
148 }
149