-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcharsl.h
253 lines (227 loc) · 5 KB
/
charsl.h
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*********************\
** <charsl.h> **
** a shadertoy style **
** shader sandbox **
\*********************/
#ifndef CHARSL_H
#define CHARSL_H
// TODO:
//
// ???????????? Maybe ????????????????
//
// void mainImage();
// void bufferA();
// void bufferB();
// void bufferC();
// void bufferD();
//
// WINDOW *main
// WINDOW *bufferA
// WINDOW *bufferB
// WINDOW *bufferC
// WINDOW *bufferD
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <curses.h>
// Enums
enum WRAP_OPTS {
WRAP_NONE,
WRAP_X,
WRAP_Y,
WRAP_BOTH,
WRAP_STRETCH
};
// Type definitions
typedef struct
{
float x;
float y;
} vec2;
typedef struct
{
int x;
int y;
} ivec2;
typedef struct
{
int width;
int height;
WINDOW *buffer;
enum WRAP_OPTS wrap; // TODO: implement texture wrapping
} Texture2D;
// Global variables
int FRAMECOUNT; // number of frames since start
double TIME; // time since start
char CHAR; // char at position
vec2 UV; // [0.0..1.0] uv coords of the character
ivec2 FRAGCOORD; // integer offset from the top-left of the window
ivec2 RESOLUTION; // resolution of the screen in chars
Texture2D TEXTURE; // Screen Texture
// ---------------------------
// Method definitions
// ---------------------------
// Methods to override
void setup(void);
void fragment(void);
// void cleanup(void); // Maybe this won't be needed
// Math functions
float fract(float a);
// Texture sampling
char texture(Texture2D texture, vec2 uv); // returns char at nearest fragCoord
char texelFetch(Texture2D texture, ivec2 fragCoord); // returns char at fragCoord
// Texture loading
Texture2D loadTexture(const char *fileName);
void unloadTexture(Texture2D texture); // TODO
// Texture configuration
void setTextureWrap(Texture2D texture, int wrap); // TODO: add wrap field to Texture2D struct
//=-------------=//
// Main function //
//=-------------=//
int main(void)
{
struct timespec START, CURRENT;
clock_gettime(CLOCK_REALTIME, &START);
// setup curses
initscr();
TEXTURE.width = COLS;
TEXTURE.height = LINES;
TEXTURE.buffer = curscr;
cbreak(); // make input immediate
noecho(); // don't echo keypresses
curs_set(0); // make cursor invisible
timeout(0); // make getch non-blocking
clear();
FRAMECOUNT = 0;
RESOLUTION.x = COLS;
RESOLUTION.y = LINES;
#ifdef RUN_SETUP
setup();
#endif
// run loop
while (getch() != 'q')
{ // quit when 'q' key is pressed; maybe ESC?
clock_gettime(CLOCK_REALTIME, &CURRENT);
TIME = (CURRENT.tv_sec - START.tv_sec) + (CURRENT.tv_nsec - START.tv_nsec) * 1e-9;
for (int y = 0; y < LINES; y++)
{
for (int x = 0; x < COLS; x++)
{
CHAR = (char)(mvinch(y, x) & A_CHARTEXT);
FRAGCOORD.x = x;
FRAGCOORD.y = y;
UV.x = (float)x / (float)COLS;
UV.y = (float)y / (float)LINES;
fragment();
mvaddch(y, x, CHAR);
}
}
FRAMECOUNT++;
refresh();
napms(50); // sleep for 50 ms
}
// cleanup curses
endwin();
return 0;
}
float fract(float a)
{
// return the fractional part of a
return a - (int)a;
}
// TODO: add sampling flags for wrapping, blank, smear
char texture(Texture2D texture, vec2 uv)
{
// return the character nearest the uv point
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)
{
return ' '; // should probably return something more useful
}
return (char)(mvwinch(texture.buffer, (int)(uv.y * texture.height), (int)(uv.x * texture.width)) & A_CHARTEXT);
}
char texelFetch(Texture2D texture, ivec2 fragCoord)
{
// check that fragCoord is in texture
if (fragCoord.x < 0 || fragCoord.x >= texture.width || fragCoord.y < 0 || fragCoord.y >= texture.height)
{
return ' ';
}
// return the character at the fragCoord
return (char)(mvwinch(texture.buffer, fragCoord.y, fragCoord.x) & A_CHARTEXT);
}
// TODO: return as a pointer
Texture2D loadTexture(const char *filename)
{
// read file into buffer
char *buffer;
FILE *fh = fopen(filename, "rb");
long s;
if (fh != NULL)
{
fseek(fh, 0, SEEK_END);
s = ftell(fh);
rewind(fh);
buffer = malloc(s);
if (buffer != NULL)
{
fread(buffer, s, 1, fh);
fclose(fh);
fh = NULL;
}
if (fh != NULL)
{
fclose(fh);
fh = NULL;
}
}
// get width and height of texture
int width = 0;
int height = 0;
int cur_width = 0;
for (int i = 0; i < s; i++)
{
if (buffer[i] == '\n')
{
if (cur_width > width)
{
width = cur_width;
}
height++;
cur_width = 0;
}
else if (buffer[i] != '\r')
{
cur_width++;
}
}
// create Texture2D struct
Texture2D newTexture;
// return pointer to Texture2D
newTexture.width = width;
newTexture.height = height;
// create curses pad
newTexture.buffer = newpad(newTexture.height, newTexture.width); // WINDOW *newpad(int lines, int cols);
// copy buffer to pad
int x = 0, y = 0;
for (int j = 0; j < s; j++)
{
if (buffer[j] == '\n')
{
y++;
x = 0;
}
else if (buffer[j] != '\r')
{
mvwaddch(newTexture.buffer, y, x, buffer[j]);
x++;
}
}
// free file buffer
free(buffer);
return newTexture;
}
void unloadTexture(Texture2D texture)
{
// free texture data
}
#endif // ifndef CHARSL_H