From 161d571117648a6873be8b1b9d8c1b366d10e15a Mon Sep 17 00:00:00 2001 From: Mehdi Sadeghi Date: Fri, 8 Apr 2022 00:04:53 +0200 Subject: [PATCH] Fix zeros and add build files. Arabic and Persian zero turned into an elevated dot. Other additions: - Makefile watch and ttftest rules - build script for watching using inodewatch - README updates - Update the glyphs picture --- Makefile | 15 ++++- README.md | 26 ++++++-- build.sh | 18 ++++++ glyphs.png | Bin 6816 -> 23288 bytes noqte.sfd | 37 ++++------- ttftest.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 243 insertions(+), 32 deletions(-) create mode 100755 build.sh create mode 100644 ttftest.c diff --git a/Makefile b/Makefile index af2e752..dcda103 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,20 @@ -.PHONY: clean all +.PHONY: clean all watch all: noqte.ttf noqte.ttf: noqte.sfd fontforge -quiet -lang ff -c "Open(\"noqte.sfd\",1);Generate(\"noqte.ttf\")" +ttftest: *.c + gcc *.c \ + -I/usr/include/SDL2 -lSDL2 -lSDL2_ttf \ + -I/usr/include/harfbuzz -I/usr/include/freetype2 \ + -I/usr/include/glib-2.0 \ + -I/usr/lib/glib-2.0/include \ + -o ttftest + +watch: + ./build.sh noqte.sfd ttftest.c + clean: - rm noqte.ttf \ No newline at end of file + rm -f noqte.ttf ttftest diff --git a/README.md b/README.md index e6daa64..6f98a40 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # Noqte -A fun, minimalistic Persian pixel font - WIP. +A fun, minimalistic Persian pixel font. ![](noqte.png) ## Introduction -I made this font in a week from scratch in order to use it in my game. The em-height is 1024 points. Each glyph is made of 64x64 points squares. There are some exceptions, sadly, mainly for designing diacritics. Those might be removed in a final version, however. For those at moment another square size is used which is 75% smaller, i.e. 32x32 points. +I made this font in a week from scratch in order to use it in my game. The em-height is 1024 points. Each glyph is made of 100x100 points squares. There are some exceptions, sadly, mainly for designing diacritics. Those might be removed in a final version, however. For those at moment another square size is used which is 75% of the base square, i.e. 75x75 points. I have made a few design choices and tried to remain consistent as much as possible: - There is no left bearing anywhere -- All initial glyphs have one block right bearing (64 points empty space to the right) +- All initial glyphs have one block right bearing (100 points empty space to the right) - Important: medial forms have no bearing to the right. I assumed that other initial or medial glyph should consider this and add blocks to the left if necessary -- The bottom left block on each initial glyph is empty +- The bottom left block on each initial glyph is empty (exceptions FEH & QAF) - The bottom left block on each medial glyph is full There might be some minor divergences, which is either a bug and should be fixed or is due to diacritics. @@ -19,7 +19,10 @@ The font covers main charachters for Persian from the following Unicode blocks: - Arabic (0600–06FF) - Arabic Presentation Forms-A (FB50–FDFF) - Arabic Presentation Forms-B (FE70–FEFF) -- Basic Latin (ASCII) - letters missing +- Basic Latin (ASCII) +- Latin-1 Supplement (partial) + +Moreover, Basic Latin i.e. ASCII and some suplementary letters and signs are included. I included as much as necessary to make the font usable for German and Spanish. ## Glyphs Here is a subset of glyphs. @@ -40,6 +43,17 @@ Please report them on the repository or email me. The following problems are kno - There are no anchors - Diacritics are not well-positioned +## Test +There is a development script and an SDL test file included. To watch the changes and rebuild do: + + $ make watch + +or directly + + $ make ttftest + +and then run `ttftest` executable. SDL and HarfBuzz should be available on your system. + ## Aknowledgement Credit when credit is due. I benefited from the work of others mentioned below. @@ -52,4 +66,4 @@ Credit when credit is due. I benefited from the work of others mentioned below. # License Noqte is released under the [OFL license](LICENSE). -Copyright (C) 2022 Mehdi Sadeghi \ No newline at end of file +Copyright (C) 2022 Mehdi Sadeghi diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..7dbac7a --- /dev/null +++ b/build.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +if [ "$#" -lt 2 ]; then + echo 'Usage: build.sh [ ... ]' +fi + +PID= +while inotifywait -e CLOSE_WRITE $@; do + test "$PID" && kill -9 "$PID" + cp -r $1 backup/$(date --iso-8601=seconds)_$1 + fontforge -quiet -lang ff -c "Open(\"$1\",1);Generate(\"noqte.ttf\")" + echo Starting... + make noqte.ttf ttftest + ./ttftest & + PID=$! + echo PID=$PID + sleep 3 +done \ No newline at end of file diff --git a/glyphs.png b/glyphs.png index 28f24a3371778a8daab17a2ef8a52a9026853413..a71f52fa1770c8ca59c8a311b34f17df3704f4ff 100644 GIT binary patch literal 23288 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 e_PD6e*!4fT35VBPCJ; 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 z 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 +#include +#include + +void blit(SDL_Texture *texture, int x, int y, int rtl); +SDL_Texture *loadTXTTexture(char *text, TTF_Font *font, int rtl); + +static TTF_Font *noqte; +static TTF_Font *dejavu; +static TTF_Font *noto; +static TTF_Font *console; +static TTF_Font *consolereg; +static SDL_Window *window; +static SDL_Renderer *renderer; + +int main(int argc, char ** argv) +{ + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + printf("Couldn't initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + if (TTF_Init() < 0) + { + printf("Couldn't initialize SDL_ttf"); + exit(1); + } + + int major, minor, patch; + TTF_GetHarfBuzzVersion(&major, &minor, &patch); + if (!(major || minor || patch)) + { + printf("SDL_ttf compiled without HarfBuz support"); + exit(1); + } + + noqte = TTF_OpenFont("noqte.ttf", 50); + if (noqte == NULL) + { + printf("Couldn't load the font"); + exit(1); + } + + window = SDL_CreateWindow("ttftest", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + 1280, 720, + SDL_WINDOW_RESIZABLE); + if (!window) + { + printf("Failed to open window: %s\n", SDL_GetError()); + exit(1); + } + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (!renderer) + { + printf("Failed to create renderer: %s\n", SDL_GetError()); + exit(1); + } + + SDL_Texture *t01 = loadTXTTexture("ء ا آ ب پ ت ث ج چ ح خ د ذ ر ز ژ س ش", noqte, 1); + SDL_Texture *t02 = loadTXTTexture("ص ض ط ظ ع غ ف ق ک گ ل م ن و ه ی ", noqte, 1); + SDL_Texture *t03 = loadTXTTexture( + "۱۲°۳۴۵۶۷۸۹۰!" + "÷ ! ٬ ٫ ٪ ﷼ × ، * ) ( ـ + - = " + , noqte, 1); + SDL_Texture *t04 = loadTXTTexture( + //"ْ ٌ ٍ ً ُ ِ َ ّ ٓ ٔ " + "ْ ٌ ٍ ً ُ ِ َ ّ ] [ } { » « : ;" + " > < ؟ < . /" + , noqte, 1); + SDL_Texture *t05 = loadTXTTexture( + "در صورت حذف این چند واژه غلط به شکیل، ثابت و جامع‌تر ساختن ", + noqte, 1); + SDL_Texture *t06 = loadTXTTexture( + "پاراگراف شعر از لحاظ دوری از قافیه‌های اضافه کمک می‌شود.", + noqte, 1); + SDL_Texture *t07 = loadTXTTexture("äüößabcdefghijklmnñopqrstuvwxyz", noqte, 0); + SDL_Texture *t08 = loadTXTTexture("ÄÜÖABCDEFGHIJKLMNÑOPQRSTUVWXYZ", noqte, 0); + SDL_Texture *t09 = loadTXTTexture("0123456789°!\"§$%&/()=?`" , noqte, 0); + + SDL_Texture *t10 = loadTXTTexture("The quick brown fox jumps over the lazy dog", noqte, 0); + SDL_Texture *t11 = loadTXTTexture("THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG", noqte, 0); + SDL_Texture *t12 = loadTXTTexture("el veloz murciélago hindú comía feliz cardillo y kiwi.", noqte, 0); + SDL_Texture *t13 = loadTXTTexture("la cigüeña tocaba el saxofón detrás del palenque de paja", noqte, 0); + + + SDL_Event event; + + while (1) + { + SDL_RenderClear(renderer); + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + exit(0); + break; + + default: + break; + } + } + + int right = 1075; + + blit(t01, right, 25, 1); + blit(t02, right, 100, 1); + blit(t03, right, 175, 1); + blit(t04, right, 250, 1); + + blit(t05, right, 325, 1); + blit(t06, right, 400, 1); + + blit(t07, 10, 475, 0); + blit(t08, 10, 550, 0); + + blit(t09, 10, 625, 0); + blit(t10, 10, 700, 0); + blit(t11, 10, 775, 0); + blit(t12, 10, 850, 0); + + SDL_Delay(32); + SDL_RenderPresent(renderer); + } + + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + TTF_CloseFont(noqte); + TTF_Quit(); + SDL_Quit(); +} + +SDL_Texture *loadTXTTexture(char *text, TTF_Font *font, int rtl) +{ + SDL_Rect dest; + + SDL_Color colorA = { 0xff, 0x99, 0x00, 0xff }; + + if (rtl) + { + TTF_SetDirection(HB_DIRECTION_RTL); + TTF_SetScript(HB_SCRIPT_ARABIC); + } else { + TTF_SetDirection(HB_DIRECTION_LTR); + TTF_SetScript(HB_SCRIPT_LATIN); + } + + SDL_Surface *surface; + + surface = TTF_RenderUTF8_Blended(font, text, colorA); + + SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface); + + SDL_FreeSurface(surface); + + return texture; +} + +void blit(SDL_Texture *texture, int x, int y, int rtl) +{ + SDL_Rect dest; + + dest.x = x; + dest.y = y; + + SDL_QueryTexture(texture, NULL, NULL, &dest.w, &dest.h); + + if (rtl) + dest.x -= dest.w; + + SDL_RenderCopy(renderer, texture, NULL, &dest); +} \ No newline at end of file