ADM3a terminal emulator
[termu] / src / font.c
1 #include <stdio.h>
2 #include <string.h>
3 #define GL_GLEXT_PROTOTYPES
4 #include <GL/gl.h>
5 #include "font.h"
6
7 /* ADM3a 5x7 glyphs, displayed in a 7x9 matrix */
8
9 #define ROM_CHARS       128
10
11 #define TEX_NCOLS       16
12 #define TEX_NROWS       (ROM_CHARS / TEX_NCOLS)
13
14 #define TEX_WIDTH       (TEX_NCOLS * 8)
15 #define TEX_HEIGHT      (TEX_NROWS * 8)
16
17 #define UVWIDTH         (1.0f / (float)TEX_NCOLS)
18 #define UVHEIGHT        (1.0f / (float)TEX_NROWS)
19
20 int fontw, fonth;
21 unsigned int tex_font;
22 extern unsigned char rom_upper[];
23 extern unsigned char rom_lower[];
24
25 struct vertex {
26         float x, y;
27         float u, v;
28 };
29
30 #define VB_NGLYPHS      128
31 #define VB_NVERTS       (VB_NGLYPHS * 4)
32 static struct vertex varr[VB_NVERTS];
33 static int nglyphs, cur_vbo;
34 static unsigned int vbo[2];
35
36
37 static int transform(int c)
38 {
39         if(c >= 0x60) {
40                 return ((~c) & 0x7f) | 0x40;
41         }
42         return c & 0x3f;
43 }
44
45 void text_init(void)
46 {
47         int i, j, k, glyph;
48         unsigned char img[TEX_WIDTH * TEX_HEIGHT];
49         unsigned char *src, *dest = img;
50
51         memset(img, 0, sizeof img);
52
53         for(i=0; i<ROM_CHARS; i++) {
54                 glyph = transform(i + 0x20);
55                 src = rom_upper + glyph * 8;
56                 for(j=0; j<8; j++) {
57                         unsigned char row = (*src++ & 0x1f) << 2;
58                         for(k=0; k<8; k++) {
59                                 dest[k] = (row >> (7 - k)) & 1 ? 0xff : 0;
60                         }
61                         dest += TEX_WIDTH;
62                 }
63
64                 if((i & 0xf) == 0xf) {
65                         dest -= TEX_WIDTH - 8;
66                 } else {
67                         dest = dest + 8 - TEX_WIDTH * 8;
68                 }
69
70         }
71         /*{
72                 FILE *fp = fopen("font.ppm", "wb");
73                 if(fp) {
74                         fprintf(fp, "P5\n%d %d\n255\n", TEX_WIDTH, TEX_HEIGHT);
75                         fwrite(img, 1, TEX_WIDTH * TEX_HEIGHT, fp);
76                         fclose(fp);
77                 }
78         }*/
79
80         glGenTextures(1, &tex_font);
81         glBindTexture(GL_TEXTURE_2D, tex_font);
82         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
83         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
84         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, TEX_WIDTH, TEX_HEIGHT, 0,
85                         GL_LUMINANCE, GL_UNSIGNED_BYTE, img);
86
87         fontw = 7;
88         fonth = 9;
89
90         glGenBuffers(2, vbo);
91         for(i=0; i<2; i++) {
92                 glBindBuffer(GL_ARRAY_BUFFER, vbo[i]);
93                 glBufferData(GL_ARRAY_BUFFER, sizeof varr, 0, GL_STREAM_DRAW);
94         }
95         glBindBuffer(GL_ARRAY_BUFFER, 0);
96 }
97
98 void text_cleanup(void)
99 {
100         glDeleteBuffers(2, vbo);
101         glDeleteTextures(1, &tex_font);
102 }
103
104 void text_begin(void)
105 {
106         nglyphs = 0;
107 }
108
109 void text_end(void)
110 {
111         if(nglyphs <= 0) return;
112
113         glBindTexture(GL_TEXTURE_2D, tex_font);
114         glEnable(GL_TEXTURE_2D);
115
116         glBindBuffer(GL_ARRAY_BUFFER, vbo[cur_vbo]);
117         glBufferSubData(GL_ARRAY_BUFFER, 0, nglyphs * 4 * sizeof *varr, varr);
118
119         glEnableClientState(GL_VERTEX_ARRAY);
120         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
121
122         glVertexPointer(2, GL_FLOAT, sizeof *varr, 0);
123         glTexCoordPointer(2, GL_FLOAT, sizeof *varr, (void*)(2 * sizeof(float)));
124         glBindBuffer(GL_ARRAY_BUFFER, 0);
125
126         glDrawArrays(GL_QUADS, 0, nglyphs * 4);
127
128         glDisableClientState(GL_VERTEX_ARRAY);
129         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
130
131         glDisable(GL_TEXTURE_2D);
132
133         nglyphs = 0;
134         cur_vbo = (cur_vbo + 1) & 1;
135 }
136
137 #define VERT(vert, vx, vy)      ((vert).x = (vx), (vert).y = (vy))
138 #define TEXC(vert, vu, vv)      ((vert).u = (vu), (vert).v = (vv))
139
140 void draw_glyph(int x, int y, int c)
141 {
142         float uoffs, voffs;
143         int col, row;
144         struct vertex *vptr = varr + nglyphs++ * 4;
145
146         if(c < 0x20 || c >= 128) return;
147
148         y = 23 - y;
149
150         VERT(vptr[0], x, y + 1.0 / 9.0);
151         VERT(vptr[1], x + 1, y + 1.0 / 9.0);
152         VERT(vptr[2], x + 1, y + 1);
153         VERT(vptr[3], x, y + 1);
154
155         c -= 0x20;
156         row = c / TEX_NCOLS;
157         col = c % TEX_NCOLS;
158
159         voffs = row * UVHEIGHT;
160         uoffs = col * UVWIDTH;
161
162         TEXC(vptr[0], uoffs, voffs + UVHEIGHT);
163         TEXC(vptr[1], uoffs + 7.0 / 8.0 * UVWIDTH, voffs + UVHEIGHT);
164         TEXC(vptr[2], uoffs + 7.0 / 8.0 * UVWIDTH, voffs);
165         TEXC(vptr[3], uoffs, voffs);
166
167         if(nglyphs >= VB_NGLYPHS) {
168                 text_end();
169         }
170 }