diff options
author | pk33 <pk33@pk33.space> | 2024-11-14 15:06:07 +0100 |
---|---|---|
committer | pk33 <pk33@pk33.space> | 2024-11-14 15:06:07 +0100 |
commit | ed2a4bc4400c38ecd11baccac5db328b797b5d68 (patch) | |
tree | b703749d0639f933edca4c3a78209159aa735c25 /src | |
parent | 5a54774474f43ae29716751d6415563a59b92c7d (diff) | |
download | engine33-master.tar.gz |
Diffstat (limited to 'src')
-rw-r--r-- | src/clock33.c | 4 | ||||
-rw-r--r-- | src/display33.c | 10 | ||||
-rw-r--r-- | src/graphics33.c | 214 | ||||
-rw-r--r-- | src/logger33.c | 1 | ||||
-rw-r--r-- | src/main.c | 44 | ||||
-rw-r--r-- | src/math33.c | 175 | ||||
-rw-r--r-- | src/scene33.c | 45 | ||||
-rw-r--r-- | src/strings33.c | 6 |
8 files changed, 480 insertions, 19 deletions
diff --git a/src/clock33.c b/src/clock33.c index 2fe0d3c..c9edfaf 100644 --- a/src/clock33.c +++ b/src/clock33.c @@ -3,14 +3,14 @@ #include "clock33.h" -Size clock_get_us( void ) +Size clock33_get_us( void ) { static struct timeval tv; gettimeofday( &tv, 0 ); return (tv.tv_sec * 1000000) + tv.tv_usec; } -f64 clock_get_s_hires( void ) +f64 clock33_get_s_hires( void ) { static struct timeval tv; gettimeofday( &tv, 0 ); diff --git a/src/display33.c b/src/display33.c index 928d4e0..c38825a 100644 --- a/src/display33.c +++ b/src/display33.c @@ -130,15 +130,10 @@ Error display33_init( void ) } - __display.surface.w = __display.mode.hdisplay; - __display.surface.h = __display.mode.vdisplay; __display.fb.size = (Size)drmData.drmCreateDumb[0].size; __display.surface.data = __display.fb.map[0]; __display.active = E33_TRUE; - free( drmData.drmRes_fbs ); - free( drmData.drmRes_encs ); - free( drmData.drmRes_conns ); return E33_EXIT_SUCCESS; } @@ -186,6 +181,9 @@ void display33_term( void ) LOGW( "Failed to close graphics device." ); } + free( drmData.drmRes_fbs ); + free( drmData.drmRes_encs ); + free( drmData.drmRes_conns ); free( drmData.drmRes_crtcs ); if( ioctl(__display.ttyFd, VT_SETMODE, &vtModeOld) < 0 ) { @@ -333,6 +331,8 @@ static Size _get_drm_connector( void ) mode->hdisplay += 10; } + __display.surface.w = mode->hdisplay; + __display.surface.h = mode->vdisplay; __display.mode = *mode; return E33_EXIT_SUCCESS; } diff --git a/src/graphics33.c b/src/graphics33.c new file mode 100644 index 0000000..686aa86 --- /dev/null +++ b/src/graphics33.c @@ -0,0 +1,214 @@ +#include "math.h" + +#include "options33.h" +#include "types33.h" +#include "display33.h" +#include "scene33.h" +#include "strings33.h" +#include "logger33.h" + + +#define _FOV_HALF (0.78539816339744830962/2.0) +#define _NEAR 1.0 +#define _FAR 24.0 + + +static Mat4 _projectionMatrix = {0,}; +static Mat4 _viewMatrix; +static Mat4 _worldMatrix; +static f64 _preXformedModelVertices[ E33_VERTICES_PER_MODEL_MAX ][4]; + + +static void _draw_line( Vec2 v0, Vec2 v1, u32 colour ); + + +Error graphics33_init( void ) +{ + f64 ar, cot; + f64 displayW = (f64)__display.surface.w; + f64 displayH = (f64)__display.surface.h; + + ar = displayW / displayH; + cot = 1.0 / tan( _FOV_HALF ); + + _projectionMatrix[ 0] = cot / ar; + _projectionMatrix[ 5] = cot; + _projectionMatrix[10] = _FAR / (_FAR - _NEAR); + _projectionMatrix[11] = 1.0; + _projectionMatrix[14] = -_NEAR * (_FAR / (_FAR - _NEAR)); + + + return E33_EXIT_SUCCESS; +} + +Error graphics33_term( void ) +{ + return E33_EXIT_SUCCESS; +} + +void graphics33_update( void ) +{ + math33_create_view_matrix(__scene.camera.t, __scene.camera.r, _viewMatrix ); + VxP( _viewMatrix, _projectionMatrix ); +} + +void graphics33_decompose_scene( void ) +{ + extern Scene33 __scene; + + Size i, j; + Size displayW = __display.surface.w; + Size displayH = __display.surface.h; + Model33 *model = &__scene.cube; + + ModelEdge33 *medges = model->medges; + Size *sedges = model->sedges; + + Size modelVertexCount = model->vertexCount; + Size modelSurfaceCount = model->surfaceCount; + + + math33_create_world_matrix( model->t, model->r, model->s, _worldMatrix ); + MxM4( _worldMatrix, _viewMatrix ); + + #define pV _preXformedModelVertices + for( i = 0; i < modelVertexCount; ++i ) { + f64 iw; + + V4xMt( pV[i], model->vertices[i], _worldMatrix ); + + iw = 1.0 / pV[i][3]; + pV[i][0] = ( ((pV[i][0] * iw) + 1.0) * 0.5 ); + pV[i][1] = ( ((pV[i][1] * iw) + 1.0) * 0.5 ); + } + + for( i = 0; i < modelSurfaceCount; ++i ) + { + Vec4 v[16]; + Size a[2], b[2], c[2]; + Boolean needsClippage = 0; + + a[0] = medges[ sedges[i*3 ] ].vertices[0]; + a[1] = medges[ sedges[i*3 ] ].vertices[1]; + b[0] = medges[ sedges[i*3+1] ].vertices[0]; + b[1] = medges[ sedges[i*3+1] ].vertices[1]; + c[0] = medges[ sedges[i*3+2] ].vertices[0]; + c[1] = medges[ sedges[i*3+2] ].vertices[1]; + + if( a[0] == b[0] ) + { + Size tmp = a[0]; + a[0] = a[1]; + a[1] = tmp; + } + else if( a[1] == b[1] ) + { + Size tmp = b[0]; + b[0] = b[1]; + b[1] = tmp; + } + + if( c[1] != a[0] ) { + Size tmp = c[0]; + c[0] = c[1]; + c[1] = tmp; + } + + if( ( (pV[a[0]][0] - pV[b[0]][0]) * (pV[c[0]][1] - pV[b[0]][1]) - + (pV[a[0]][1] - pV[b[0]][1]) * (pV[c[0]][0] - pV[b[0]][0]) ) <= 0 ) { + continue; + } + + v[0][3] = pV[a[0]][3]; + if( v[0][3] <= _NEAR ) continue; + if( v[0][3] > _FAR ) continue; + v[0][0] = pV[a[0]][0]; + v[0][1] = pV[a[0]][1]; + v[0][2] = pV[a[0]][2]; + + v[1][3] = pV[b[0]][3]; + if( v[1][3] <= _NEAR ) continue; + if( v[1][3] > _FAR ) continue; + v[1][0] = pV[b[0]][0]; + v[1][1] = pV[b[0]][1]; + v[1][2] = pV[b[0]][2]; + + v[2][3] = pV[c[0]][3]; + if( v[2][3] <= _NEAR ) continue; + if( v[2][3] > _FAR ) continue; + v[2][0] = pV[c[0]][0]; + v[2][1] = pV[c[0]][1]; + v[2][2] = pV[c[0]][2]; + + v[0][0] *= (f64)(displayW - 1); + v[0][1] *= (f64)(displayH - 1); + v[1][0] *= (f64)(displayW - 1); + v[1][1] *= (f64)(displayH - 1); + v[2][0] *= (f64)(displayW - 1); + v[2][1] *= (f64)(displayH - 1); + + _draw_line( v[0], v[1], CYAN ); + _draw_line( v[1], v[2], CYAN ); + _draw_line( v[2], v[0], CYAN ); + } + #undef pV +} + + +static void _draw_line( Vec2 v0, Vec2 v1, u32 colour ) +{ + u32 *dest = __display.surface.data; + Size w = __display.surface.w; + Size h = __display.surface.h; + Size x0 = (Size)(v0[0] + 0.5 ); + Size y0 = (Size)(v0[1] + 0.5 ); + Size x1 = (Size)(v1[0] + 0.5 ); + Size y1 = (Size)(v1[1] + 0.5 ); + + Size sx, sy; + Size dx, dy, error; + + + dx = (x1 - x0); + if( dx < 0 ) { dx = -dx; } + sx = -1; if( x0 < x1 ) sx = 1; + + dy = -(y1 - y0); + if( dy > 0 ) { dy = -dy; } + sy = -1; if( y0 < y1 ) sy = 1; + + error = dx + dy; + + while( 1 ) + { + Size e2; + + dest[ x0 + y0 * w ] = colour; + + if( (x0 == x1) && (y0 == y1) ) { + break; + } + + e2 = error << 1; + + if( e2 >= dy ) + { + if( x0 == x1 ) { + break; + } + + error += dy; + x0 += sx; + } + + if( e2 <= dx ) + { + if( y0 == y1 ) { + break; + } + + error += dx; + y0 += sy; + } + } +} diff --git a/src/logger33.c b/src/logger33.c index d9b0d8d..b15ef4c 100644 --- a/src/logger33.c +++ b/src/logger33.c @@ -1,5 +1,6 @@ #include <linux/vt.h> +#include "sys/stat.h" #include "fcntl.h" #include "stdarg.h" #include "errno.h" @@ -7,6 +7,7 @@ #include "strings33.h" #include "input33.h" #include "ui33.h" +#include "scene33.h" static void _term_sighandler( int sig ); @@ -20,7 +21,7 @@ int main(int argc, char *argv[]) if( e33_set_signal( SIGINT, _term_sighandler ) == -1 ) { LOGW( "SIGINT not handled"); } if( e33_set_signal( SIGTERM, _term_sighandler ) == -1 ) { LOGW( "SIGTERM not handled"); } - timeOld = clock_get_us(); + timeOld = clock33_get_us(); time = 0; fps = 0; FPS = 0; @@ -37,6 +38,15 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } + if( scene33_init() ) { + return EXIT_FAILURE; + } + + if( graphics33_init() ) { + return EXIT_FAILURE; + } + + while(1) { display33_vtswitcher_poll(1); @@ -46,9 +56,21 @@ int main(int argc, char *argv[]) { input33_poll(); - QPRINTF( 5, 5, "fps: %d", FPS-1 ); - if( KEYDOWN(KEY_K) ) { ui33_add_message("Pressed '%c'", 'K'); } + if( KEYDOWN(KEY_Q) ) { break; } + + if( KEYDOWN(KEY_W) ) { __scene.camera.t[2] += 0.1; } + else if( KEYDOWN(KEY_S) ) { __scene.camera.t[2] -= 0.1; } + if( KEYDOWN(KEY_A) ) { __scene.camera.t[0] -= 0.1; } + else if( KEYDOWN(KEY_D) ) { __scene.camera.t[0] += 0.1; } + if( KEYDOWN(KEY_SPACE) ) { __scene.camera.t[1] -= 0.1; } + else if( KEYDOWN(KEY_LEFTCTRL) ) { __scene.camera.t[1] += 0.1; } + + if( KEYDOWN(KEY_LEFT) ) { __scene.cube.r[1] -= 0.04; } + else if( KEYDOWN(KEY_RIGHT) ) { __scene.cube.r[1] += 0.04; } + if( KEYDOWN(KEY_UP) ) { __scene.cube.r[0] -= 0.04; } + else if( KEYDOWN(KEY_DOWN) ) { __scene.cube.r[0] += 0.04; } + if( MOUSEX ) { __mouse.x += MOUSEX; @@ -57,24 +79,26 @@ int main(int argc, char *argv[]) __mouse.y += MOUSEY; } - - if( __mouse.x < 0 ) __mouse.x = 0; if( __mouse.y < 0 ) __mouse.y = 0; if( __mouse.x >= __display.surface.w ) __mouse.x = __display.surface.w-1; if( __mouse.y >= __display.surface.h ) __mouse.y = __display.surface.h-1; - ui33_draw_mouse(); + graphics33_update(); + + graphics33_decompose_scene(); + QPRINTF( 5, 5, "fps: %d", FPS-1 ); QPRINTF( 100, 5, "M: x(%d), y(%d)", __mouse.x, __mouse.y ); + ui33_draw_mouse(); + ui33_draw_messages(); - ui33_draw_messages(); display33_flip(); } - time += clock_get_us() - timeOld; - timeOld = clock_get_us(); + time += clock33_get_us() - timeOld; + timeOld = clock33_get_us(); if(time >= 1000000) { @@ -89,6 +113,8 @@ int main(int argc, char *argv[]) display33_term(); logger33_term(); input33_term(); + graphics33_term(); + scene33_term(); return EXIT_SUCCESS; diff --git a/src/math33.c b/src/math33.c new file mode 100644 index 0000000..24f8dd9 --- /dev/null +++ b/src/math33.c @@ -0,0 +1,175 @@ +#include "math33.h" + + +void M4I( Mat4 m ) +{ + m[0] = 1.0; m[1] = 0; m[2] = 0; m[3] = 0; + m[4] = 0; m[5] = 1.0; m[6] = 0; m[7] = 0; + m[8] = 0; m[9] = 0; m[10] = 1.0; m[11] = 0; + m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1.0; +} + +void V4xMt( Vec4 dst, Vec4 v, Mat4 m ) +{ + dst[0] = (v[0] * m[0]) + (v[1] * m[4]) + (v[2] * m[8]) + (v[3] * m[12]); + dst[1] = (v[0] * m[1]) + (v[1] * m[5]) + (v[2] * m[9]) + (v[3] * m[13]); + dst[2] = (v[0] * m[2]) + (v[1] * m[6]) + (v[2] * m[10]) + (v[3] * m[14]); + dst[3] = (v[0] * m[3]) + (v[1] * m[7]) + (v[2] * m[11]) + (v[3] * m[15]); +} + +void MxM4( Mat4 a, Mat4 b ) +{ + Mat4 t = { + a[0], a[1], a[2], a[3], + a[4], a[5], a[6], a[7], + a[8], a[9], a[10], a[11], + a[12], a[13], a[14], a[15] + }; + + a[ 0] = (t[ 0] * b[ 0]) + (t[ 1] * b[ 4]) + (t[ 2] * b[ 8]) + (t[ 3] * b[12]); + a[ 1] = (t[ 0] * b[ 1]) + (t[ 1] * b[ 5]) + (t[ 2] * b[ 9]) + (t[ 3] * b[13]); + a[ 2] = (t[ 0] * b[ 2]) + (t[ 1] * b[ 6]) + (t[ 2] * b[10]) + (t[ 3] * b[14]); + a[ 3] = (t[ 0] * b[ 3]) + (t[ 1] * b[ 7]) + (t[ 2] * b[11]) + (t[ 3] * b[15]); + + a[ 4] = (t[ 4] * b[ 0]) + (t[ 5] * b[ 4]) + (t[ 6] * b[ 8]) + (t[ 7] * b[12]); + a[ 5] = (t[ 4] * b[ 1]) + (t[ 5] * b[ 5]) + (t[ 6] * b[ 9]) + (t[ 7] * b[13]); + a[ 6] = (t[ 4] * b[ 2]) + (t[ 5] * b[ 6]) + (t[ 6] * b[10]) + (t[ 7] * b[14]); + a[ 7] = (t[ 4] * b[ 3]) + (t[ 5] * b[ 7]) + (t[ 6] * b[11]) + (t[ 7] * b[15]); + + a[ 8] = (t[ 8] * b[ 0]) + (t[ 9] * b[ 4]) + (t[10] * b[ 8]) + (t[11] * b[12]); + a[ 9] = (t[ 8] * b[ 1]) + (t[ 9] * b[ 5]) + (t[10] * b[ 9]) + (t[11] * b[13]); + a[10] = (t[ 8] * b[ 2]) + (t[ 9] * b[ 6]) + (t[10] * b[10]) + (t[11] * b[14]); + a[11] = (t[ 8] * b[ 3]) + (t[ 9] * b[ 7]) + (t[10] * b[11]) + (t[11] * b[15]); + + a[12] = (t[12] * b[ 0]) + (t[13] * b[ 4]) + (t[14] * b[ 8]) + (t[15] * b[12]); + a[13] = (t[12] * b[ 1]) + (t[13] * b[ 5]) + (t[14] * b[ 9]) + (t[15] * b[13]); + a[14] = (t[12] * b[ 2]) + (t[13] * b[ 6]) + (t[14] * b[10]) + (t[15] * b[14]); + a[15] = (t[12] * b[ 3]) + (t[13] * b[ 7]) + (t[14] * b[11]) + (t[15] * b[15]); +} + +void VxP( Mat4 v, Mat4 p ) +{ + Mat4 t = { + v[0], v[1], v[2], v[3], + v[4], v[5], v[6], v[7], + v[8], v[9], v[10], v[11], + v[12], v[13], v[14], v[15] }; + + v[ 0] = t[ 0] * p[ 0]; + v[ 1] = t[ 1] * p[ 5]; + v[ 2] = t[ 2] * p[10] + t[ 3] * p[14]; + v[ 3] = t[ 2]; + + v[ 4] = t[ 4] * p[ 0]; + v[ 5] = t[ 5] * p[ 5]; + v[ 6] = t[ 6] * p[10] + t[ 7] * p[14]; + v[ 7] = t[ 6]; + + v[ 8] = t[ 8] * p[ 0]; + v[ 9] = t[ 9] * p[ 5]; + v[10] = t[10] * p[10] + t[11] * p[14]; + v[11] = t[10]; + + v[12] = t[12] * p[ 0]; + v[13] = t[13] * p[ 5]; + v[14] = t[14] * p[10] + t[15] * p[14]; + v[15] = t[14]; +} + +void math33_create_translation_matrix( f64 x, f64 y, f64 z, Mat4 m ) +{ + m[0] = 1.0; m[1] = 0; m[2] = 0; m[3] = 0; + m[4] = 0; m[5] = 1.0; m[6] = 0; m[7] = 0; + m[8] = 0; m[9] = 0; m[10] = 1.0; m[11] = 0; + m[12] = x; m[13] = y; m[14] = z; m[15] = 1.0; +} + +void math33_create_view_rotation_matrix( f64 x, f64 y, Mat4 m ) +{ + f64 sx, sy, cx, cy; + + sx = sin(x); + sy = sin(y); + cx = cos(x); + cy = cos(y); + + Mat4 Rx = { + 1.0, 0, 0, 0, + 0, cx, sx, 0, + 0, -sx, cx, 0, + 0, 0, 0, 1.0 + }; + + m[ 0] = cy; m[ 1] = 0; m[ 2] = -sy; m[ 3] = 0; + m[ 4] = 0; m[ 5] = 1.0; m[ 6] = 0; m[ 7] = 0; + m[ 8] = sy; m[ 9] = 0; m[10] = cy; m[11] = 0; + m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1.0; + + MxM4(m, Rx); +} + +void math33_create_view_matrix( Vec3 t, Vec3 r, Mat4 m ) +{ + Mat4 rot; + + math33_create_translation_matrix(-t[0], -t[1], -t[2], m); + math33_create_view_rotation_matrix(r[0], r[1], rot); + MxM4(m, rot); +} + +void math33_create_rotation_matrix( f64 x, f64 y, f64 z, Mat4 m ) +{ + f64 sx, sy, sz, cx, cy, cz; + + sx = sin(x); + sy = sin(y); + sz = sin(z); + cx = cos(x); + cy = cos(y); + cz = cos(z); + + m[ 0] = 1.0; m[ 1] = 0; m[ 2] = 0; m[ 3] = 0; + m[ 4] = 0; m[ 5] = cx; m[ 6] = sx; m[ 7] = 0; + m[ 8] = 0; m[ 9] = -sx; m[10] = cx; m[11] = 0; + m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1.0; + + Mat4 Ry = { + cy, 0, sy, 0, + 0, 1.0, 0, 0, + -sy, 0, cy, 0, + 0, 0, 0, 1.0 + }; + + Mat4 Rz = { + cz, -sz, 0, 0, + sz, cz, 0, 0, + 0, 0, 1.0, 0, + 0, 0, 0, 1.0 + }; + + MxM4(m, Ry); + MxM4(m, Rz); +} + +void math33_create_scale_matrix( f64 x, f64 y, f64 z, Mat4 m ) +{ + m[0] = x; m[1] = 0; m[2] = 0; m[3] = 0; + m[4] = 0; m[5] = y; m[6] = 0; m[7] = 0; + m[8] = 0; m[9] = 0; m[10] = z; m[11] = 0; + m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1.0; +} + +#include "strings33.h" + +void math33_create_world_matrix( Vec3 t, Vec3 r, Vec3 s, Mat4 m ) +{ + Mat4 rot; + + + math33_create_scale_matrix(s[0], s[1], s[2], m); + math33_create_rotation_matrix(r[0], r[1], r[2], rot); + MxM4(m, rot); + math33_create_translation_matrix(t[0], t[1], t[2], rot); + MxM4(m, rot); +} + diff --git a/src/scene33.c b/src/scene33.c new file mode 100644 index 0000000..00bd177 --- /dev/null +++ b/src/scene33.c @@ -0,0 +1,45 @@ +#include "logger33.h" +#include "scene33.h" +#include "strings33.h" + + +Scene33 __scene = {0,}; + + +Error scene33_init( void ) +{ + Size i; + + Vec4 verts[ GFX33_QUAD_VERTEX_COUNT ] = GFX33_QUAD_VERTICES; + ModelEdge33 medge[ GFX33_QUAD_EDGE_COUNT ] = GFX33_QUAD_MEDGES; + Size sedge[ GFX33_QUAD_SEDGE_COUNT ] = GFX33_QUAD_SEDGES; + + __scene.cube.vertices = malloc( sizeof(Vec4) * GFX33_QUAD_VERTEX_COUNT ); + __scene.cube.medges = malloc( sizeof(ModelEdge33) * GFX33_QUAD_EDGE_COUNT ); + __scene.cube.sedges = malloc( sizeof(Size) * GFX33_QUAD_SEDGE_COUNT ); + + memcpy( __scene.cube.vertices, verts, sizeof(Vec4) * GFX33_QUAD_VERTEX_COUNT ); + memcpy( __scene.cube.medges, medge, sizeof(ModelEdge33) * GFX33_QUAD_EDGE_COUNT ); + memcpy( __scene.cube.sedges, sedge, sizeof(Size) * GFX33_QUAD_SEDGE_COUNT ); + + __scene.cube.vertexCount = GFX33_QUAD_VERTEX_COUNT; + __scene.cube.edgeCount = GFX33_QUAD_EDGE_COUNT; + __scene.cube.surfaceCount = GFX33_QUAD_SFACE_COUNT; + + __scene.cube.t[2] = 10.0; + __scene.cube.s[0] = 1.0; + __scene.cube.s[1] = 1.0; + __scene.cube.s[2] = 1.0; + + return E33_EXIT_SUCCESS; +} + + +Error scene33_term( void ) +{ + free( __scene.cube.vertices ); + free( __scene.cube.medges ); + free( __scene.cube.sedges ); + + return E33_EXIT_SUCCESS; +} diff --git a/src/strings33.c b/src/strings33.c index 0291393..1d2d78b 100644 --- a/src/strings33.c +++ b/src/strings33.c @@ -24,7 +24,7 @@ static u32 textColours[9] = { }; -void e33_uprintf( Surface33 *surf, Size f, u32 col, Size x, Size y, const char *fmt, ... ) +void strings33_uprintf( Surface33 *surf, Size f, u32 col, Size x, Size y, const char *fmt, ... ) { static char tmp[ _STRING_MAX ]; @@ -32,13 +32,13 @@ void e33_uprintf( Surface33 *surf, Size f, u32 col, Size x, Size y, const char * va_start(args, fmt); vsnprintf(tmp, _STRING_MAX, fmt, args); - e33_uprint( surf, f, col, x, y, tmp ); + strings33_uprint( surf, f, col, x, y, tmp ); va_end(args); } -void e33_uprint( Surface33 *surf, Size f, u32 col, Size x, Size y, const char *str ) +void strings33_uprint( Surface33 *surf, Size f, u32 col, Size x, Size y, const char *str ) { Size i, j, ofs; Font33 *font = fonts[f]; |