├── README.md ├── _old ├── CMakeLists.txt ├── README.md ├── dwritetest.cc ├── emojidump.cc ├── harfbuzz.cmake ├── hbftsvg.cc ├── hello-harfbuzz-gl.cc ├── hello-harfbuzz.cc ├── init.bat ├── init.sh ├── stb_image_write.h ├── tut0.cc ├── tut1.cc ├── tut2.cc ├── tut3.cc ├── tut4.cc └── xcodeinit.sh ├── cairo-draw.c ├── curl-download.c ├── expat-parse.c ├── ffmpeg-frames.c ├── fontconfig-resolve.c ├── freetype-render.c ├── fribidi-bidi.c ├── gtk4-gui.c ├── harfbuzz-shape.c ├── icu4c-bidi.c ├── input ├── Roboto.abc.ttf ├── example.svg ├── test.png ├── test.txt.zst ├── test.webp └── testorig.jpg ├── libjpeg-decode.c ├── libpng-decode.c ├── librsvg-render.c ├── libwebp-decode.c ├── libzstd-decode.c ├── lua-run.c ├── mujs-run.c ├── openal-stream.c ├── pangocairo-drawtext.c ├── qt5-gui.cc ├── raqm-shape.c ├── skia-pdf.cc ├── sqlite-run.c ├── ssd1306-cairo-clock.c ├── ssd1306.c ├── v8-run.cc ├── win32-gui.c └── xlib-gui.c /README.md: -------------------------------------------------------------------------------- 1 | Simple self contained examples on how to use different C libraries -------------------------------------------------------------------------------- /_old/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.12) 2 | project (glcourse) 3 | 4 | # Deps 5 | ## glfw 6 | set(GLFW_BUILD_EXAMPLES OFF CACHE STRING "" FORCE) 7 | set(GLFW_BUILD_TESTS OFF CACHE STRING "" FORCE) 8 | set(GLFW_INSTALL OFF CACHE STRING "" FORCE) 9 | add_subdirectory(glfw) 10 | include_directories(${GLFW_INCLUDE_DIRS}) 11 | 12 | ## freetype 13 | add_subdirectory(freetype2) 14 | include_directories(freetype2/include) 15 | 16 | ## harfbuzz 17 | set(ENV{FREETYPE_DIR} "${PROJECT_SOURCE_DIR}/freetype2") 18 | set(HB_HAVE_FREETYPE ON CACHE STRING "" FORCE) 19 | set(HB_HAVE_DIRECTWRITE ON CACHE STRING "" FORCE) 20 | set(HB_HAVE_UNISCRIBE ON CACHE STRING "" FORCE) 21 | add_subdirectory(harfbuzz) 22 | include_directories(harfbuzz/src ${PROJECT_BINARY_DIR}/harfbuzz/src) 23 | 24 | ## glew 25 | add_definitions(-DGLEW_STATIC) 26 | option(glew-cmake_BUILD_SHARED "" OFF) 27 | add_subdirectory(glew) 28 | include_directories(${GLEW_INCLUDE_DIRS}) 29 | 30 | # Ours 31 | ## tut0 32 | add_executable(tut0 tut0.cc) 33 | target_link_libraries(tut0 glfw ${GLFW_LIBRARIES} libglew_static) 34 | 35 | ## tut1 36 | add_executable(tut1 tut1.cc) 37 | target_link_libraries(tut1 harfbuzz freetype) 38 | 39 | ## tut2 40 | add_executable(tut2 tut2.cc) 41 | target_link_libraries(tut2 glfw ${GLFW_LIBRARIES} libglew_static) 42 | 43 | ## tut3 44 | add_executable(tut3 tut3.cc) 45 | target_link_libraries(tut3 glfw ${GLFW_LIBRARIES} libglew_static) 46 | 47 | ## tut4 48 | add_executable(tut4 tut4.cc) 49 | target_link_libraries(tut4 harfbuzz freetype) 50 | 51 | ## hbftsvg 52 | add_executable(hbftsvg hbftsvg.cc) 53 | target_link_libraries(hbftsvg harfbuzz freetype) 54 | 55 | ## hello-harfbuzz 56 | add_definitions(-DPNG_OUTPUT) 57 | add_executable(hello-harfbuzz hello-harfbuzz.cc) 58 | target_link_libraries(hello-harfbuzz harfbuzz freetype) 59 | 60 | ## hello-harfbuzz-gl 61 | add_executable(hello-harfbuzz-gl hello-harfbuzz-gl.cc) 62 | target_link_libraries(hello-harfbuzz-gl harfbuzz freetype glfw ${GLFW_LIBRARIES} libglew_static) 63 | -------------------------------------------------------------------------------- /_old/README.md: -------------------------------------------------------------------------------- 1 | Simple cross platform graphic and OpenGL examples 2 | 3 | Intended to be usable specially on Windows with Visual Studio, where I need it to use for educating OpenGL and graphic. 4 | 5 | For HarfBuzz, [ragel](http://www.complang.org/ragel/) is needed to be installed. 6 | 7 | After cloning it, use `init.sh` or `init.bat` to get needed libraries. 8 | -------------------------------------------------------------------------------- /_old/dwritetest.cc: -------------------------------------------------------------------------------- 1 | // Ebrahim Byagowi 2 | #include 3 | 4 | #include 5 | #include FT_FREETYPE_H 6 | #include FT_GLYPH_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define STB_IMAGE_WRITE_IMPLEMENTATION 13 | #include "stb_image_write.h" 14 | 15 | // from harfbuzz 16 | static inline uint16_t hb_uint16_swap(const uint16_t v) 17 | { 18 | return (v >> 8) | (v << 8); 19 | } 20 | static inline uint32_t hb_uint32_swap(const uint32_t v) 21 | { 22 | return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); 23 | } 24 | 25 | // Simple pixel copy code brought from http://www.freetype.org/freetype2/docs/tutorial/example1.c 26 | inline void drawBitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y, unsigned char* image, int width, int height, uint32_t color) { 27 | FT_Int i, j, p, q; 28 | FT_Int x_max = x + bitmap->width; 29 | FT_Int y_max = y + bitmap->rows; 30 | 31 | int r = color & 0xFF; 32 | int g = (color >> 8) & 0xFF; 33 | int b = (color >> 16) & 0xFF; 34 | int alpha = (color >> 24) & 0xFF; 35 | 36 | for (i = x, p = 0; i < x_max; i++, p++) { 37 | for (j = y, q = 0; j < y_max; j++, q++) { 38 | if (i < 0 || j < 0 || 39 | i >= width || j >= height) 40 | continue; 41 | 42 | // https://github.com/ShaoYuZhang/freetype/commit/27d9e6f6012b55d4001c33e3d46f6814c94ebc0d#diff-3f6d401db89b11a93b8eec6805f53a21R423 43 | int aa = bitmap->buffer[q * bitmap->width + p]; 44 | int fa = alpha * aa / 255; 45 | int fr = r * fa / 255; 46 | int fg = g * fa / 255; 47 | int fb = b * fa / 255; 48 | int ba2 = 255 - fa; 49 | int br = image[4 * j * width + i * 4 + 0]; 50 | int bg = image[4 * j * width + i * 4 + 1]; 51 | int bb = image[4 * j * width + i * 4 + 2]; 52 | int ba = image[4 * j * width + i * 4 + 3]; 53 | image[4 * j * width + i * 4 + 0] = br * ba2 / 255 + fr; 54 | image[4 * j * width + i * 4 + 1] = bg * ba2 / 255 + fg; 55 | image[4 * j * width + i * 4 + 2] = bb * ba2 / 255 + fb; 56 | image[4 * j * width + i * 4 + 3] = ba * ba2 / 255 + fa; 57 | } 58 | } 59 | } 60 | 61 | int main() { 62 | // Initialize freetype 63 | FT_Library library; 64 | FT_Init_FreeType(&library); 65 | 66 | // Initialize the font face 67 | FT_Face face; 68 | FT_New_Face(library, 69 | "C:\\Windows\\Fonts\\tahoma.ttf", 70 | 0, 71 | &face); 72 | 73 | FT_Set_Char_Size(face, 0, 256 * 64, 72, 72); 74 | // Configure harfbuzz buffer and shape 75 | hb_font_t *hb_font; 76 | hb_face_t *hb_face; 77 | hb_buffer_t *buf = nullptr; 78 | const char *text = "متن"; // Emoji sequence 79 | 80 | auto a = new char*{ "directwrite" }; 81 | for (int i = 0; i < 10; ++i) { 82 | if (buf) { 83 | hb_buffer_destroy(buf); 84 | //hb_face_destroy(hb_face); 85 | hb_font_destroy(hb_font); 86 | } 87 | hb_font = hb_ft_font_create(face, NULL); 88 | hb_face = hb_font_get_face(hb_font); 89 | buf = hb_buffer_create(); 90 | hb_buffer_set_direction(buf, HB_DIRECTION_RTL); 91 | hb_buffer_set_language(buf, hb_language_from_string("fa", 2)); 92 | hb_buffer_set_script(buf, HB_SCRIPT_ARABIC); 93 | hb_buffer_add_utf8(buf, text, strlen(text), 0, -1); 94 | hb_directwrite_buffer_set_line_width(buf, 1000); 95 | hb_shape_full(hb_font, buf, 0, 0, a); 96 | } 97 | delete a; 98 | 99 | 100 | unsigned int glyphCount; 101 | 102 | hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(buf, &glyphCount); 103 | hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions(buf, &glyphCount); 104 | 105 | // this is not a good assumption specially when there is GPOS on the font 106 | int height = face->size->metrics.height / 64; 107 | int width = 0; 108 | // doing width measuring just based shaper glyphs advances is not good assumption either 109 | for (int i = 0; i < glyphCount; ++i) { width += glyphPositions[i].x_advance; } 110 | width /= 64; 111 | unsigned char* image = (unsigned char*)calloc(width * height * 16, sizeof(char)); 112 | FT_GlyphSlot slot = face->glyph; 113 | int x = 0, y = face->size->metrics.ascender / 64; 114 | for (int i = 0; i < glyphCount; ++i) { 115 | uint16_t* layerGlyphs = NULL; 116 | uint32_t* layerColors = NULL; 117 | 118 | FT_Load_Glyph(face, glyphInfos[i].codepoint, FT_LOAD_DEFAULT); 119 | FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); 120 | drawBitmap(&slot->bitmap, 121 | x + (glyphPositions[i].x_offset / 64) + slot->bitmap_left, 122 | y - (glyphPositions[i].y_offset / 64) - slot->bitmap_top, 123 | image, width, height, 0xFFFFFFFF); 124 | int a = 2; 125 | 126 | x += glyphPositions[i].x_advance / 64; 127 | y -= glyphPositions[i].y_advance / 64; 128 | } 129 | 130 | stbi_write_png("out.png", width, height, 1 * 4, image, 0); 131 | 132 | // Destroying things 133 | free(image); 134 | 135 | hb_buffer_clear_contents(buf); 136 | hb_buffer_destroy(buf); 137 | hb_font_destroy(hb_font); 138 | FT_Done_Face(face); 139 | FT_Done_FreeType(library); 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /_old/emojidump.cc: -------------------------------------------------------------------------------- 1 | // Ebrahim Byagowi 2 | #include 3 | 4 | #include 5 | #include FT_FREETYPE_H 6 | #include FT_GLYPH_H 7 | 8 | #include 9 | #include 10 | 11 | #define STB_IMAGE_WRITE_IMPLEMENTATION 12 | #include "stb_image_write.h" 13 | 14 | // from harfbuzz 15 | static inline uint16_t hb_uint16_swap(const uint16_t v) 16 | { 17 | return (v >> 8) | (v << 8); 18 | } 19 | static inline uint32_t hb_uint32_swap(const uint32_t v) 20 | { 21 | return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); 22 | } 23 | 24 | // from Mozilla Firefox, https://bug908503.bmoattachments.org/attachment.cgi?id=8424620 25 | #pragma pack(1) 26 | struct COLRBaseGlyphRecord { 27 | uint16_t glyphId; 28 | uint16_t firstLayerIndex; 29 | uint16_t numLayers; 30 | }; 31 | 32 | struct COLRLayerRecord { 33 | uint16_t glyphId; 34 | uint16_t paletteEntryIndex; 35 | }; 36 | 37 | struct CPALColorRecord { 38 | uint8_t blue; 39 | uint8_t green; 40 | uint8_t red; 41 | uint8_t alpha; 42 | }; 43 | 44 | struct COLRHeader { 45 | uint16_t version; 46 | uint16_t numBaseGlyphRecord; 47 | uint32_t offsetBaseGlyphRecord; 48 | uint32_t offsetLayerRecord; 49 | uint16_t numLayerRecords; 50 | }; 51 | 52 | struct CPALHeaderVersion0 { 53 | uint16_t version; 54 | uint16_t numPaletteEntries; 55 | uint16_t numPalettes; 56 | uint16_t numColorRecords; 57 | uint32_t offsetFirstColorRecord; 58 | }; 59 | #pragma pack() 60 | 61 | static int 62 | CompareBaseGlyph(const void* key, const void* data) 63 | { 64 | uint32_t glyphId = (uint32_t)(uintptr_t)key; 65 | auto baseGlyph = (COLRBaseGlyphRecord*)data; 66 | uint16_t baseGlyphId = hb_uint16_swap((uint16_t)(baseGlyph->glyphId)); 67 | 68 | if (baseGlyphId == glyphId) { 69 | return 0; 70 | } 71 | 72 | return baseGlyphId > glyphId ? -1 : 1; 73 | } 74 | 75 | bool GetColorLayersInfo(hb_face_t *face, 76 | uint32_t glyphId, 77 | uint16_t* layerGlyphs[], 78 | uint32_t* layerColors[], 79 | int* layers) 80 | { 81 | COLRHeader* colr = (COLRHeader*)hb_blob_get_data( 82 | hb_face_reference_table(face, hb_tag_from_string("COLR", -1)), 0); 83 | CPALHeaderVersion0* cpal = (CPALHeaderVersion0*)hb_blob_get_data( 84 | hb_face_reference_table(face, hb_tag_from_string("CPAL", -1)), 0); 85 | 86 | const uint8_t* baseGlyphRecords = 87 | (const uint8_t*)colr + uint32_t(hb_uint32_swap(colr->offsetBaseGlyphRecord)); 88 | // BaseGlyphRecord is sorted by glyphId 89 | COLRBaseGlyphRecord* baseGlyph = (COLRBaseGlyphRecord*)bsearch( 90 | (void*)(uintptr_t)glyphId, 91 | baseGlyphRecords, 92 | uint16_t(hb_uint16_swap(colr->numBaseGlyphRecord)), 93 | sizeof(COLRBaseGlyphRecord), 94 | CompareBaseGlyph); 95 | if (!baseGlyph) { return false; } 96 | 97 | const COLRLayerRecord* layer = (COLRLayerRecord*)(((uint8_t*)colr) + 98 | uint32_t(hb_uint32_swap(colr->offsetLayerRecord)) + 99 | sizeof(COLRLayerRecord) * uint16_t(hb_uint16_swap(baseGlyph->firstLayerIndex))); 100 | const uint16_t numLayers = hb_uint16_swap(baseGlyph->numLayers); 101 | const uint32_t offsetFirstColorRecord = hb_uint32_swap(cpal->offsetFirstColorRecord); 102 | 103 | *layerGlyphs = (uint16_t*)malloc(numLayers * sizeof(uint16_t)); 104 | *layerColors = (uint32_t*)malloc(numLayers * sizeof(uint32_t)); 105 | *layers = numLayers; 106 | 107 | for (uint16_t layerIndex = 0; layerIndex < numLayers; layerIndex++) { 108 | (*layerGlyphs)[layerIndex] = hb_uint16_swap(layer->glyphId); 109 | CPALColorRecord* color = (CPALColorRecord*)(((uint8_t*)cpal) + 110 | offsetFirstColorRecord + 111 | sizeof(CPALColorRecord) * hb_uint16_swap(layer->paletteEntryIndex)); 112 | (*layerColors)[layerIndex] = (uint32_t)color->red + (color->green << 8) 113 | + (color->blue << 16) + (color->alpha << 24); 114 | layer++; 115 | } 116 | 117 | return true; 118 | } 119 | 120 | // Simple pixel copy code brought from http://www.freetype.org/freetype2/docs/tutorial/example1.c 121 | inline void drawBitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y, unsigned char* image, int width, int height, uint32_t color) { 122 | FT_Int i, j, p, q; 123 | FT_Int x_max = x + bitmap->width; 124 | FT_Int y_max = y + bitmap->rows; 125 | 126 | int r = color & 0xFF; 127 | int g = (color >> 8) & 0xFF; 128 | int b = (color >> 16) & 0xFF; 129 | int alpha = (color >> 24) & 0xFF; 130 | 131 | for (i = x, p = 0; i < x_max; i++, p++) { 132 | for (j = y, q = 0; j < y_max; j++, q++) { 133 | if (i < 0 || j < 0 || 134 | i >= width || j >= height) 135 | continue; 136 | 137 | // https://github.com/ShaoYuZhang/freetype/commit/27d9e6f6012b55d4001c33e3d46f6814c94ebc0d#diff-3f6d401db89b11a93b8eec6805f53a21R423 138 | int aa = bitmap->buffer[q * bitmap->width + p]; 139 | int fa = alpha * aa / 255; 140 | int fr = r * fa / 255; 141 | int fg = g * fa / 255; 142 | int fb = b * fa / 255; 143 | int ba2 = 255 - fa; 144 | int br = image[4 * j * width + i * 4 + 0]; 145 | int bg = image[4 * j * width + i * 4 + 1]; 146 | int bb = image[4 * j * width + i * 4 + 2]; 147 | int ba = image[4 * j * width + i * 4 + 3]; 148 | image[4 * j * width + i * 4 + 0] = br * ba2 / 255 + fr; 149 | image[4 * j * width + i * 4 + 1] = bg * ba2 / 255 + fg; 150 | image[4 * j * width + i * 4 + 2] = bb * ba2 / 255 + fb; 151 | image[4 * j * width + i * 4 + 3] = ba * ba2 / 255 + fa; 152 | } 153 | } 154 | } 155 | 156 | int main() { 157 | // Initialize freetype 158 | FT_Library library; 159 | FT_Init_FreeType(&library); 160 | 161 | // Initialize the font face 162 | FT_Face face; 163 | FT_New_Face(library, 164 | "colrcpalfont.ttf", 165 | 0, 166 | &face); 167 | 168 | FT_Set_Char_Size(face, 0, 29100, 72, 72); 169 | 170 | // Configure harfbuzz buffer and shape 171 | hb_font_t *hb_font = hb_ft_font_create(face, NULL); 172 | hb_face_t *hb_face = hb_font_get_face(hb_font); 173 | 174 | for (int i = 0; i < face->num_glyphs; ++i) { 175 | 176 | uint16_t* layerGlyphs; 177 | uint32_t* layerColors; 178 | int layers; 179 | if (GetColorLayersInfo(hb_face, i, &layerGlyphs, &layerColors, &layers)) { 180 | 181 | FT_Load_Glyph(face, i, FT_LOAD_DEFAULT); 182 | FT_GlyphSlot slot = face->glyph; 183 | FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); 184 | int left = slot->bitmap_left; 185 | int top = slot->bitmap_top; 186 | 187 | int width = slot->bitmap.width; 188 | int height = slot->bitmap.rows; 189 | 190 | unsigned char* image = (unsigned char*)calloc(width * height * 16, sizeof(char)); 191 | 192 | for (int n = 0; n < layers; ++n) { 193 | FT_Load_Glyph(face, layerGlyphs[n], FT_LOAD_DEFAULT); 194 | FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); 195 | drawBitmap(&slot->bitmap, 196 | slot->bitmap_left - left, 197 | top - slot->bitmap_top, 198 | image, width, height, layerColors[n]); 199 | } 200 | 201 | char outName[255]; 202 | sprintf(outName, "out/%d.png", i); 203 | stbi_write_png(outName, width, height, 1 * 4, image, 0); 204 | 205 | free(image); 206 | free(layerGlyphs); 207 | free(layerColors); 208 | } 209 | } 210 | 211 | // Destroying things 212 | FT_Done_Face(face); 213 | FT_Done_FreeType(library); 214 | 215 | return 0; 216 | } 217 | -------------------------------------------------------------------------------- /_old/harfbuzz.cmake: -------------------------------------------------------------------------------- 1 | migrated to https://github.com/behdad/harfbuzz/blob/master/CMakeLists.txt 2 | -------------------------------------------------------------------------------- /_old/hbftsvg.cc: -------------------------------------------------------------------------------- 1 | // HarfBuzz sample of SVG rendering. It is not best practice nor right way to do 2 | // text rendering using harfbuzz/ft. There are more superior sample on the net, 3 | // you should look at for a real example, this one is just a fun one 4 | // Ebrahim Byagowi 5 | // 6 | // sudo apt-get install libfreetype6-dev libharfbuzz-dev 7 | // Compile and run on Chrome: 8 | // g++ hbftsvg.cc `pkg-config --cflags --libs freetype2 harfbuzz` && chromium-browser 1.svg 9 | // 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include FT_FREETYPE_H 16 | #include FT_GLYPH_H 17 | 18 | #include 19 | #include 20 | 21 | std::string do_outline(FT_Vector_ *ftpoints, FT_Outline ftoutline, char* tagS, short* contourS); 22 | 23 | int main() { 24 | // Initialize freetype 25 | FT_Library library; 26 | FT_Init_FreeType(&library); 27 | 28 | // Initialize the font face 29 | FT_Face face; 30 | FT_New_Face(library, 31 | // Just for sake of simplicity 32 | #if 0 33 | "IranNastaliq.ttf", 34 | #else 35 | #if defined(__linux__) 36 | "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 37 | #elif defined(_WIN32) || defined(_WIN64) 38 | "C:\\Windows\\Fonts\\tahoma.ttf", 39 | #elif __APPLE__ 40 | "/Library/Fonts/Tahoma.ttf", 41 | #endif 42 | #endif 43 | 0, 44 | &face); 45 | 46 | hb_face_t *hb_face = hb_ft_face_create(face, NULL); 47 | hb_font_t *font = hb_font_create(hb_face); 48 | unsigned int upem = hb_face_get_upem(hb_face); 49 | hb_font_set_scale(font, upem, upem); 50 | hb_ft_font_set_funcs(font); 51 | 52 | hb_buffer_t *buf = hb_buffer_create(); 53 | hb_buffer_set_direction(buf, HB_DIRECTION_RTL); 54 | hb_buffer_set_script(buf, HB_SCRIPT_ARABIC); // see hb-unicode.h 55 | // hb_buffer_set_language(buf, hb_language_from_string("ar", 2)); // for language specific font features 56 | const char *text = "طرح‌نَما"; // Arabic script sample 57 | hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); 58 | hb_shape(font, buf, NULL, 0); // Shaping magic happens here 59 | 60 | // Drawing 61 | unsigned int glyphCount; 62 | hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(buf, &glyphCount); 63 | hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions(buf, &glyphCount); 64 | 65 | // this is not a good assumption specially when there is GPOS on the font 66 | int height = face->height; 67 | int width = 0; 68 | for (int i = 0; i < glyphCount; ++i) { width += glyphPositions[i].x_advance; } 69 | int x = 0, y = face->ascender; 70 | 71 | std::ofstream file("1.svg"); 72 | file << ""; 73 | 74 | for (int i = 0; i < glyphCount; ++i) { 75 | FT_Load_Glyph(face, glyphInfos[i].codepoint, FT_LOAD_NO_SCALE | 76 | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_BITMAP | 77 | FT_LOAD_LINEAR_DESIGN | FT_KERNING_UNSCALED | FT_LOAD_IGNORE_TRANSFORM); 78 | 79 | FT_GlyphSlot slot = face->glyph; 80 | FT_Outline ftoutline = slot->outline; 81 | FT_Glyph_Metrics gm = slot->metrics; 82 | 83 | int s = x + glyphPositions[i].x_offset + slot->bitmap_left; 84 | int t = y - glyphPositions[i].y_offset - slot->bitmap_top; 85 | 86 | FT_Vector_ *ftpoints = ftoutline.points; 87 | 88 | // TODO: Instead do_outline, use FT_Outline_Decompose based approach 89 | #if 0 90 | for (int j = 0; j < ftoutline.n_points; j++) { 91 | ftpoints[j].y *= -1; 92 | ftpoints[j].x += s; 93 | ftpoints[j].y += t; 94 | } 95 | file << do_outline(ftpoints, ftoutline, ftoutline.tags, ftoutline.contours).c_str(); 96 | #else 97 | file << ""; 98 | file << do_outline(ftpoints, ftoutline, ftoutline.tags, ftoutline.contours).c_str(); 99 | file << ""; 100 | #endif 101 | 102 | x += glyphPositions[i].x_advance; 103 | y -= glyphPositions[i].y_advance; 104 | 105 | file << std::endl; 106 | } 107 | 108 | file << std::endl << ""; 109 | file.close(); 110 | 111 | // Destroying things 112 | hb_buffer_clear_contents(buf); 113 | hb_buffer_destroy(buf); 114 | FT_Done_Face(face); 115 | FT_Done_FreeType(library); 116 | 117 | return 0; 118 | } 119 | 120 | 121 | 122 | // Below code is brought from this project: 123 | // github.com/donbright/font_to_svg (Under BSD license) 124 | #include 125 | #include 126 | #include 127 | /* Draw the outline of the font as svg. 128 | There are three main components. 129 | 1. the points 130 | 2. the 'tags' for the points 131 | 3. the contour indexes (that define which points belong to which contour) 132 | */ 133 | std::string do_outline(FT_Vector_ *ftpoints, FT_Outline ftoutline, char* tagS, short* contourS) 134 | { 135 | std::vector points(ftpoints, ftpoints + ftoutline.n_points); 136 | std::vector tags(tagS, tagS + ftoutline.n_points); 137 | std::vector contours(contourS, contourS + ftoutline.n_contours); 138 | 139 | std::stringstream debug, svg; 140 | if (points.size() == 0) return ""; 141 | if (contours.size() == 0) return ""; 142 | svg.str(""); 143 | svg << "\n "; 232 | return svg.str(); 233 | } 234 | -------------------------------------------------------------------------------- /_old/hello-harfbuzz-gl.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define FONT_SIZE 300 10 | #define MARGIN (FONT_SIZE * .5) 11 | 12 | int main(int argc, char* argv[]) { 13 | const char *fontfile; 14 | const char *text; 15 | 16 | 17 | if (argc < 3) { 18 | fprintf(stderr, "usage: hello-harfbuzz font-file.ttf text\n"); 19 | 20 | fontfile = 21 | #if defined(__linux__) 22 | "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"; 23 | #elif defined(_WIN32) || defined(_WIN64) 24 | "C:\\Windows\\Fonts\\tahoma.ttf"; 25 | #elif __APPLE__ 26 | "/Library/Fonts/Tahoma.ttf"; 27 | #endif 28 | text = "متن متن"; 29 | } else { 30 | fontfile = argv[1]; 31 | text = argv[2]; 32 | } 33 | 34 | /* Initialize FreeType and create FreeType font face. */ 35 | FT_Library ft_library; 36 | FT_Face ft_face; 37 | FT_Error ft_error; 38 | 39 | 40 | if ((ft_error = FT_Init_FreeType(&ft_library))) 41 | abort(); 42 | if ((ft_error = FT_New_Face(ft_library, fontfile, 0, &ft_face))) 43 | abort(); 44 | if ((ft_error = FT_Set_Char_Size(ft_face, FONT_SIZE * 64, FONT_SIZE * 64, 0, 0))) 45 | abort(); 46 | 47 | /* Create hb-ft font. */ 48 | hb_font_t *hb_font; 49 | hb_font = hb_ft_font_create(ft_face, NULL); 50 | 51 | /* Create hb-buffer and populate. */ 52 | hb_buffer_t *hb_buffer; 53 | hb_buffer = hb_buffer_create(); 54 | hb_buffer_add_utf8(hb_buffer, text, -1, 0, -1); 55 | hb_buffer_guess_segment_properties(hb_buffer); 56 | 57 | /* Shape it! */ 58 | hb_shape(hb_font, hb_buffer, NULL, 0); 59 | 60 | /* Print glyph names and positions out. */ 61 | unsigned int len; 62 | hb_glyph_info_t *infos; 63 | hb_glyph_position_t *positions; 64 | len = hb_buffer_get_length(hb_buffer); 65 | infos = hb_buffer_get_glyph_infos(hb_buffer, NULL); 66 | positions = hb_buffer_get_glyph_positions(hb_buffer, NULL); 67 | 68 | /* Draw */ 69 | int width = 2 * MARGIN; 70 | int height = 2 * MARGIN; 71 | for (unsigned int i = 0; i < len; i++) 72 | { 73 | width += positions[i].x_advance / 64.; 74 | height -= positions[i].y_advance / 64.; 75 | } 76 | if (HB_DIRECTION_IS_HORIZONTAL(hb_buffer_get_direction(hb_buffer))) 77 | height += FONT_SIZE; 78 | else 79 | width += FONT_SIZE; 80 | 81 | width = pow(2, (int)log2(width) + 1); 82 | int image_len = width * height; 83 | unsigned char *image = (unsigned char*)calloc(image_len, sizeof(unsigned char)); 84 | 85 | FT_GlyphSlot slot = ft_face->glyph; 86 | 87 | int x = MARGIN, y = MARGIN; 88 | if (HB_DIRECTION_IS_HORIZONTAL(hb_buffer_get_direction(hb_buffer))) 89 | y += (FONT_SIZE - ft_face->size->metrics.height / 64.) * .5 + 90 | ft_face->size->metrics.ascender / 64.; 91 | else 92 | x += FONT_SIZE * .5; 93 | 94 | for (int i = 0; i < len; ++i) { 95 | FT_Load_Glyph(ft_face, infos[i].codepoint, FT_LOAD_DEFAULT); 96 | FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); 97 | 98 | const int src_x = x + (positions[i].x_offset / 64.) + slot->bitmap_left; 99 | const int src_y = y - (positions[i].y_offset / 64.) - slot->bitmap_top; 100 | const int src_height = slot->bitmap.rows; 101 | const int src_width = slot->bitmap.width; 102 | const int width_diff = width - src_width; 103 | int dst_index = src_y * width + src_x; 104 | int src_index = 0; 105 | for (int row = 0; row < src_height; dst_index += width_diff, ++row) 106 | for (int index = 0; index < src_width; ++index, ++dst_index, ++src_index) 107 | if (dst_index < image_len && dst_index > 0) 108 | image[dst_index] |= slot->bitmap.buffer[src_index]; 109 | 110 | x += positions[i].x_advance / 64.; 111 | y -= positions[i].y_advance / 64.; 112 | } 113 | 114 | /* Display */ 115 | // http://antongerdelan.net/opengl 116 | GLFWwindow* window = NULL; 117 | GLuint vao; 118 | GLuint vbo; 119 | 120 | // position and texture coords at the same time 121 | GLfloat points[] = { 122 | 0.0, 0.0, 123 | 1.0, 0.0, 124 | 0.0, 1.0, 125 | 1.0, 1.0, 126 | }; 127 | const char* vertex_shader = 128 | "#version 400\n" 129 | "uniform float time;" 130 | "in vec2 vp;" 131 | "out vec2 vTexCoord;" 132 | "void main () {" 133 | " gl_Position = vec4(vp * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);" 134 | " gl_Position.x *= sin(time);" 135 | " vTexCoord = vp;" 136 | "}"; 137 | const char* fragment_shader = 138 | "#version 400\n" 139 | "uniform sampler2D basic_texture;" 140 | "in vec2 vTexCoord;" 141 | "out vec4 frag_color;" 142 | "void main () {" 143 | " frag_color = texture(basic_texture, vec2(vTexCoord.x, 1 - vTexCoord.y));" 144 | " frag_color = vec4(frag_color.r, frag_color.r, frag_color.r, 1.0);" 145 | "}"; 146 | GLuint vs, fs; 147 | GLuint shader_programme; 148 | 149 | if (!glfwInit()) { 150 | fprintf(stderr, "ERROR: could not start GLFW3\n"); 151 | return 1; 152 | } 153 | 154 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 155 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 156 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 157 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 158 | 159 | glfwWindowHint(GLFW_SAMPLES, 4); 160 | 161 | window = glfwCreateWindow(width, height, text, NULL, NULL); 162 | if (!window) { 163 | fprintf(stderr, "ERROR: could not open window with GLFW3\n"); 164 | glfwTerminate(); 165 | return 1; 166 | } 167 | glfwMakeContextCurrent(window); 168 | glewExperimental = GL_TRUE; 169 | glewInit(); 170 | glEnable(GL_DEPTH_TEST); 171 | glDepthFunc(GL_LESS); 172 | 173 | glGenBuffers(1, &vbo); 174 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 175 | glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), points, GL_STATIC_DRAW); 176 | 177 | glGenVertexArrays(1, &vao); 178 | glBindVertexArray(vao); 179 | glEnableVertexAttribArray(0); 180 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 181 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); 182 | 183 | vs = glCreateShader(GL_VERTEX_SHADER); 184 | glShaderSource(vs, 1, &vertex_shader, NULL); 185 | glCompileShader(vs); 186 | fs = glCreateShader(GL_FRAGMENT_SHADER); 187 | glShaderSource(fs, 1, &fragment_shader, NULL); 188 | glCompileShader(fs); 189 | shader_programme = glCreateProgram(); 190 | glAttachShader(shader_programme, fs); 191 | glAttachShader(shader_programme, vs); 192 | glLinkProgram(shader_programme); 193 | 194 | GLuint tex = 0; 195 | glActiveTexture(GL_TEXTURE0); 196 | glBindTexture(GL_TEXTURE_2D, tex); 197 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, 198 | GL_UNSIGNED_BYTE, image); 199 | glUniform1i(glGetUniformLocation(shader_programme, "image"), tex); 200 | glGenerateMipmap(GL_TEXTURE_2D); 201 | 202 | GLuint time_uniform = glGetUniformLocation(shader_programme, "time"); 203 | 204 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 205 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 206 | 207 | while (!glfwWindowShouldClose(window)) { 208 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 209 | glClearColor(1.0, 1.0, 1.0, 1.0); 210 | glUseProgram(shader_programme); 211 | glUniform1f(time_uniform, glfwGetTime()); 212 | glBindVertexArray(vao); 213 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 214 | glfwPollEvents(); 215 | glfwSwapBuffers(window); 216 | } 217 | 218 | /* free resources */ 219 | free(image); 220 | 221 | hb_buffer_destroy(hb_buffer); 222 | hb_font_destroy(hb_font); 223 | 224 | FT_Done_Face(ft_face); 225 | FT_Done_FreeType(ft_library); 226 | 227 | glDeleteProgram(shader_programme); 228 | glfwTerminate(); 229 | 230 | return 0; 231 | } 232 | -------------------------------------------------------------------------------- /_old/hello-harfbuzz.cc: -------------------------------------------------------------------------------- 1 | // Cairo free version of https://github.com/behdad/harfbuzz-tutorial/blob/master/hello-harfbuzz.c 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef PNG_OUTPUT 9 | #define STB_IMAGE_WRITE_IMPLEMENTATION 10 | #include "stb_image_write.h" 11 | #endif 12 | 13 | #define FONT_SIZE 36 14 | #define MARGIN (FONT_SIZE * .5) 15 | 16 | int 17 | main(int argc, char **argv) 18 | { 19 | const char *fontfile; 20 | const char *text; 21 | 22 | if (argc < 3) { 23 | fprintf(stderr, "usage: hello-harfbuzz font-file.ttf text\n"); 24 | 25 | fontfile = 26 | #if defined(__linux__) 27 | "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"; 28 | #elif defined(_WIN32) || defined(_WIN64) 29 | "C:\\Windows\\Fonts\\tahoma.ttf"; 30 | #elif __APPLE__ 31 | "/Library/Fonts/Tahoma.ttf"; 32 | #endif 33 | text = "متن متن"; 34 | } else { 35 | fontfile = argv[1]; 36 | text = argv[2]; 37 | } 38 | 39 | /* Initialize FreeType and create FreeType font face. */ 40 | FT_Library ft_library; 41 | FT_Face ft_face; 42 | FT_Error ft_error; 43 | 44 | if ((ft_error = FT_Init_FreeType (&ft_library))) 45 | abort(); 46 | if ((ft_error = FT_New_Face (ft_library, fontfile, 0, &ft_face))) 47 | abort(); 48 | if ((ft_error = FT_Set_Char_Size (ft_face, FONT_SIZE*64, FONT_SIZE*64, 0, 0))) 49 | abort(); 50 | 51 | /* Create hb-ft font. */ 52 | hb_font_t *hb_font; 53 | hb_font = hb_ft_font_create (ft_face, NULL); 54 | 55 | /* Create hb-buffer and populate. */ 56 | hb_buffer_t *hb_buffer; 57 | hb_buffer = hb_buffer_create (); 58 | hb_buffer_add_utf8(hb_buffer, text, -1, 0, -1); 59 | hb_buffer_guess_segment_properties (hb_buffer); 60 | 61 | /* Shape it! */ 62 | hb_shape (hb_font, hb_buffer, NULL, 0); 63 | 64 | /* Print glyph names and positions out. */ 65 | unsigned int len; 66 | hb_glyph_info_t *infos; 67 | hb_glyph_position_t *positions; 68 | len = hb_buffer_get_length (hb_buffer); 69 | infos = hb_buffer_get_glyph_infos (hb_buffer, NULL); 70 | positions = hb_buffer_get_glyph_positions (hb_buffer, NULL); 71 | 72 | for (unsigned int i = 0; i < len; i++) 73 | { 74 | hb_glyph_info_t *info = &infos[i]; 75 | hb_glyph_position_t *pos = &positions[i]; 76 | 77 | char glyphname[32]; 78 | hb_font_get_glyph_name (hb_font, info->codepoint, glyphname, sizeof (glyphname)); 79 | printf ("glyph '%s' cluster %d x-advance %4.2g offset %g,%g\n", 80 | glyphname, 81 | info->cluster, 82 | pos->x_advance / 64., 83 | pos->x_offset / 64., 84 | pos->y_offset / 64.); 85 | } 86 | 87 | /* Draw */ 88 | int width = 2 * MARGIN; 89 | int height = 2 * MARGIN; 90 | for (unsigned int i = 0; i < len; i++) 91 | { 92 | width += positions[i].x_advance / 64.; 93 | height -= positions[i].y_advance / 64.; 94 | } 95 | if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction (hb_buffer))) 96 | height += FONT_SIZE; 97 | else 98 | width += FONT_SIZE; 99 | 100 | int image_len = width * height; 101 | unsigned char *image = (unsigned char*)calloc (image_len, sizeof (char)); 102 | 103 | FT_GlyphSlot slot = ft_face->glyph; 104 | 105 | int x = MARGIN, y = MARGIN; 106 | if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction (hb_buffer))) 107 | y += (FONT_SIZE - ft_face->size->metrics.height / 64.) * .5 + 108 | ft_face->size->metrics.ascender / 64.; 109 | else 110 | x += FONT_SIZE * .5; 111 | 112 | for (int i = 0; i < len; ++i) 113 | { 114 | FT_Load_Glyph (ft_face, infos[i].codepoint, FT_LOAD_DEFAULT); 115 | FT_Render_Glyph (slot, FT_RENDER_MODE_NORMAL); 116 | 117 | const int src_x = x + (positions[i].x_offset / 64.) + slot->bitmap_left; 118 | const int src_y = y - (positions[i].y_offset / 64.) - slot->bitmap_top; 119 | const int src_height = slot->bitmap.rows; 120 | const int src_width = slot->bitmap.width; 121 | const int width_diff = width - src_width; 122 | int dst_index = src_y * width + src_x; 123 | int src_index = 0; 124 | for (int row = 0; row < src_height; dst_index += width_diff, ++row) 125 | for (int index = 0; index < src_width; ++index, ++dst_index, ++src_index) 126 | if (dst_index < image_len && dst_index > 0) 127 | image[dst_index] |= slot->bitmap.buffer[src_index]; 128 | 129 | x += positions[i].x_advance / 64.; 130 | y -= positions[i].y_advance / 64.; 131 | } 132 | 133 | #ifndef PNG_OUTPUT 134 | // Save as pbm file, Inkscape Libre/OpenOffice Draw can open it 135 | FILE *f = fopen ("out.pbm", "wb"); 136 | fprintf (f, "P5 %d %d %d\n", width, height, slot->bitmap.num_grays - 1); 137 | fwrite ((const char *)image, sizeof (char), width * height, f); 138 | fclose (f); 139 | #else 140 | stbi_write_png ("out.png", width, height, 1, image, 0); 141 | #endif 142 | 143 | free (image); 144 | 145 | hb_buffer_destroy (hb_buffer); 146 | hb_font_destroy (hb_font); 147 | 148 | FT_Done_Face (ft_face); 149 | FT_Done_FreeType (ft_library); 150 | 151 | return 0; 152 | } 153 | -------------------------------------------------------------------------------- /_old/init.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if not exist freetype2 git clone --depth=1 http://git.savannah.nongnu.org/r/freetype/freetype2.git/ 3 | if not exist glfw git clone --depth=1 https://github.com/glfw/glfw 4 | if not exist glew git clone --depth=1 https://github.com/omniavinco/glew-cmake glew 5 | if not exist harfbuzz git clone --depth=1 https://github.com/behdad/harfbuzz 6 | for %%f in (freetype2 glfw glew harfbuzz) do cd %%f & git pull & cd .. 7 | 8 | "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\devenv.com" . -------------------------------------------------------------------------------- /_old/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit 3 | set -o pipefail 4 | set -o nounset 5 | # set -o xtrace 6 | 7 | [ -d freetype2 ] || git clone --depth=1 http://git.savannah.nongnu.org/r/freetype/freetype2.git/ 8 | [ -d glfw ] || git clone --depth=1 https://github.com/glfw/glfw 9 | [ -d glew ] || git clone --depth=1 https://github.com/omniavinco/glew-cmake glew 10 | [ -d harfbuzz ] || git clone --depth=1 https://github.com/behdad/harfbuzz 11 | for f in freetype2 glfw glew harfbuzz; do cd $f; git pull; cd ..; done 12 | 13 | rm -rf build 14 | mkdir build 15 | cd build 16 | cmake -G "Unix Makefiles" ../ 17 | make 18 | cd .. 19 | code . || true 20 | -------------------------------------------------------------------------------- /_old/stb_image_write.h: -------------------------------------------------------------------------------- 1 | /* stb_image_write - v0.98 - public domain - http://nothings.org/stb/stb_image_write.h 2 | writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010 3 | no warranty implied; use at your own risk 4 | 5 | 6 | Before #including, 7 | 8 | #define STB_IMAGE_WRITE_IMPLEMENTATION 9 | 10 | in the file that you want to have the implementation. 11 | 12 | Will probably not work correctly with strict-aliasing optimizations. 13 | 14 | ABOUT: 15 | 16 | This header file is a library for writing images to C stdio. It could be 17 | adapted to write to memory or a general streaming interface; let me know. 18 | 19 | The PNG output is not optimal; it is 20-50% larger than the file 20 | written by a decent optimizing implementation. This library is designed 21 | for source code compactness and simplicitly, not optimal image file size 22 | or run-time performance. 23 | 24 | BUILDING: 25 | 26 | You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. 27 | You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace 28 | malloc,realloc,free. 29 | You can define STBIW_MEMMOVE() to replace memmove() 30 | 31 | USAGE: 32 | 33 | There are four functions, one for each image file format: 34 | 35 | int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 36 | int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 37 | int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 38 | int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data); 39 | 40 | Each function returns 0 on failure and non-0 on success. 41 | 42 | The functions create an image file defined by the parameters. The image 43 | is a rectangle of pixels stored from left-to-right, top-to-bottom. 44 | Each pixel contains 'comp' channels of data stored interleaved with 8-bits 45 | per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is 46 | monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. 47 | The *data pointer points to the first byte of the top-left-most pixel. 48 | For PNG, "stride_in_bytes" is the distance in bytes from the first byte of 49 | a row of pixels to the first byte of the next row of pixels. 50 | 51 | PNG creates output files with the same number of components as the input. 52 | The BMP format expands Y to RGB in the file format and does not 53 | output alpha. 54 | 55 | PNG supports writing rectangles of data even when the bytes storing rows of 56 | data are not consecutive in memory (e.g. sub-rectangles of a larger image), 57 | by supplying the stride between the beginning of adjacent rows. The other 58 | formats do not. (Thus you cannot write a native-format BMP through the BMP 59 | writer, both because it is in BGR order and because it may have padding 60 | at the end of the line.) 61 | 62 | HDR expects linear float data. Since the format is always 32-bit rgb(e) 63 | data, alpha (if provided) is discarded, and for monochrome data it is 64 | replicated across all three channels. 65 | 66 | CREDITS: 67 | 68 | PNG/BMP/TGA 69 | Sean Barrett 70 | HDR 71 | Baldur Karlsson 72 | TGA monochrome: 73 | Jean-Sebastien Guay 74 | misc enhancements: 75 | Tim Kelsey 76 | bugfixes: 77 | github:Chribba 78 | */ 79 | 80 | #ifndef INCLUDE_STB_IMAGE_WRITE_H 81 | #define INCLUDE_STB_IMAGE_WRITE_H 82 | 83 | #ifdef __cplusplus 84 | extern "C" { 85 | #endif 86 | 87 | extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 88 | extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 89 | extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 90 | extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | 96 | #endif//INCLUDE_STB_IMAGE_WRITE_H 97 | 98 | #ifdef STB_IMAGE_WRITE_IMPLEMENTATION 99 | 100 | #include 101 | #include 102 | #include 103 | #include 104 | #include 105 | 106 | #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && defined(STBIW_REALLOC) 107 | // ok 108 | #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) 109 | // ok 110 | #else 111 | #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC." 112 | #endif 113 | 114 | #ifndef STBIW_MALLOC 115 | #define STBIW_MALLOC(sz) malloc(sz) 116 | #define STBIW_REALLOC(p,sz) realloc(p,sz) 117 | #define STBIW_FREE(p) free(p) 118 | #endif 119 | #ifndef STBIW_MEMMOVE 120 | #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) 121 | #endif 122 | 123 | 124 | #ifndef STBIW_ASSERT 125 | #include 126 | #define STBIW_ASSERT(x) assert(x) 127 | #endif 128 | 129 | typedef unsigned int stbiw_uint32; 130 | typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; 131 | 132 | static void writefv(FILE *f, const char *fmt, va_list v) 133 | { 134 | while (*fmt) { 135 | switch (*fmt++) { 136 | case ' ': break; 137 | case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; } 138 | case '2': { int x = va_arg(v,int); unsigned char b[2]; 139 | b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8); 140 | fwrite(b,2,1,f); break; } 141 | case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4]; 142 | b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8); 143 | b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24); 144 | fwrite(b,4,1,f); break; } 145 | default: 146 | STBIW_ASSERT(0); 147 | return; 148 | } 149 | } 150 | } 151 | 152 | static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c) 153 | { 154 | unsigned char arr[3]; 155 | arr[0] = a, arr[1] = b, arr[2] = c; 156 | fwrite(arr, 3, 1, f); 157 | } 158 | 159 | static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) 160 | { 161 | unsigned char bg[3] = { 255, 0, 255}, px[3]; 162 | stbiw_uint32 zero = 0; 163 | int i,j,k, j_end; 164 | 165 | if (y <= 0) 166 | return; 167 | 168 | if (vdir < 0) 169 | j_end = -1, j = y-1; 170 | else 171 | j_end = y, j = 0; 172 | 173 | for (; j != j_end; j += vdir) { 174 | for (i=0; i < x; ++i) { 175 | unsigned char *d = (unsigned char *) data + (j*x+i)*comp; 176 | if (write_alpha < 0) 177 | fwrite(&d[comp-1], 1, 1, f); 178 | switch (comp) { 179 | case 1: fwrite(d, 1, 1, f); 180 | break; 181 | case 2: if (expand_mono) 182 | write3(f, d[0],d[0],d[0]); // monochrome bmp 183 | else 184 | fwrite(d, 1, 1, f); // monochrome TGA 185 | break; 186 | case 4: 187 | if (!write_alpha) { 188 | // composite against pink background 189 | for (k=0; k < 3; ++k) 190 | px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255; 191 | write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]); 192 | break; 193 | } 194 | /* FALLTHROUGH */ 195 | case 3: 196 | write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]); 197 | break; 198 | } 199 | if (write_alpha > 0) 200 | fwrite(&d[comp-1], 1, 1, f); 201 | } 202 | fwrite(&zero,scanline_pad,1,f); 203 | } 204 | } 205 | 206 | static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) 207 | { 208 | FILE *f; 209 | if (y < 0 || x < 0) return 0; 210 | f = fopen(filename, "wb"); 211 | if (f) { 212 | va_list v; 213 | va_start(v, fmt); 214 | writefv(f, fmt, v); 215 | va_end(v); 216 | write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono); 217 | fclose(f); 218 | } 219 | return f != NULL; 220 | } 221 | 222 | int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) 223 | { 224 | int pad = (-x*3) & 3; 225 | return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad, 226 | "11 4 22 4" "4 44 22 444444", 227 | 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header 228 | 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header 229 | } 230 | 231 | int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) 232 | { 233 | int has_alpha = (comp == 2 || comp == 4); 234 | int colorbytes = has_alpha ? comp-1 : comp; 235 | int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 236 | return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0, 237 | "111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8); 238 | } 239 | 240 | // ************************************************************************************************* 241 | // Radiance RGBE HDR writer 242 | // by Baldur Karlsson 243 | #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) 244 | 245 | void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) 246 | { 247 | int exponent; 248 | float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); 249 | 250 | if (maxcomp < 1e-32) { 251 | rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; 252 | } else { 253 | float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; 254 | 255 | rgbe[0] = (unsigned char)(linear[0] * normalize); 256 | rgbe[1] = (unsigned char)(linear[1] * normalize); 257 | rgbe[2] = (unsigned char)(linear[2] * normalize); 258 | rgbe[3] = (unsigned char)(exponent + 128); 259 | } 260 | } 261 | 262 | void stbiw__write_run_data(FILE *f, int length, unsigned char databyte) 263 | { 264 | unsigned char lengthbyte = (unsigned char) (length+128); 265 | STBIW_ASSERT(length+128 <= 255); 266 | fwrite(&lengthbyte, 1, 1, f); 267 | fwrite(&databyte, 1, 1, f); 268 | } 269 | 270 | void stbiw__write_dump_data(FILE *f, int length, unsigned char *data) 271 | { 272 | unsigned char lengthbyte = (unsigned char )(length & 0xff); 273 | STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code 274 | fwrite(&lengthbyte, 1, 1, f); 275 | fwrite(data, length, 1, f); 276 | } 277 | 278 | void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline) 279 | { 280 | unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; 281 | unsigned char rgbe[4]; 282 | float linear[3]; 283 | int x; 284 | 285 | scanlineheader[2] = (width&0xff00)>>8; 286 | scanlineheader[3] = (width&0x00ff); 287 | 288 | /* skip RLE for images too small or large */ 289 | if (width < 8 || width >= 32768) { 290 | for (x=0; x < width; x++) { 291 | switch (comp) { 292 | case 4: /* fallthrough */ 293 | case 3: linear[2] = scanline[x*comp + 2]; 294 | linear[1] = scanline[x*comp + 1]; 295 | linear[0] = scanline[x*comp + 0]; 296 | break; 297 | case 2: /* fallthrough */ 298 | case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0]; 299 | break; 300 | } 301 | stbiw__linear_to_rgbe(rgbe, linear); 302 | fwrite(rgbe, 4, 1, f); 303 | } 304 | } else { 305 | int c,r; 306 | /* encode into scratch buffer */ 307 | for (x=0; x < width; x++) { 308 | switch(comp) { 309 | case 4: /* fallthrough */ 310 | case 3: linear[2] = scanline[x*comp + 2]; 311 | linear[1] = scanline[x*comp + 1]; 312 | linear[0] = scanline[x*comp + 0]; 313 | break; 314 | case 2: /* fallthrough */ 315 | case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0]; 316 | break; 317 | } 318 | stbiw__linear_to_rgbe(rgbe, linear); 319 | scratch[x + width*0] = rgbe[0]; 320 | scratch[x + width*1] = rgbe[1]; 321 | scratch[x + width*2] = rgbe[2]; 322 | scratch[x + width*3] = rgbe[3]; 323 | } 324 | 325 | fwrite(scanlineheader, 4, 1, f); 326 | 327 | /* RLE each component separately */ 328 | for (c=0; c < 4; c++) { 329 | unsigned char *comp = &scratch[width*c]; 330 | 331 | x = 0; 332 | while (x < width) { 333 | // find first run 334 | r = x; 335 | while (r+2 < width) { 336 | if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) 337 | break; 338 | ++r; 339 | } 340 | if (r+2 >= width) 341 | r = width; 342 | // dump up to first run 343 | while (x < r) { 344 | int len = r-x; 345 | if (len > 128) len = 128; 346 | stbiw__write_dump_data(f, len, &comp[x]); 347 | x += len; 348 | } 349 | // if there's a run, output it 350 | if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd 351 | // find next byte after run 352 | while (r < width && comp[r] == comp[x]) 353 | ++r; 354 | // output run up to r 355 | while (x < r) { 356 | int len = r-x; 357 | if (len > 127) len = 127; 358 | stbiw__write_run_data(f, len, comp[x]); 359 | x += len; 360 | } 361 | } 362 | } 363 | } 364 | } 365 | } 366 | 367 | int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) 368 | { 369 | int i; 370 | FILE *f; 371 | if (y <= 0 || x <= 0 || data == NULL) return 0; 372 | f = fopen(filename, "wb"); 373 | if (f) { 374 | /* Each component is stored separately. Allocate scratch space for full output scanline. */ 375 | unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); 376 | fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" ); 377 | fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x); 378 | for(i=0; i < y; i++) 379 | stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x); 380 | STBIW_FREE(scratch); 381 | fclose(f); 382 | } 383 | return f != NULL; 384 | } 385 | 386 | ///////////////////////////////////////////////////////// 387 | // PNG 388 | 389 | // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() 390 | #define stbiw__sbraw(a) ((int *) (a) - 2) 391 | #define stbiw__sbm(a) stbiw__sbraw(a)[0] 392 | #define stbiw__sbn(a) stbiw__sbraw(a)[1] 393 | 394 | #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) 395 | #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) 396 | #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) 397 | 398 | #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) 399 | #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) 400 | #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) 401 | 402 | static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) 403 | { 404 | int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; 405 | void *p = STBIW_REALLOC(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2); 406 | STBIW_ASSERT(p); 407 | if (p) { 408 | if (!*arr) ((int *) p)[1] = 0; 409 | *arr = (void *) ((int *) p + 2); 410 | stbiw__sbm(*arr) = m; 411 | } 412 | return *arr; 413 | } 414 | 415 | static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) 416 | { 417 | while (*bitcount >= 8) { 418 | stbiw__sbpush(data, (unsigned char) *bitbuffer); 419 | *bitbuffer >>= 8; 420 | *bitcount -= 8; 421 | } 422 | return data; 423 | } 424 | 425 | static int stbiw__zlib_bitrev(int code, int codebits) 426 | { 427 | int res=0; 428 | while (codebits--) { 429 | res = (res << 1) | (code & 1); 430 | code >>= 1; 431 | } 432 | return res; 433 | } 434 | 435 | static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) 436 | { 437 | int i; 438 | for (i=0; i < limit && i < 258; ++i) 439 | if (a[i] != b[i]) break; 440 | return i; 441 | } 442 | 443 | static unsigned int stbiw__zhash(unsigned char *data) 444 | { 445 | stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); 446 | hash ^= hash << 3; 447 | hash += hash >> 5; 448 | hash ^= hash << 4; 449 | hash += hash >> 17; 450 | hash ^= hash << 25; 451 | hash += hash >> 6; 452 | return hash; 453 | } 454 | 455 | #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) 456 | #define stbiw__zlib_add(code,codebits) \ 457 | (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) 458 | #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) 459 | // default huffman tables 460 | #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) 461 | #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) 462 | #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) 463 | #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) 464 | #define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) 465 | #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) 466 | 467 | #define stbiw__ZHASH 16384 468 | 469 | unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) 470 | { 471 | static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; 472 | static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; 473 | static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; 474 | static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; 475 | unsigned int bitbuf=0; 476 | int i,j, bitcount=0; 477 | unsigned char *out = NULL; 478 | unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack! 479 | if (quality < 5) quality = 5; 480 | 481 | stbiw__sbpush(out, 0x78); // DEFLATE 32K window 482 | stbiw__sbpush(out, 0x5e); // FLEVEL = 1 483 | stbiw__zlib_add(1,1); // BFINAL = 1 484 | stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman 485 | 486 | for (i=0; i < stbiw__ZHASH; ++i) 487 | hash_table[i] = NULL; 488 | 489 | i=0; 490 | while (i < data_len-3) { 491 | // hash next 3 bytes of data to be compressed 492 | int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; 493 | unsigned char *bestloc = 0; 494 | unsigned char **hlist = hash_table[h]; 495 | int n = stbiw__sbcount(hlist); 496 | for (j=0; j < n; ++j) { 497 | if (hlist[j]-data > i-32768) { // if entry lies within window 498 | int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); 499 | if (d >= best) best=d,bestloc=hlist[j]; 500 | } 501 | } 502 | // when hash table entry is too long, delete half the entries 503 | if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { 504 | STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); 505 | stbiw__sbn(hash_table[h]) = quality; 506 | } 507 | stbiw__sbpush(hash_table[h],data+i); 508 | 509 | if (bestloc) { 510 | // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal 511 | h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); 512 | hlist = hash_table[h]; 513 | n = stbiw__sbcount(hlist); 514 | for (j=0; j < n; ++j) { 515 | if (hlist[j]-data > i-32767) { 516 | int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); 517 | if (e > best) { // if next match is better, bail on current match 518 | bestloc = NULL; 519 | break; 520 | } 521 | } 522 | } 523 | } 524 | 525 | if (bestloc) { 526 | int d = (int) (data+i - bestloc); // distance back 527 | STBIW_ASSERT(d <= 32767 && best <= 258); 528 | for (j=0; best > lengthc[j+1]-1; ++j); 529 | stbiw__zlib_huff(j+257); 530 | if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); 531 | for (j=0; d > distc[j+1]-1; ++j); 532 | stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); 533 | if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); 534 | i += best; 535 | } else { 536 | stbiw__zlib_huffb(data[i]); 537 | ++i; 538 | } 539 | } 540 | // write out final bytes 541 | for (;i < data_len; ++i) 542 | stbiw__zlib_huffb(data[i]); 543 | stbiw__zlib_huff(256); // end of block 544 | // pad with 0 bits to byte boundary 545 | while (bitcount) 546 | stbiw__zlib_add(0,1); 547 | 548 | for (i=0; i < stbiw__ZHASH; ++i) 549 | (void) stbiw__sbfree(hash_table[i]); 550 | 551 | { 552 | // compute adler32 on input 553 | unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552; 554 | int j=0; 555 | while (j < data_len) { 556 | for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; 557 | s1 %= 65521, s2 %= 65521; 558 | j += blocklen; 559 | blocklen = 5552; 560 | } 561 | stbiw__sbpush(out, (unsigned char) (s2 >> 8)); 562 | stbiw__sbpush(out, (unsigned char) s2); 563 | stbiw__sbpush(out, (unsigned char) (s1 >> 8)); 564 | stbiw__sbpush(out, (unsigned char) s1); 565 | } 566 | *out_len = stbiw__sbn(out); 567 | // make returned pointer freeable 568 | STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); 569 | return (unsigned char *) stbiw__sbraw(out); 570 | } 571 | 572 | unsigned int stbiw__crc32(unsigned char *buffer, int len) 573 | { 574 | static unsigned int crc_table[256]; 575 | unsigned int crc = ~0u; 576 | int i,j; 577 | if (crc_table[1] == 0) 578 | for(i=0; i < 256; i++) 579 | for (crc_table[i]=i, j=0; j < 8; ++j) 580 | crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0); 581 | for (i=0; i < len; ++i) 582 | crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; 583 | return ~crc; 584 | } 585 | 586 | #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4) 587 | #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); 588 | #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) 589 | 590 | static void stbiw__wpcrc(unsigned char **data, int len) 591 | { 592 | unsigned int crc = stbiw__crc32(*data - len - 4, len+4); 593 | stbiw__wp32(*data, crc); 594 | } 595 | 596 | static unsigned char stbiw__paeth(int a, int b, int c) 597 | { 598 | int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); 599 | if (pa <= pb && pa <= pc) return (unsigned char) a; 600 | if (pb <= pc) return (unsigned char) b; 601 | return (unsigned char) c; 602 | } 603 | 604 | unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) 605 | { 606 | int ctype[5] = { -1, 0, 4, 2, 6 }; 607 | unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; 608 | unsigned char *out,*o, *filt, *zlib; 609 | signed char *line_buffer; 610 | int i,j,k,p,zlen; 611 | 612 | if (stride_bytes == 0) 613 | stride_bytes = x * n; 614 | 615 | filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; 616 | line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } 617 | for (j=0; j < y; ++j) { 618 | static int mapping[] = { 0,1,2,3,4 }; 619 | static int firstmap[] = { 0,1,0,5,6 }; 620 | int *mymap = j ? mapping : firstmap; 621 | int best = 0, bestval = 0x7fffffff; 622 | for (p=0; p < 2; ++p) { 623 | for (k= p?best:0; k < 5; ++k) { 624 | int type = mymap[k],est=0; 625 | unsigned char *z = pixels + stride_bytes*j; 626 | for (i=0; i < n; ++i) 627 | switch (type) { 628 | case 0: line_buffer[i] = z[i]; break; 629 | case 1: line_buffer[i] = z[i]; break; 630 | case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; 631 | case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; 632 | case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break; 633 | case 5: line_buffer[i] = z[i]; break; 634 | case 6: line_buffer[i] = z[i]; break; 635 | } 636 | for (i=n; i < x*n; ++i) { 637 | switch (type) { 638 | case 0: line_buffer[i] = z[i]; break; 639 | case 1: line_buffer[i] = z[i] - z[i-n]; break; 640 | case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; 641 | case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; 642 | case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; 643 | case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; 644 | case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; 645 | } 646 | } 647 | if (p) break; 648 | for (i=0; i < x*n; ++i) 649 | est += abs((signed char) line_buffer[i]); 650 | if (est < bestval) { bestval = est; best = k; } 651 | } 652 | } 653 | // when we get here, best contains the filter type, and line_buffer contains the data 654 | filt[j*(x*n+1)] = (unsigned char) best; 655 | STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); 656 | } 657 | STBIW_FREE(line_buffer); 658 | zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory 659 | STBIW_FREE(filt); 660 | if (!zlib) return 0; 661 | 662 | // each tag requires 12 bytes of overhead 663 | out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); 664 | if (!out) return 0; 665 | *out_len = 8 + 12+13 + 12+zlen + 12; 666 | 667 | o=out; 668 | STBIW_MEMMOVE(o,sig,8); o+= 8; 669 | stbiw__wp32(o, 13); // header length 670 | stbiw__wptag(o, "IHDR"); 671 | stbiw__wp32(o, x); 672 | stbiw__wp32(o, y); 673 | *o++ = 8; 674 | *o++ = (unsigned char) ctype[n]; 675 | *o++ = 0; 676 | *o++ = 0; 677 | *o++ = 0; 678 | stbiw__wpcrc(&o,13); 679 | 680 | stbiw__wp32(o, zlen); 681 | stbiw__wptag(o, "IDAT"); 682 | STBIW_MEMMOVE(o, zlib, zlen); 683 | o += zlen; 684 | STBIW_FREE(zlib); 685 | stbiw__wpcrc(&o, zlen); 686 | 687 | stbiw__wp32(o,0); 688 | stbiw__wptag(o, "IEND"); 689 | stbiw__wpcrc(&o,0); 690 | 691 | STBIW_ASSERT(o == out + *out_len); 692 | 693 | return out; 694 | } 695 | 696 | int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) 697 | { 698 | FILE *f; 699 | int len; 700 | unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); 701 | if (!png) return 0; 702 | f = fopen(filename, "wb"); 703 | if (!f) { STBIW_FREE(png); return 0; } 704 | fwrite(png, 1, len, f); 705 | fclose(f); 706 | STBIW_FREE(png); 707 | return 1; 708 | } 709 | #endif // STB_IMAGE_WRITE_IMPLEMENTATION 710 | 711 | /* Revision history 712 | 0.98 (2015-04-08) 713 | added STBIW_MALLOC, STBIW_ASSERT etc 714 | 0.97 (2015-01-18) 715 | fixed HDR asserts, rewrote HDR rle logic 716 | 0.96 (2015-01-17) 717 | add HDR output 718 | fix monochrome BMP 719 | 0.95 (2014-08-17) 720 | add monochrome TGA output 721 | 0.94 (2014-05-31) 722 | rename private functions to avoid conflicts with stb_image.h 723 | 0.93 (2014-05-27) 724 | warning fixes 725 | 0.92 (2010-08-01) 726 | casts to unsigned char to fix warnings 727 | 0.91 (2010-07-17) 728 | first public release 729 | 0.90 first internal release 730 | */ 731 | -------------------------------------------------------------------------------- /_old/tut0.cc: -------------------------------------------------------------------------------- 1 | // Just a sample, brought from https://github.com/glfw/glfw/blob/master/examples/simple.c 2 | 3 | //======================================================================== 4 | // Simple GLFW example 5 | // Copyright (c) Camilla Berglund 6 | // 7 | // This software is provided 'as-is', without any express or implied 8 | // warranty. In no event will the authors be held liable for any damages 9 | // arising from the use of this software. 10 | // 11 | // Permission is granted to anyone to use this software for any purpose, 12 | // including commercial applications, and to alter it and redistribute it 13 | // freely, subject to the following restrictions: 14 | // 15 | // 1. The origin of this software must not be misrepresented; you must not 16 | // claim that you wrote the original software. If you use this software 17 | // in a product, an acknowledgment in the product documentation would 18 | // be appreciated but is not required. 19 | // 20 | // 2. Altered source versions must be plainly marked as such, and must not 21 | // be misrepresented as being the original software. 22 | // 23 | // 3. This notice may not be removed or altered from any source 24 | // distribution. 25 | // 26 | //======================================================================== 27 | //! [code] 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | static void error_callback(int error, const char* description) 35 | { 36 | fputs(description, stderr); 37 | } 38 | 39 | static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) 40 | { 41 | if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) 42 | glfwSetWindowShouldClose(window, GL_TRUE); 43 | } 44 | 45 | int main(void) 46 | { 47 | GLFWwindow* window; 48 | 49 | glfwSetErrorCallback(error_callback); 50 | 51 | if (!glfwInit()) 52 | exit(EXIT_FAILURE); 53 | 54 | window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL); 55 | if (!window) 56 | { 57 | glfwTerminate(); 58 | exit(EXIT_FAILURE); 59 | } 60 | 61 | glfwMakeContextCurrent(window); 62 | 63 | glfwSetKeyCallback(window, key_callback); 64 | 65 | while (!glfwWindowShouldClose(window)) 66 | { 67 | float ratio; 68 | int width, height; 69 | 70 | glfwGetFramebufferSize(window, &width, &height); 71 | ratio = width / (float) height; 72 | 73 | glViewport(0, 0, width, height); 74 | glClear(GL_COLOR_BUFFER_BIT); 75 | 76 | glMatrixMode(GL_PROJECTION); 77 | glLoadIdentity(); 78 | glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f); 79 | glMatrixMode(GL_MODELVIEW); 80 | 81 | glLoadIdentity(); 82 | glRotatef((float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f); 83 | 84 | glBegin(GL_TRIANGLES); 85 | glColor3f(1.f, 0.f, 0.f); 86 | glVertex3f(-0.6f, -0.4f, 0.f); 87 | glColor3f(0.f, 1.f, 0.f); 88 | glVertex3f(0.6f, -0.4f, 0.f); 89 | glColor3f(0.f, 0.f, 1.f); 90 | glVertex3f(0.f, 0.6f, 0.f); 91 | glEnd(); 92 | 93 | glfwSwapBuffers(window); 94 | glfwPollEvents(); 95 | } 96 | 97 | glfwDestroyWindow(window); 98 | 99 | glfwTerminate(); 100 | exit(EXIT_SUCCESS); 101 | } 102 | 103 | //! [code] -------------------------------------------------------------------------------- /_old/tut1.cc: -------------------------------------------------------------------------------- 1 | // Simple harfbuzz, it is not best practice nor right way to do text rendering using harfbuzz/ft 2 | // there are more superior sample on the net, you should look at for a real example 3 | // Ebrahim Byagowi 4 | #include 5 | 6 | #include 7 | #include FT_FREETYPE_H 8 | #include FT_GLYPH_H 9 | 10 | #include 11 | #include 12 | 13 | // Simple pixel copy code brought from http://www.freetype.org/freetype2/docs/tutorial/example1.c 14 | void drawBitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y, unsigned char* image, int width, int height) { 15 | FT_Int i, j, p, q; 16 | FT_Int x_max = x + bitmap->width; 17 | FT_Int y_max = y + bitmap->rows; 18 | 19 | for (i = x, p = 0; i < x_max; i++, p++) { 20 | for (j = y, q = 0; j < y_max; j++, q++) { 21 | if (i < 0 || j < 0 || 22 | i >= width || j >= height) 23 | continue; 24 | 25 | image[j * width + i] |= bitmap->buffer[q * bitmap->width + p]; 26 | } 27 | } 28 | } 29 | 30 | int main() { 31 | // Initialize freetype 32 | FT_Library library; 33 | FT_Init_FreeType(&library); 34 | 35 | // Initialize the font face 36 | FT_Face face; 37 | FT_New_Face(library, 38 | // Just for sake of simplicity 39 | #if defined(__linux__) 40 | "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 41 | #elif defined(_WIN32) || defined(_WIN64) 42 | "C:\\Windows\\Fonts\\tahoma.ttf", 43 | #elif __APPLE__ 44 | "/Library/Fonts/Tahoma.ttf", 45 | #endif 46 | 0, 47 | &face); 48 | 49 | FT_Set_Char_Size(face, 0, 100 * 64, 72, 72); 50 | 51 | // Configure harfbuzz buffer and shape 52 | hb_font_t *font = hb_ft_font_create(face, NULL); 53 | hb_buffer_t *buf = hb_buffer_create(); 54 | hb_buffer_set_direction(buf, HB_DIRECTION_RTL); 55 | hb_buffer_set_script(buf, HB_SCRIPT_ARABIC); // see hb-unicode.h 56 | // hb_buffer_set_language(buf, hb_language_from_string("ar", 2)); // for language specific font features 57 | const char *text = "فرآیند"; // Sample Arabic text 58 | hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); 59 | hb_shape(font, buf, NULL, 0); // Shaping magic happens here 60 | 61 | // Drawing 62 | unsigned int glyphCount; 63 | hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(buf, &glyphCount); 64 | hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions(buf, &glyphCount); 65 | 66 | // this is not a good assumption specially when there is GPOS on the font 67 | int height = face->size->metrics.height / 64; 68 | int width = 0; 69 | // doing width measuring just based shaper glyphs advances is not good assumption either 70 | for (int i = 0; i < glyphCount; ++i) { width += glyphPositions[i].x_advance; } 71 | width /= 64; 72 | unsigned char* image = (unsigned char*)calloc(width * height, sizeof(char)); 73 | FT_GlyphSlot slot = face->glyph; 74 | int x = 0, y = face->size->metrics.ascender / 64; 75 | for (int i = 0; i < glyphCount; ++i) { 76 | FT_Load_Glyph(face, glyphInfos[i].codepoint, FT_LOAD_DEFAULT); 77 | FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); 78 | 79 | drawBitmap(&slot->bitmap, 80 | x + (glyphPositions[i].x_offset / 64) + slot->bitmap_left, 81 | y - (glyphPositions[i].y_offset / 64) - slot->bitmap_top, 82 | image, width, height); 83 | 84 | x += glyphPositions[i].x_advance / 64; 85 | y -= glyphPositions[i].y_advance / 64; 86 | } 87 | 88 | // Saving as pbm file, Inkscape can open it 89 | FILE *f = fopen("out.pbm", "wb"); 90 | fprintf(f, "P5 %d %d %d\n", width, height, slot->bitmap.num_grays - 1); 91 | fwrite((const char *)image, sizeof(char), width * height, f); 92 | fclose(f); 93 | 94 | // Destroying things 95 | free(image); 96 | hb_buffer_clear_contents(buf); 97 | hb_buffer_destroy(buf); 98 | FT_Done_Face(face); 99 | FT_Done_FreeType(library); 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /_old/tut2.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/OpenGL_Programming 3 | * This file is in the public domain. 4 | * Contributors: Sylvain Beucler 5 | * 6 | * 7 | * Modified to use glfw instead glut 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | GLuint program; 15 | GLint attribute_coord2d; 16 | 17 | int init_resources() { 18 | GLint compile_ok = GL_FALSE, link_ok = GL_FALSE; 19 | 20 | GLuint vs = glCreateShader(GL_VERTEX_SHADER); 21 | const char *vs_source = 22 | #ifdef GL_ES_VERSION_2_0 23 | "#version 100\n" // OpenGL ES 2.0 24 | #else 25 | "#version 120\n" // OpenGL 2.1 26 | #endif 27 | "attribute vec2 coord2d; " 28 | "void main(void) { " 29 | " gl_Position = vec4(coord2d, 0.0, 1.0); " 30 | "}"; 31 | glShaderSource(vs, 1, &vs_source, NULL); 32 | glCompileShader(vs); 33 | glGetShaderiv(vs, GL_COMPILE_STATUS, &compile_ok); 34 | if (!compile_ok) { 35 | fprintf(stderr, "Error in vertex shader\n"); 36 | return 0; 37 | } 38 | 39 | GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); 40 | const char *fs_source = 41 | #ifdef GL_ES_VERSION_2_0 42 | "#version 100\n" // OpenGL ES 2.0 43 | #else 44 | "#version 120\n" // OpenGL 2.1 45 | #endif 46 | "void main(void) { " 47 | " gl_FragColor[0] = 0.0; " 48 | " gl_FragColor[1] = 0.0; " 49 | " gl_FragColor[2] = 1.0; " 50 | "}"; 51 | glShaderSource(fs, 1, &fs_source, NULL); 52 | glCompileShader(fs); 53 | glGetShaderiv(fs, GL_COMPILE_STATUS, &compile_ok); 54 | if (!compile_ok) { 55 | fprintf(stderr, "Error in fragment shader\n"); 56 | return 0; 57 | } 58 | 59 | program = glCreateProgram(); 60 | glAttachShader(program, vs); 61 | glAttachShader(program, fs); 62 | glLinkProgram(program); 63 | glGetProgramiv(program, GL_LINK_STATUS, &link_ok); 64 | if (!link_ok) { 65 | fprintf(stderr, "glLinkProgram:"); 66 | return 0; 67 | } 68 | 69 | const char* attribute_name = "coord2d"; 70 | attribute_coord2d = glGetAttribLocation(program, attribute_name); 71 | if (attribute_coord2d == -1) { 72 | fprintf(stderr, "Could not bind attribute %s\n", attribute_name); 73 | return 0; 74 | } 75 | 76 | return 1; 77 | } 78 | 79 | void free_resources() { 80 | glDeleteProgram(program); 81 | } 82 | 83 | int main(int argc, char* argv[]) { 84 | glfwInit(); 85 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); 86 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 87 | //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 88 | //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 89 | GLFWwindow* window = glfwCreateWindow(640, 480, "My First Triangle", NULL, NULL); 90 | 91 | glfwMakeContextCurrent(window); 92 | 93 | GLenum glew_status = glewInit(); 94 | if (glew_status != GLEW_OK) { 95 | fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status)); 96 | return 1; 97 | } 98 | 99 | if (!init_resources()) { 100 | return 1; 101 | } 102 | while (!glfwWindowShouldClose(window)) { 103 | 104 | glClearColor(1.0, 1.0, 1.0, 1.0); 105 | glClear(GL_COLOR_BUFFER_BIT); 106 | 107 | glUseProgram(program); 108 | glEnableVertexAttribArray(attribute_coord2d); 109 | GLfloat triangle_vertices[] = { 110 | 0.0, 0.8, 111 | -0.8, -0.8, 112 | 0.8, -0.8, 113 | }; 114 | /* Describe our vertices array to OpenGL (it can't guess its format automatically) */ 115 | glVertexAttribPointer( 116 | attribute_coord2d, // attribute 117 | 2, // number of elements per vertex, here (x,y) 118 | GL_FLOAT, // the type of each element 119 | GL_FALSE, // take our values as-is 120 | 0, // no extra data between each position 121 | triangle_vertices // pointer to the C array 122 | ); 123 | 124 | /* Push each element in buffer_vertices to the vertex shader */ 125 | glDrawArrays(GL_TRIANGLES, 0, 3); 126 | 127 | glDisableVertexAttribArray(attribute_coord2d); 128 | 129 | 130 | glfwSwapBuffers(window); 131 | glfwPollEvents(); 132 | } 133 | 134 | free_resources(); 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /_old/tut3.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | // Init glfw 8 | glfwInit(); 9 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 10 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 11 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 12 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 13 | GLFWwindow *window = glfwCreateWindow(640, 460, "Hello Triangle", NULL, NULL); 14 | glfwMakeContextCurrent(window); 15 | printf("Renderer: %s\nOpenGL version %s\n", glGetString(GL_RENDERER), glGetString(GL_VERSION)); 16 | 17 | // Init glew 18 | glewExperimental = GL_TRUE; 19 | glewInit(); 20 | 21 | // On fragments overlap, just draw nearest one 22 | glEnable(GL_DEPTH_TEST); 23 | glDepthFunc(GL_LESS); 24 | 25 | // Rendering 26 | float points[] = { 27 | 0.0f, 0.5f, 0.0f, 28 | 0.5f, -0.5f, 0.0f, 29 | -0.5f, -0.5f, 0.0f 30 | }; 31 | 32 | GLuint vbo; 33 | glGenBuffers(1, &vbo); 34 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 35 | glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), points, GL_STATIC_DRAW); 36 | 37 | GLuint vao; 38 | glGenVertexArrays(1, &vao); 39 | glBindVertexArray(vao); 40 | glEnableVertexAttribArray(0); 41 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 42 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); 43 | 44 | const char* vertex_shader = 45 | "#version 400\n" 46 | "in vec3 vp;" 47 | "uniform float a;" 48 | "void main () {" 49 | " gl_Position = vec4 (vp.x, vp.y - sin(a), vp.z, 1.0);" 50 | "}"; 51 | 52 | const char* fragment_shader = 53 | "#version 400\n" 54 | "out vec4 frag_colour;" 55 | "void main () {" 56 | " frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);" 57 | "}"; 58 | 59 | GLuint vs = glCreateShader(GL_VERTEX_SHADER); 60 | glShaderSource(vs, 1, &vertex_shader, NULL); 61 | glCompileShader(vs); 62 | GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); 63 | glShaderSource(fs, 1, &fragment_shader, NULL); 64 | glCompileShader(fs); 65 | 66 | GLuint shader_programme = glCreateProgram(); 67 | glAttachShader(shader_programme, fs); 68 | glAttachShader(shader_programme, vs); 69 | glLinkProgram(shader_programme); 70 | 71 | 72 | GLint a = glGetUniformLocation(shader_programme, "a"); 73 | GLfloat b = 0; 74 | //glUniform1f(a, b); 75 | 76 | 77 | while (!glfwWindowShouldClose(window)) { 78 | // wipe the drawing surface clear 79 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 80 | glUseProgram(shader_programme); 81 | glBindVertexArray(vao); 82 | 83 | // draw points 0-3 from the currently bound VAO with current in-use shader 84 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); 85 | // update other events like input handling 86 | glfwPollEvents(); 87 | 88 | if (glfwGetKey(window, GLFW_KEY_S)) { 89 | b += .01; 90 | glUniform1f(a, b); 91 | } 92 | 93 | // put the stuff we've been drawing onto the display 94 | glfwSwapBuffers(window); 95 | } 96 | 97 | // Terminate 98 | glfwTerminate(); 99 | return 0; 100 | } -------------------------------------------------------------------------------- /_old/tut4.cc: -------------------------------------------------------------------------------- 1 | // Very simple CPAL/COLR sample 2 | // Ebrahim Byagowi 3 | #include 4 | 5 | #include 6 | #include FT_FREETYPE_H 7 | #include FT_GLYPH_H 8 | 9 | #include 10 | #include 11 | 12 | #define STB_IMAGE_WRITE_IMPLEMENTATION 13 | #include "stb_image_write.h" 14 | 15 | // from harfbuzz 16 | static inline uint16_t hb_uint16_swap(const uint16_t v) 17 | { 18 | return (v >> 8) | (v << 8); 19 | } 20 | static inline uint32_t hb_uint32_swap(const uint32_t v) 21 | { 22 | return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); 23 | } 24 | 25 | // from Mozilla Firefox, https://bug908503.bmoattachments.org/attachment.cgi?id=8424620 26 | #pragma pack(1) 27 | struct COLRBaseGlyphRecord { 28 | uint16_t glyphId; 29 | uint16_t firstLayerIndex; 30 | uint16_t numLayers; 31 | }; 32 | 33 | struct COLRLayerRecord { 34 | uint16_t glyphId; 35 | uint16_t paletteEntryIndex; 36 | }; 37 | 38 | struct CPALColorRecord { 39 | uint8_t blue; 40 | uint8_t green; 41 | uint8_t red; 42 | uint8_t alpha; 43 | }; 44 | 45 | struct COLRHeader { 46 | uint16_t version; 47 | uint16_t numBaseGlyphRecord; 48 | uint32_t offsetBaseGlyphRecord; 49 | uint32_t offsetLayerRecord; 50 | uint16_t numLayerRecords; 51 | }; 52 | 53 | struct CPALHeaderVersion0 { 54 | uint16_t version; 55 | uint16_t numPaletteEntries; 56 | uint16_t numPalettes; 57 | uint16_t numColorRecords; 58 | uint32_t offsetFirstColorRecord; 59 | }; 60 | #pragma pack() 61 | 62 | static int 63 | CompareBaseGlyph(const void* key, const void* data) 64 | { 65 | uint32_t glyphId = (uint32_t)(uintptr_t)key; 66 | auto baseGlyph = (COLRBaseGlyphRecord*)data; 67 | uint16_t baseGlyphId = hb_uint16_swap((uint16_t)(baseGlyph->glyphId)); 68 | 69 | if (baseGlyphId == glyphId) { 70 | return 0; 71 | } 72 | 73 | return baseGlyphId > glyphId ? -1 : 1; 74 | } 75 | 76 | void GetColorLayersInfo(hb_face_t *face, 77 | uint32_t glyphId, 78 | uint16_t* layerGlyphs[], 79 | uint32_t* layerColors[], 80 | int* layers) 81 | { 82 | COLRHeader* colr = (COLRHeader*)hb_blob_get_data( 83 | hb_face_reference_table(face, hb_tag_from_string("COLR", -1)), 0); 84 | CPALHeaderVersion0* cpal = (CPALHeaderVersion0*)hb_blob_get_data( 85 | hb_face_reference_table(face, hb_tag_from_string("CPAL", -1)), 0); 86 | 87 | const uint8_t* baseGlyphRecords = 88 | (const uint8_t*)colr + uint32_t(hb_uint32_swap(colr->offsetBaseGlyphRecord)); 89 | // BaseGlyphRecord is sorted by glyphId 90 | COLRBaseGlyphRecord* baseGlyph = (COLRBaseGlyphRecord*)bsearch( 91 | (void*)(uintptr_t)glyphId, 92 | baseGlyphRecords, 93 | uint16_t(hb_uint16_swap(colr->numBaseGlyphRecord)), 94 | sizeof(COLRBaseGlyphRecord), 95 | CompareBaseGlyph); 96 | 97 | const COLRLayerRecord* layer = (COLRLayerRecord*)(((uint8_t*)colr) + 98 | uint32_t(hb_uint32_swap(colr->offsetLayerRecord)) + 99 | sizeof(COLRLayerRecord) * uint16_t(hb_uint16_swap(baseGlyph->firstLayerIndex))); 100 | const uint16_t numLayers = hb_uint16_swap(baseGlyph->numLayers); 101 | const uint32_t offsetFirstColorRecord = hb_uint32_swap(cpal->offsetFirstColorRecord); 102 | 103 | *layerGlyphs = (uint16_t*)malloc(numLayers * sizeof(uint16_t)); 104 | *layerColors = (uint32_t*)malloc(numLayers * sizeof(uint32_t)); 105 | *layers = numLayers; 106 | 107 | for (uint16_t layerIndex = 0; layerIndex < numLayers; layerIndex++) { 108 | (*layerGlyphs)[layerIndex] = hb_uint16_swap(layer->glyphId); 109 | CPALColorRecord* color = (CPALColorRecord*)(((uint8_t*)cpal) + 110 | offsetFirstColorRecord + 111 | sizeof(CPALColorRecord) * hb_uint16_swap(layer->paletteEntryIndex)); 112 | (*layerColors)[layerIndex] = (uint32_t)color->red + (color->green << 8) 113 | + (color->blue << 16) + (color->alpha << 24); 114 | layer++; 115 | } 116 | } 117 | 118 | // Simple pixel copy code brought from http://www.freetype.org/freetype2/docs/tutorial/example1.c 119 | inline void drawBitmap(FT_Bitmap* bitmap, FT_Int x, FT_Int y, unsigned char* image, int width, int height, uint32_t color) { 120 | FT_Int i, j, p, q; 121 | FT_Int x_max = x + bitmap->width; 122 | FT_Int y_max = y + bitmap->rows; 123 | 124 | int r = color & 0xFF; 125 | int g = (color >> 8) & 0xFF; 126 | int b = (color >> 16) & 0xFF; 127 | int a = (color >> 24) & 0xFF; 128 | 129 | for (i = x, p = 0; i < x_max; i++, p++) { 130 | for (j = y, q = 0; j < y_max; j++, q++) { 131 | if (i < 0 || j < 0 || 132 | i >= width || j >= height) 133 | continue; 134 | 135 | image[4 * j * width + i * 4 + 0] |= bitmap->buffer[q * bitmap->width + p] * r / 256; 136 | image[4 * j * width + i * 4 + 1] |= bitmap->buffer[q * bitmap->width + p] * g / 256; 137 | image[4 * j * width + i * 4 + 2] |= bitmap->buffer[q * bitmap->width + p] * b / 256; 138 | image[4 * j * width + i * 4 + 3] |= bitmap->buffer[q * bitmap->width + p] * a / 256; 139 | } 140 | } 141 | } 142 | 143 | int main() { 144 | // Initialize freetype 145 | FT_Library library; 146 | FT_Init_FreeType(&library); 147 | 148 | // Initialize the font face 149 | FT_Face face; 150 | FT_New_Face(library, 151 | #if defined(_WIN32) || defined(_WIN64) 152 | "C:\\Windows\\Fonts\\seguiemj.ttf", 153 | #else 154 | "seguiemj.ttf", 155 | #endif 156 | 0, 157 | &face); 158 | 159 | FT_Set_Char_Size(face, 0, 256 * 64, 72, 72); 160 | 161 | // Configure harfbuzz buffer and shape 162 | hb_font_t *hb_font = hb_ft_font_create(face, NULL); 163 | hb_face_t *hb_face = hb_font_get_face(hb_font); 164 | hb_buffer_t *buf; 165 | const char *text = "🍔🍕🍖🍗🍘🍙🍚🍛🍜🍝"; // Emoji sequence 166 | buf = hb_buffer_create(); 167 | hb_buffer_set_direction(buf, HB_DIRECTION_LTR); 168 | hb_buffer_set_language(buf, hb_language_from_string("fa", 2)); 169 | hb_buffer_set_script(buf, HB_SCRIPT_COMMON); 170 | hb_buffer_add_utf8(buf, text, strlen(text), 0, -1); 171 | hb_shape(hb_font, buf, 0, 0); 172 | 173 | unsigned int glyphCount; 174 | 175 | hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(buf, &glyphCount); 176 | hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions(buf, &glyphCount); 177 | 178 | // this is not a good assumption specially when there is GPOS on the font 179 | int height = face->size->metrics.height / 64; 180 | int width = 0; 181 | // doing width measuring just based shaper glyphs advances is not good assumption either 182 | for (int i = 0; i < glyphCount; ++i) { width += glyphPositions[i].x_advance; } 183 | width /= 64; 184 | unsigned char* image = (unsigned char*)calloc(width * height * 16, sizeof(char)); 185 | FT_GlyphSlot slot = face->glyph; 186 | int x = 0, y = face->size->metrics.ascender / 64; 187 | for (int i = 0; i < glyphCount; ++i) { 188 | uint16_t* layerGlyphs = NULL; 189 | uint32_t* layerColors = NULL; 190 | int layers; 191 | GetColorLayersInfo(hb_face, glyphInfos[i].codepoint, &layerGlyphs, &layerColors, &layers); 192 | for (int n = 0; n < layers; ++n) { 193 | FT_Load_Glyph(face, layerGlyphs[n], FT_LOAD_DEFAULT); 194 | FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); 195 | drawBitmap(&slot->bitmap, 196 | x + (glyphPositions[i].x_offset / 64) + slot->bitmap_left, 197 | y - (glyphPositions[i].y_offset / 64) - slot->bitmap_top, 198 | image, width, height, layerColors[n]); 199 | int a = 2; 200 | } 201 | 202 | x += glyphPositions[i].x_advance / 64; 203 | y -= glyphPositions[i].y_advance / 64; 204 | } 205 | 206 | stbi_write_png("out.png", width, height, 1 * 4, image, 0); 207 | 208 | // Destroying things 209 | free(image); 210 | hb_buffer_clear_contents(buf); 211 | hb_buffer_destroy(buf); 212 | FT_Done_Face(face); 213 | FT_Done_FreeType(library); 214 | 215 | return 0; 216 | } 217 | -------------------------------------------------------------------------------- /_old/xcodeinit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -o errexit 3 | set -o pipefail 4 | set -o nounset 5 | # set -o xtrace 6 | 7 | [ -d freetype2 ] || git clone --depth=1 http://git.savannah.nongnu.org/r/freetype/freetype2.git/ 8 | [ -d glfw ] || git clone --depth=1 https://github.com/glfw/glfw 9 | [ -d glew ] || git clone --depth=1 https://github.com/omniavinco/glew-cmake glew 10 | [ -d harfbuzz ] || git clone --depth=1 https://github.com/behdad/harfbuzz 11 | for f in freetype2 glfw glew harfbuzz; do cd $f; git pull; cd ..; done 12 | 13 | rm -rf build 14 | mkdir build 15 | cd build 16 | cmake -G Xcode ../ 17 | open glcourse.xcodeproj 18 | cd .. 19 | -------------------------------------------------------------------------------- /cairo-draw.c: -------------------------------------------------------------------------------- 1 | // gcc cairo-draw.c `pkg-config --libs --cflags cairo` -Wall && ./a.outs 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | cairo_surface_t *cairo_surface = 8 | cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 150); 9 | cairo_t *cr = cairo_create(cairo_surface); 10 | 11 | cairo_set_source_rgb(cr, .3, .7, .2); 12 | cairo_set_line_width(cr, 10); 13 | cairo_move_to(cr, 20, 20); 14 | cairo_line_to(cr, 20, 130); 15 | cairo_line_to(cr, 180, 20); 16 | cairo_stroke(cr); 17 | 18 | cairo_destroy(cr); 19 | cairo_surface_write_to_png(cairo_surface, "out.png"); 20 | cairo_surface_destroy(cairo_surface); 21 | } 22 | -------------------------------------------------------------------------------- /curl-download.c: -------------------------------------------------------------------------------- 1 | // gcc curl-download.c `pkg-config --libs --cflags libcurl` -Wall && ./a.out 2 | #include 3 | #include 4 | 5 | size_t print_func(void *ptr, size_t size /*always==1*/, size_t nmemb, 6 | void *userdata) { 7 | printf("%.*s", (unsigned)nmemb, (unsigned char *)ptr); 8 | return nmemb; 9 | } 10 | 11 | int main(void) { 12 | CURL *curl = curl_easy_init(); 13 | if (!curl) 14 | return 1; 15 | CURLcode res; 16 | curl_easy_setopt(curl, CURLOPT_URL, "https://ipinfo.io"); 17 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); 18 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &print_func); 19 | res = curl_easy_perform(curl); 20 | if (res != CURLE_OK) 21 | fprintf(stderr, "curl_easy_perform() failed: %s\n", 22 | curl_easy_strerror(res)); 23 | curl_easy_cleanup(curl); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /expat-parse.c: -------------------------------------------------------------------------------- 1 | // cc expat-parse.c `pkg-config --libs --cflags expat` -Wall && ./a.out 2 | // https://github.com/libexpat/libexpat/blob/master/expat/examples/outline.c 3 | 4 | #include 5 | 6 | #include 7 | 8 | #define BUFFSIZE 8192 9 | char Buff[BUFFSIZE]; 10 | 11 | int depth; 12 | 13 | static void XMLCALL start(void *data, const XML_Char *el, 14 | const XML_Char **attr) { 15 | for (unsigned i = 0; i < depth; i++) 16 | printf(" "); 17 | 18 | printf("<%s", el); 19 | 20 | for (unsigned i = 0; attr[i]; i += 2) { 21 | printf(" %s='%s'", attr[i], attr[i + 1]); 22 | } 23 | 24 | printf(">\n"); 25 | depth++; 26 | } 27 | 28 | static void XMLCALL end(void *data, const XML_Char *el) { depth--; } 29 | 30 | int main() { 31 | XML_Parser p = XML_ParserCreate(NULL); 32 | if (!p) { 33 | fprintf(stderr, "Couldn't allocate memory for parser\n"); 34 | exit(-1); 35 | } 36 | 37 | XML_SetElementHandler(p, start, end); 38 | 39 | for (;;) { 40 | int len = (int)fread(Buff, 1, BUFFSIZE, stdin); 41 | if (ferror(stdin)) { 42 | fprintf(stderr, "Read error\n"); 43 | exit(-1); 44 | } 45 | int done = feof(stdin); 46 | 47 | if (XML_Parse(p, Buff, len, done) == XML_STATUS_ERROR) { 48 | fprintf(stderr, "Parse error at line %ld:\n%s\n", 49 | XML_GetCurrentLineNumber(p), 50 | XML_ErrorString(XML_GetErrorCode(p))); 51 | exit(-1); 52 | } 53 | 54 | if (done) 55 | break; 56 | } 57 | XML_ParserFree(p); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /ffmpeg-frames.c: -------------------------------------------------------------------------------- 1 | // gcc ffmpeg-frames.c `pkg-config --cflags --libs libavutil libavformat` -Wall && ./a.out 2 | // https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/demuxing_decoding.c 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static AVCodecContext *video_dec_ctx = NULL; 9 | static int width, height; 10 | static enum AVPixelFormat pix_fmt; 11 | static AVStream *video_stream = NULL; 12 | 13 | static uint8_t *video_dst_data[4] = {NULL}; 14 | static int video_dst_linesize[4]; 15 | static int video_dst_bufsize; 16 | 17 | static int video_stream_idx = -1; 18 | static AVFrame *frame = NULL; 19 | static AVPacket pkt; 20 | 21 | void callback(uint8_t *ptr, unsigned len, unsigned width, unsigned height, unsigned pix_fmt); 22 | 23 | static int output_video_frame(AVFrame *frame) { 24 | if (frame->width != width || frame->height != height || 25 | frame->format != pix_fmt) { 26 | return -1; 27 | } 28 | av_image_copy(video_dst_data, video_dst_linesize, 29 | (const uint8_t **)(frame->data), frame->linesize, pix_fmt, 30 | width, height); 31 | callback(video_dst_data[0], video_dst_bufsize, width, height, pix_fmt); 32 | return 0; 33 | } 34 | 35 | static int decode_packet(AVCodecContext *dec, const AVPacket *pkt) { 36 | int ret = avcodec_send_packet(dec, pkt); 37 | if (ret < 0) { 38 | return ret; 39 | } 40 | while (ret >= 0) { 41 | ret = avcodec_receive_frame(dec, frame); 42 | if (ret < 0) { 43 | if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) 44 | return 0; 45 | return ret; 46 | } 47 | if (dec->codec->type == AVMEDIA_TYPE_VIDEO) 48 | ret = output_video_frame(frame); 49 | av_frame_unref(frame); 50 | if (ret < 0) 51 | return ret; 52 | } 53 | 54 | return 0; 55 | } 56 | 57 | static int open_codec_context(int *stream_idx, AVCodecContext **dec_ctx, 58 | AVFormatContext *fmt_ctx, enum AVMediaType type) { 59 | AVStream *st; 60 | AVCodec *dec = NULL; 61 | AVDictionary *opts = NULL; 62 | int ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); 63 | if (ret < 0) { 64 | return ret; 65 | } else { 66 | int stream_index = ret; 67 | st = fmt_ctx->streams[stream_index]; 68 | dec = avcodec_find_decoder(st->codecpar->codec_id); 69 | if (!dec) 70 | return AVERROR(EINVAL); 71 | *dec_ctx = avcodec_alloc_context3(dec); 72 | if (!*dec_ctx) 73 | return AVERROR(ENOMEM); 74 | if ((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) 75 | return ret; 76 | if ((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) 77 | return ret; 78 | *stream_idx = stream_index; 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | struct buffer_data { 85 | uint8_t *ptr; 86 | size_t size; 87 | }; 88 | 89 | static int read_packet(void *opaque, uint8_t *buf, int buf_size) { 90 | struct buffer_data *bd = (struct buffer_data *)opaque; 91 | buf_size = FFMIN(buf_size, bd->size); 92 | memcpy(buf, bd->ptr, buf_size); 93 | bd->ptr += buf_size; 94 | bd->size -= buf_size; 95 | return buf_size; 96 | } 97 | 98 | int decode(uint8_t *buf, unsigned len) { 99 | struct buffer_data buffer = {.ptr = buf, .size = len}; 100 | // probably not the best just that good enough for here 101 | uint8_t *file_stream_buffer = (uint8_t *)av_malloc(len); 102 | AVIOContext *io_context = 103 | avio_alloc_context(file_stream_buffer, len, 0, &buffer, 104 | read_packet, NULL, NULL); 105 | if (!io_context) 106 | abort(); 107 | AVFormatContext *fmt_ctx = avformat_alloc_context(); 108 | fmt_ctx->pb = io_context; 109 | fmt_ctx->flags |= AVFMT_FLAG_CUSTOM_IO; 110 | if (avformat_open_input(&fmt_ctx, "", 0, 0) < 0) 111 | abort(); 112 | if (avformat_find_stream_info(fmt_ctx, NULL) < 0) 113 | abort(); 114 | int ret = 0; 115 | if (open_codec_context(&video_stream_idx, &video_dec_ctx, fmt_ctx, 116 | AVMEDIA_TYPE_VIDEO) >= 0) { 117 | video_stream = fmt_ctx->streams[video_stream_idx]; 118 | width = video_dec_ctx->width; 119 | height = video_dec_ctx->height; 120 | pix_fmt = video_dec_ctx->pix_fmt; 121 | ret = av_image_alloc(video_dst_data, video_dst_linesize, width, height, 122 | pix_fmt, 1); 123 | if (ret < 0) 124 | goto end; 125 | video_dst_bufsize = ret; 126 | } 127 | if (!video_stream) { 128 | ret = 1; 129 | goto end; 130 | } 131 | frame = av_frame_alloc(); 132 | if (!frame) { 133 | ret = AVERROR(ENOMEM); 134 | goto end; 135 | } 136 | av_init_packet(&pkt); 137 | pkt.data = NULL; 138 | pkt.size = 0; 139 | while (av_read_frame(fmt_ctx, &pkt) >= 0) { 140 | if (pkt.stream_index == video_stream_idx) 141 | ret = decode_packet(video_dec_ctx, &pkt); 142 | av_packet_unref(&pkt); 143 | if (ret < 0) 144 | break; 145 | } 146 | if (video_dec_ctx) 147 | decode_packet(video_dec_ctx, NULL); 148 | 149 | end: 150 | avcodec_free_context(&video_dec_ctx); 151 | avformat_close_input(&fmt_ctx); 152 | av_frame_free(&frame); 153 | av_free(video_dst_data[0]); 154 | av_free(io_context); 155 | return ret < 0; 156 | } 157 | 158 | #ifndef NO_MAIN 159 | void callback(uint8_t *ptr, unsigned len, unsigned width, unsigned height, unsigned pix_fmt) { 160 | printf("%d %d %d %d: %d %d %d %d...\n", width, height, pix_fmt, len, ptr[0], ptr[1], ptr[2], ptr[3]); 161 | } 162 | int main() { 163 | uint8_t *buf; 164 | unsigned len; 165 | { 166 | FILE *f = fopen("input/test.mp4", "rb"); 167 | fseek(f, 0, SEEK_END); 168 | len = ftell(f); 169 | rewind(f); 170 | buf = (uint8_t *)malloc(len); 171 | len = fread(buf, 1, len, f); 172 | fclose(f); 173 | } 174 | decode(buf, len); 175 | free(buf); 176 | return 0; 177 | } 178 | #endif 179 | -------------------------------------------------------------------------------- /fontconfig-resolve.c: -------------------------------------------------------------------------------- 1 | // cc fontconfig-resolve.c `pkg-config --libs --cflags fontconfig` -Wall && ./a.out 2 | // https://gist.github.com/CallumDev/7c66b3f9cf7a876ef75f#gistcomment-3355764 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int main() { 9 | FcInit(); 10 | FcConfig *config = FcInitLoadConfigAndFonts(); 11 | 12 | // not necessarily has to be a specific name 13 | FcPattern *pat = FcNameParse((const FcChar8 *)"Arial"); 14 | 15 | // NECESSARY; it increases the scope of possible fonts 16 | FcConfigSubstitute(config, pat, FcMatchPattern); 17 | // NECESSARY; it increases the scope of possible fonts 18 | FcDefaultSubstitute(pat); 19 | 20 | char *fontFile; 21 | FcResult result; 22 | 23 | FcPattern *font = FcFontMatch(config, pat, &result); 24 | 25 | if (font) { 26 | FcChar8 *file = NULL; 27 | 28 | if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) { 29 | fontFile = (char *)file; 30 | printf("%s\n", fontFile); 31 | } 32 | } 33 | FcPatternDestroy(font); 34 | FcPatternDestroy(pat); 35 | FcConfigDestroy(config); 36 | FcFini(); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /freetype-render.c: -------------------------------------------------------------------------------- 1 | // gcc freetype-render.c `pkg-config --libs --cflags freetype2` -Wall && a.out 2 | #include 3 | #include 4 | 5 | #include 6 | #include FT_FREETYPE_H 7 | #include FT_GLYPH_H 8 | 9 | int main() { 10 | FT_Library library; 11 | FT_Init_FreeType(&library); 12 | FT_Face face; 13 | FT_New_Face(library, "input/Roboto.abc.ttf", 0, &face); 14 | FT_Set_Char_Size(face, 36 * 64, 36 * 64, 0, 0); 15 | 16 | FT_Load_Glyph(face, 2 /* gid=3 is 'b' in this particular font */, 17 | FT_LOAD_DEFAULT); 18 | 19 | FT_GlyphSlot slot = face->glyph; 20 | FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); 21 | 22 | unsigned width = slot->bitmap.width; 23 | unsigned height = slot->bitmap.rows; 24 | 25 | FILE *f = fopen("out.pbm", "wb"); 26 | fprintf(f, "P5 %d %d %d\n", width, height, slot->bitmap.num_grays - 1); 27 | fwrite(slot->bitmap.buffer, sizeof(char), width * height, f); 28 | fclose(f); 29 | 30 | FT_Done_Face(face); 31 | FT_Done_FreeType(library); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /fribidi-bidi.c: -------------------------------------------------------------------------------- 1 | // gcc fribidi-bidi.c `pkg-config --libs --cflags fribidi` -Wall && ./a.out 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main() { 8 | uint32_t str[] = U"abcششa234 سیبسی ۲۳۴ سیشبسبbc"; 9 | unsigned str_len = sizeof(str) / sizeof(uint32_t); 10 | 11 | FriBidiCharType *types = malloc(str_len * sizeof(FriBidiCharType)); 12 | FriBidiBracketType *btypes = malloc(str_len * sizeof(FriBidiBracketType)); 13 | FriBidiLevel *levels = malloc(str_len * sizeof(FriBidiLevel)); 14 | FriBidiParType pbase_dir; 15 | 16 | fribidi_get_bidi_types(str, str_len, types); 17 | fribidi_get_bracket_types(str, str_len, types, btypes); 18 | unsigned max_level = fribidi_get_par_embedding_levels_ex( 19 | types, btypes, str_len, &pbase_dir, levels); 20 | 21 | for (unsigned i = 0; i < str_len; ++i) 22 | printf(i ? ",%d" : "%d", levels[i]); 23 | 24 | // Result: 0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,0,0 25 | // Even numbers for LTR characters and odd numbers for RTL 26 | // Higher numbers mean they are in more inner levels 27 | 28 | printf("\nmax level: %d\n", max_level); 29 | 30 | free(types); 31 | free(btypes); 32 | free(levels); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /gtk4-gui.c: -------------------------------------------------------------------------------- 1 | // clang gtk4-gui.c `pkg-config --libs --cflags gtk4` -Wall && ./a.out 2 | // https://developer.gnome.org/gtk4/unstable/ch01s03.html#gtk-getting-started-grid-packing 3 | #include 4 | 5 | static void print_hello(GtkWidget *widget, gpointer data) { 6 | printf("Hello World\n"); 7 | } 8 | 9 | static void activate(GtkApplication *app, gpointer user_data) { 10 | GtkWidget *window = gtk_application_window_new(app); 11 | 12 | gtk_window_set_title(GTK_WINDOW(window), "Window"); 13 | GtkWidget *grid = gtk_grid_new(); 14 | gtk_window_set_child(GTK_WINDOW(window), grid); 15 | 16 | GtkWidget *button1 = gtk_button_new_with_label("Button 1"); 17 | g_signal_connect(button1, "clicked", G_CALLBACK(print_hello), NULL); 18 | gtk_grid_attach(GTK_GRID(grid), button1, 0, 0, 1, 1); 19 | // gtk_grid_attach(GtkGrid*, GtkWidget*, left, top, width, height); 20 | 21 | GtkWidget *button2 = gtk_button_new_with_label("Button 2"); 22 | g_signal_connect(button2, "clicked", G_CALLBACK(print_hello), NULL); 23 | gtk_grid_attach(GTK_GRID(grid), button2, 1, 0, 1, 1); 24 | 25 | GtkWidget *button3 = gtk_button_new_with_label("Quit"); 26 | g_signal_connect_swapped(button3, "clicked", G_CALLBACK(gtk_window_destroy), 27 | window); 28 | gtk_grid_attach(GTK_GRID(grid), button3, 0, 1, 2, 1); 29 | 30 | GtkWidget *label = gtk_label_new("\nHello World\n"); 31 | gtk_label_set_selectable(GTK_LABEL(label), TRUE); 32 | gtk_grid_attach(GTK_GRID(grid), label, 0, 2, 2, 1); 33 | 34 | gtk_widget_show(window); 35 | } 36 | 37 | int main(int argc, char **argv) { 38 | GtkApplication *app = 39 | gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE); 40 | g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); 41 | int status = g_application_run(G_APPLICATION(app), argc, argv); 42 | g_object_unref(app); 43 | return status; 44 | } 45 | -------------------------------------------------------------------------------- /harfbuzz-shape.c: -------------------------------------------------------------------------------- 1 | // gcc harfbuzz-shape.c `pkg-config --libs --cflags harfbuzz` -Wall && a.out 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main() { 8 | hb_blob_t *blob = hb_blob_create_from_file("input/Roboto.abc.ttf"); 9 | // or read the file yourself into buf and use, 10 | // hb_blob_create(buf, len, HB_MEMORY_MODE_WRITABLE, buf, free); 11 | hb_face_t *face = hb_face_create(blob, 0); 12 | hb_blob_destroy(blob); 13 | hb_font_t *font = hb_font_create(face); 14 | hb_face_destroy(face); 15 | 16 | // consider 36 as font size and 64 as subpixel percision 17 | hb_font_set_scale(font, 36 * 64, 36 * 64); 18 | 19 | hb_buffer_t *buffer = hb_buffer_create(); 20 | hb_buffer_add_utf8(buffer, "abc", -1, 0, -1); 21 | hb_buffer_guess_segment_properties(buffer); 22 | // or use these instead guess: 23 | // hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); 24 | // hb_buffer_set_script(buffer, HB_SCRIPT_LATIN); 25 | hb_shape(font, buffer, NULL, 0); 26 | 27 | unsigned len = hb_buffer_get_length(buffer); 28 | hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL); 29 | hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, NULL); 30 | 31 | double current_x = 0; 32 | double current_y = 0; 33 | for (unsigned int i = 0; i < len; i++) { 34 | char glyph_name[32]; 35 | hb_font_get_glyph_name(font, info[i].codepoint, glyph_name, 36 | sizeof(glyph_name)); 37 | double x_position = current_x + pos[i].x_offset / 64.; 38 | double y_position = current_y + pos[i].y_offset / 64.; 39 | printf("gid: %s (%d), position: (%g, %g), str index: %d\n", glyph_name, 40 | info[i].codepoint, x_position, y_position, info[i].cluster); 41 | current_x += pos[i].x_advance / 64.; 42 | current_y += pos[i].y_advance / 64.; 43 | } 44 | 45 | hb_font_destroy(font); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /icu4c-bidi.c: -------------------------------------------------------------------------------- 1 | 2 | // gcc icu4c-bidi.c `pkg-config --cflags --libs icu-i18n` -Wall && ./a.out 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int main() { 9 | UChar text[] = u"abcششa234 سیبسی ۲۳۴ سیشبسبbc"; 10 | unsigned length = sizeof(text) / sizeof(UChar); 11 | UErrorCode errorCode = U_ZERO_ERROR; 12 | UBiDi *para = ubidi_openSized(length, 0, &errorCode); 13 | if (!para) return 1; 14 | ubidi_setPara(para, text, length, UBIDI_DEFAULT_LTR, NULL, 15 | &errorCode); 16 | const UBiDiLevel *levels = ubidi_getLevels(para, &errorCode); 17 | if (U_FAILURE(errorCode)) return 1; 18 | for (unsigned i = 0; i < length; ++i) 19 | printf(i ? ",%d" : "%d", levels[i]); 20 | // Result: 0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,0,0 21 | // Even numbers for LTR characters and odd numbers for RTL 22 | // Higher numbers mean they are in more inner levels 23 | printf("\n"); 24 | ubidi_close(para); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /input/Roboto.abc.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebraminio/c-demos/d0c24136b7c52359250269aaf29402d49ab2ec1a/input/Roboto.abc.ttf -------------------------------------------------------------------------------- /input/example.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /input/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebraminio/c-demos/d0c24136b7c52359250269aaf29402d49ab2ec1a/input/test.png -------------------------------------------------------------------------------- /input/test.txt.zst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebraminio/c-demos/d0c24136b7c52359250269aaf29402d49ab2ec1a/input/test.txt.zst -------------------------------------------------------------------------------- /input/test.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebraminio/c-demos/d0c24136b7c52359250269aaf29402d49ab2ec1a/input/test.webp -------------------------------------------------------------------------------- /input/testorig.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebraminio/c-demos/d0c24136b7c52359250269aaf29402d49ab2ec1a/input/testorig.jpg -------------------------------------------------------------------------------- /libjpeg-decode.c: -------------------------------------------------------------------------------- 1 | // clang libjpeg-decode.c `pkg-config --libs --cflags libturbojpeg` -Wall && ./a.out 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | uint8_t *decode(uint8_t *buf, unsigned buf_size, unsigned *width, 10 | unsigned *height) { 11 | struct jpeg_decompress_struct cinfo; 12 | jpeg_create_decompress(&cinfo); 13 | jpeg_mem_src(&cinfo, buf, buf_size); 14 | struct jpeg_error_mgr jerr; 15 | cinfo.err = jpeg_std_error(&jerr); 16 | jpeg_read_header(&cinfo, TRUE); 17 | jpeg_start_decompress(&cinfo); 18 | *width = cinfo.output_width; 19 | *height = cinfo.output_height; 20 | int row_stride = cinfo.output_width * cinfo.output_components; 21 | (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1); 22 | uint8_t *result = (uint8_t *)malloc(cinfo.output_height * row_stride); 23 | while (cinfo.output_scanline < cinfo.output_height) { 24 | uint8_t *buffer_array = result + (cinfo.output_scanline) * row_stride; 25 | jpeg_read_scanlines(&cinfo, &buffer_array, 1); 26 | } 27 | jpeg_finish_decompress(&cinfo); 28 | jpeg_destroy_decompress(&cinfo); 29 | return result; 30 | } 31 | 32 | int main() { 33 | uint8_t *buf; 34 | unsigned len; 35 | { 36 | FILE *f = fopen("input/testorig.jpg", "rb"); 37 | fseek(f, 0, SEEK_END); 38 | len = ftell(f); 39 | rewind(f); 40 | buf = (uint8_t *)malloc(len); 41 | len = fread(buf, 1, len, f); 42 | fclose(f); 43 | } 44 | unsigned width, height; 45 | uint8_t *image = decode(buf, len, &width, &height); 46 | free(buf); 47 | { 48 | FILE *f = fopen("out.pbm", "wb"); 49 | fprintf(f, "P6 %d %d 255\n", width, height); 50 | fwrite(image, sizeof(char), width * height * 3, f); 51 | fclose(f); 52 | } 53 | free(image); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /libpng-decode.c: -------------------------------------------------------------------------------- 1 | // gcc libpng-decode.c `pkg-config --libs --cflags libpng` -Wall && ./a.out 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | typedef struct { 10 | uint8_t *buf; 11 | unsigned len; 12 | unsigned location; 13 | } png_memory_reader; 14 | 15 | void read_function(png_structp ps, png_bytep data, png_size_t length) { 16 | png_memory_reader *reader = png_get_io_ptr(ps); 17 | memcpy(data, reader->buf + reader->location, 18 | reader->location + length <= reader->len ? length : 0); 19 | reader->location += length; 20 | } 21 | 22 | uint8_t *decode(uint8_t *buf, unsigned buf_size, uint32_t *width, 23 | uint32_t *height, int *color_type) { 24 | if (png_sig_cmp(buf, 0, 8)) 25 | abort(); 26 | png_structp png_ptr = 27 | png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 28 | png_infop info_ptr = png_create_info_struct(png_ptr); 29 | if (setjmp(png_jmpbuf(png_ptr))) 30 | abort(); 31 | 32 | png_memory_reader memory_reader = { 33 | .location = 0, .buf = buf, .len = buf_size}; 34 | png_set_read_fn(png_ptr, &memory_reader, read_function); 35 | png_read_info(png_ptr, info_ptr); 36 | 37 | png_get_IHDR(png_ptr, info_ptr, width, height, NULL, color_type, NULL, NULL, 38 | NULL); 39 | png_set_expand(png_ptr); 40 | png_set_strip_16(png_ptr); 41 | png_set_gray_to_rgb(png_ptr); 42 | png_set_interlace_handling(png_ptr); 43 | 44 | png_read_update_info(png_ptr, info_ptr); 45 | 46 | if (setjmp(png_jmpbuf(png_ptr))) 47 | abort(); 48 | 49 | png_bytep *row_pointers = malloc(sizeof(png_bytep) * *height); 50 | unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr); 51 | uint8_t *result = malloc(rowbytes * *height); 52 | for (unsigned y = 0; y < *height; ++y) 53 | row_pointers[y] = result + rowbytes * y; 54 | 55 | png_read_image(png_ptr, row_pointers); 56 | png_read_end(png_ptr, NULL); 57 | 58 | return result; 59 | } 60 | 61 | int main(int argc, char **argv) { 62 | uint8_t *buf; 63 | unsigned len; 64 | { 65 | FILE *f = fopen(argc == 2 ? argv[1] : "input/test.png", "rb"); 66 | fseek(f, 0, SEEK_END); 67 | len = ftell(f); 68 | rewind(f); 69 | buf = (uint8_t *)malloc(len); 70 | len = fread(buf, 1, len, f); 71 | fclose(f); 72 | } 73 | unsigned width, height; 74 | int color_type; 75 | uint8_t *image = decode(buf, len, &width, &height, &color_type); 76 | free(buf); 77 | 78 | if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) { 79 | printf("Only RGBA types are supported for the rest of the example for now"); 80 | return 1; 81 | } 82 | { 83 | // Just that .pbm doesn't supoprt 4 channels let's turn it into 3 channels 84 | // https://stackoverflow.com/a/18495447 85 | for (int i = 0; i < width * height; i++) { 86 | int r = image[i * 4 + 0], g = image[i * 4 + 1], b = image[i * 4 + 2], 87 | a = image[i * 4 + 3]; 88 | 89 | image[i * 3 + 0] = r * a / 255; 90 | image[i * 3 + 1] = g * a / 255; 91 | image[i * 3 + 2] = b * a / 255; 92 | } 93 | } 94 | 95 | { 96 | FILE *f = fopen("out.pbm", "wb"); 97 | fprintf(f, "P6 %d %d 255\n", width, height); 98 | fwrite(image, sizeof(char), width * height * 3, f); 99 | fclose(f); 100 | } 101 | 102 | free(image); 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /librsvg-render.c: -------------------------------------------------------------------------------- 1 | // gcc librsvg-render.c `pkg-config --libs --cflags librsvg-2.0` -Wall && ./a.out 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main() { 8 | uint8_t *buf; 9 | unsigned len; 10 | { 11 | FILE *f = fopen("input/example.svg", "rb"); 12 | fseek(f, 0, SEEK_END); 13 | len = ftell(f); 14 | rewind(f); 15 | buf = (uint8_t *)malloc(len); 16 | len = fread(buf, 1, len, f); 17 | fclose(f); 18 | } 19 | 20 | GError *error = NULL; 21 | RsvgHandle *handle = rsvg_handle_new_from_data(buf, len, &error); 22 | free(buf); 23 | if (error) 24 | return 1; 25 | RsvgDimensionData dim; 26 | rsvg_handle_get_dimensions(handle, &dim); 27 | 28 | cairo_surface_t *cairo_surface = 29 | cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim.width, dim.height); 30 | cairo_t *cr = cairo_create(cairo_surface); 31 | rsvg_handle_render_cairo(handle, cr); 32 | cairo_destroy(cr); 33 | cairo_surface_write_to_png(cairo_surface, "out.png"); 34 | cairo_surface_destroy(cairo_surface); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /libwebp-decode.c: -------------------------------------------------------------------------------- 1 | // gcc libwebp-decode.c `pkg-config --libs --cflags libwebp` -Wall && ./a.out 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main() { 8 | uint8_t *buf; 9 | unsigned len; 10 | { 11 | FILE *f = fopen("input/test.webp", "rb"); 12 | fseek(f, 0, SEEK_END); 13 | len = ftell(f); 14 | rewind(f); 15 | buf = (uint8_t *)malloc(len); 16 | len = fread(buf, 1, len, f); 17 | fclose(f); 18 | } 19 | int width, height; 20 | uint8_t *image = WebPDecodeRGB(buf, len, &width, &height); 21 | free(buf); 22 | { 23 | FILE *f = fopen("out.pbm", "wb"); 24 | fprintf(f, "P6 %d %d 255\n", width, height); 25 | fwrite(image, sizeof(char), width * height * 3, f); 26 | fclose(f); 27 | } 28 | WebPFree(image); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /libzstd-decode.c: -------------------------------------------------------------------------------- 1 | // gcc libzstd-decode.c `pkg-config --libs --cflags libzstd` -Wall && ./a.out 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main() { 8 | uint8_t *src; 9 | unsigned src_size; 10 | { 11 | FILE *f = fopen("input/test.txt.zst", "rb"); 12 | fseek(f, 0, SEEK_END); 13 | src_size = ftell(f); 14 | rewind(f); 15 | src = (uint8_t *)malloc(src_size); 16 | src_size = fread(src, 1, src_size, f); 17 | fclose(f); 18 | } 19 | unsigned dst_size = ZSTD_getFrameContentSize(src, src_size); 20 | uint8_t *dst = malloc(dst_size); 21 | ZSTD_decompress(dst, dst_size, src, src_size); 22 | free(src); 23 | printf("%.*s", dst_size, dst); 24 | free(dst); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /lua-run.c: -------------------------------------------------------------------------------- 1 | // clang lua-run.c `pkg-config --libs --cflags lua` -Wall && ./a.out 2 | // https://lucasklassmann.com/blog/2019-02-02-how-to-embeddeding-lua-in-c/ 3 | #include 4 | #include 5 | #include 6 | 7 | int multiplication(lua_State *L) { 8 | int a = luaL_checkinteger(L, 1); 9 | int b = luaL_checkinteger(L, 2); 10 | lua_Integer c = a * b; 11 | lua_pushinteger(L, c); 12 | return 1; 13 | } 14 | 15 | int main(int argc, char **argv) { 16 | lua_State *L = luaL_newstate(); 17 | luaL_openlibs(L); 18 | lua_newtable(L); 19 | const struct luaL_Reg my_functions_registery[] = {{"mul", multiplication}}; 20 | // put the registry on the stack 21 | luaL_setfuncs(L, my_functions_registery, 0); 22 | // set it to my_functions_registry 23 | lua_setglobal(L, "my_functions_registry"); 24 | char *code = "print(my_functions_registry.mul(7, 8))"; 25 | 26 | if (luaL_loadstring(L, code) == LUA_OK) { 27 | if (lua_pcall(L, 0, 1, 0) == LUA_OK) { 28 | lua_pop(L, lua_gettop(L)); 29 | } 30 | } 31 | 32 | lua_close(L); 33 | return 0; 34 | } -------------------------------------------------------------------------------- /mujs-run.c: -------------------------------------------------------------------------------- 1 | // gcc mujs-run.c `pkg-config --libs --cflags mujs` -Wall && ./a.out 2 | // https://mujs.com/examples.html 3 | #include 4 | #include 5 | 6 | static void hello(js_State *J) { 7 | const char *name = js_tostring(J, 1); 8 | printf("Hello, %s!\n", name); 9 | js_pushundefined(J); 10 | } 11 | 12 | int main(int argc, char **argv) { 13 | js_State *J = js_newstate(NULL, NULL, JS_STRICT); 14 | 15 | js_newcfunction(J, hello, "hello", 1); 16 | js_setglobal(J, "hello"); 17 | 18 | js_dostring(J, "hello('world');"); 19 | 20 | js_freestate(J); 21 | } 22 | -------------------------------------------------------------------------------- /openal-stream.c: -------------------------------------------------------------------------------- 1 | // Stream some noise using OpenAL 2 | // Linux: cc openal-stream.c `pkg-config --cflags --libs openal` && ./a.out 3 | // macOS: cc openal-stream.c -framework OpenAL -DMACOS_BUILTIN_OPENAL && ./a.out 4 | // web: emcc openal-stream.c -lopenal -o index.html 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef MACOS_BUILTIN_OPENAL 13 | #include 14 | #include 15 | #else 16 | #include 17 | #include 18 | #endif 19 | 20 | #ifdef __EMSCRIPTEN__ 21 | #include 22 | #else 23 | #include 24 | #endif 25 | 26 | #define PCM_SIZE 1024 27 | float pcm[PCM_SIZE]; 28 | ALuint source = 0; 29 | unsigned counter; 30 | 31 | static void stream_buffer(ALuint bufferId) { 32 | for (unsigned i = 0; i < PCM_SIZE; ++i) 33 | pcm[i] = (ALfloat)sin((++counter / 2) / 5.0) * .2; 34 | alBufferData( 35 | bufferId, 0x10011/* AL_FORMAT_STEREO_FLOAT32 */, pcm, 36 | sizeof (pcm), 44000/* Your buffer sample rate */ 37 | ); 38 | } 39 | 40 | static void iter() { 41 | ALint processed, state; 42 | alGetSourcei(source, AL_SOURCE_STATE, &state); 43 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); 44 | assert(alGetError() == AL_NO_ERROR); 45 | 46 | while (processed > 0) { 47 | ALuint buffer; 48 | alSourceUnqueueBuffers(source, 1, &buffer); 49 | processed--; 50 | stream_buffer(buffer); 51 | alSourceQueueBuffers(source, 1, &buffer); 52 | } 53 | 54 | if (state != AL_PLAYING && state != AL_PAUSED) { 55 | fprintf(stderr, "Buffer underrun, restart the play\n"); 56 | alSourcePlay(source); 57 | } 58 | } 59 | 60 | int main() { 61 | ALCdevice *device = alcOpenDevice(0); 62 | assert(device); 63 | ALCcontext *ctx = alcCreateContext(device, 0); 64 | assert(ctx); 65 | assert(alcMakeContextCurrent(ctx)); 66 | // The only natively supported one in WebAudio 67 | assert(alIsExtensionPresent("AL_EXT_float32")); 68 | 69 | alGenSources(1, &source); 70 | { 71 | enum { BUFFERS_COUNT = 4 }; 72 | ALuint buffers[BUFFERS_COUNT] = {}; 73 | alGenBuffers(BUFFERS_COUNT, buffers); 74 | for (unsigned i = 0; i < BUFFERS_COUNT; ++i) stream_buffer(buffers[i]); 75 | alSourceQueueBuffers(source, BUFFERS_COUNT, buffers); 76 | } 77 | alSourcePlay(source); 78 | 79 | #ifdef __EMSCRIPTEN__ 80 | emscripten_set_main_loop(iter, 0, 0); 81 | #else 82 | while (1) { 83 | usleep(16); 84 | iter(); 85 | } 86 | #endif 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /pangocairo-drawtext.c: -------------------------------------------------------------------------------- 1 | // gcc pangocairo-drawtext.c `pkg-config --libs --cflags pangocairo` -Wall && ./a.out 2 | #include 3 | 4 | int main(int argc, const char **argv) { 5 | int width, height; 6 | const char *text = argc < 2 ? "سلام" : argv[1]; 7 | PangoFontDescription *font_description = pango_font_description_from_string("Noto Naskh Arabic 600"); 8 | { 9 | cairo_surface_t *cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); 10 | cairo_t *cr = cairo_create(cairo_surface); 11 | PangoLayout *pango_layout = pango_cairo_create_layout(cr); 12 | pango_layout_set_font_description(pango_layout, font_description); 13 | pango_layout_set_text(pango_layout, text, -1); 14 | pango_layout_set_auto_dir(pango_layout, 1); 15 | pango_layout_get_pixel_size(pango_layout, &width, &height); 16 | cairo_destroy(cr); 17 | cairo_surface_destroy(cairo_surface); 18 | } 19 | { 20 | cairo_surface_t *cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); 21 | cairo_t *cr = cairo_create(cairo_surface); 22 | PangoLayout *pango_layout = pango_cairo_create_layout(cr); 23 | pango_layout_set_font_description(pango_layout, font_description); 24 | pango_layout_set_text(pango_layout, text, -1); 25 | pango_layout_set_auto_dir(pango_layout, 1); 26 | cairo_set_source_rgba(cr, 0, 0, 0, 0); 27 | cairo_rectangle(cr, 0, 0, width, height); 28 | cairo_fill(cr); 29 | cairo_set_source_rgb(cr, 1, 1, 1); 30 | pango_cairo_show_layout(cr, pango_layout); 31 | cairo_surface_write_to_png(cairo_surface, "out.png"); 32 | cairo_surface_destroy(cairo_surface); 33 | cairo_destroy(cr); 34 | } 35 | pango_font_description_free(font_description); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /qt5-gui.cc: -------------------------------------------------------------------------------- 1 | // clang++ qt5-gui.cc `pkg-config --libs --cflags Qt5Core Qt5Widgets` -Wall && ./a.out 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | QApplication app(argc, argv); 7 | QLabel label("Hello World"); 8 | label.setTextInteractionFlags(Qt::TextSelectableByMouse); 9 | label.show(); 10 | return app.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /raqm-shape.c: -------------------------------------------------------------------------------- 1 | // gcc raqm-shape.c `pkg-config --cflags --libs raqm` -Wall && ./a.out 2 | #include 3 | 4 | #include 5 | 6 | int main() { 7 | FT_Library library; 8 | FT_Init_FreeType(&library); 9 | FT_Face face; 10 | FT_New_Face(library, "input/Roboto.abc.ttf", 0, &face); 11 | FT_Set_Char_Size(face, 36 * 64, 36 * 64, 0, 0); 12 | raqm_t *rq = raqm_create(); 13 | const char *text = "abc"; 14 | raqm_set_text_utf8(rq, text, strlen(text)); 15 | raqm_set_freetype_face(rq, face); 16 | raqm_set_par_direction(rq, RAQM_DIRECTION_LTR); 17 | const char *lang = "en"; 18 | raqm_set_language(rq, lang, 0, strlen(lang)); 19 | raqm_layout(rq); 20 | size_t count; 21 | raqm_glyph_t *glyphs = raqm_get_glyphs(rq, &count); 22 | for (unsigned i = 0; i < count; i++) 23 | printf("gid#%d off: (%d, %d) adv: (%d, %d) idx: %d\n", glyphs[i].index, 24 | glyphs[i].x_offset, glyphs[i].y_offset, glyphs[i].x_advance, 25 | glyphs[i].y_advance, glyphs[i].cluster); 26 | printf("\n"); 27 | raqm_destroy(rq); 28 | FT_Done_Face(face); 29 | FT_Done_FreeType(library); 30 | return 0; 31 | } -------------------------------------------------------------------------------- /skia-pdf.cc: -------------------------------------------------------------------------------- 1 | // vcpkg install skia 2 | /* clang++ -I ~/vcpkg/installed/x64-osx/include/ -std=c++14 \ 3 | -L ~/vcpkg/installed/x64-osx/lib -framework CoreText -framework CoreFoundation \ 4 | -framework CoreGraphics -framework ApplicationServices -lbrotlicommon-static \ 5 | -lbrotlidec-static -lbrotlienc-static -lbz2 -lexpat -lfreetype -lharfbuzz-icu \ 6 | -lharfbuzz-subset -lharfbuzz -licudata -licui18n -licuio -licutu -licuuc \ 7 | -lintl -ljpeg -lpng -lpng16 -lskia -lturbojpeg -lwebp -lwebpdecoder \ 8 | -lwebpdemux -lwebpmux -lz skia-pdf.cc -Wall && ./a.out 9 | */ 10 | // https://skia.org/user/sample/pdf 11 | #include "skia/core/SkCanvas.h" 12 | #include "skia/core/SkFont.h" 13 | #include "skia/core/SkGraphics.h" 14 | #include "skia/core/SkPath.h" 15 | #include "skia/core/SkSurface.h" 16 | #include "skia/docs/SkPDFDocument.h" 17 | #include "skia/effects/SkGradientShader.h" 18 | 19 | int main() { 20 | SkDynamicMemoryWStream buffer; 21 | SkPDF::Metadata metadata; 22 | metadata.fTitle = "SkPDF Example"; 23 | metadata.fCreator = "Example WritePDF() Function"; 24 | metadata.fCreation = {0, 2019, 1, 4, 31, 12, 34, 56}; 25 | metadata.fModified = {0, 2019, 1, 4, 31, 12, 34, 56}; 26 | auto pdfDocument = SkPDF::MakeDocument(&buffer, metadata); 27 | SkASSERT(pdfDocument); 28 | for (unsigned page = 0; page < 2; ++page) { 29 | constexpr SkSize ansiLetterSize{8.5f * 72, 11.0f * 72}; 30 | SkCanvas *pageCanvas = 31 | pdfDocument->beginPage(ansiLetterSize.width(), ansiLetterSize.height()); 32 | { 33 | const SkScalar R = 115.2f, C = 128.0f; 34 | SkPath path; 35 | path.moveTo(C + R, C); 36 | for (int i = 1; i < 8; ++i) { 37 | SkScalar a = 2.6927937f * i; 38 | path.lineTo(C + R * cos(a), C + R * sin(a)); 39 | } 40 | SkPaint paint; 41 | paint.setStyle(SkPaint::kStroke_Style); 42 | pageCanvas->drawPath(path, paint); 43 | } 44 | pdfDocument->endPage(); 45 | } 46 | pdfDocument->close(); 47 | 48 | sk_sp pdfData = buffer.detachAsData(); 49 | SkData *data = pdfData.get(); 50 | FILE *f = fopen("out.pdf", "wb"); 51 | fwrite(data->bytes(), 1, data->size(), f); 52 | fclose(f); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /sqlite-run.c: -------------------------------------------------------------------------------- 1 | // cc sqlite-run.c `pkg-config --libs --cflags sqlite3` -Wall && ./a.out :memory: 'SELECT 1;' 2 | // https://youtu.be/ZSKLA81tBis?t=982 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) { 9 | sqlite3 *db; 10 | assert(!sqlite3_open(argv[1], &db)); 11 | sqlite3_stmt *pStmt; 12 | assert(!sqlite3_prepare(db, argv[2], strlen(argv[2]), &pStmt, NULL)); 13 | int nCol = sqlite3_column_count(pStmt); 14 | while (sqlite3_step(pStmt) == SQLITE_ROW) { 15 | printf("Row:\n"); 16 | for (unsigned i = 0; i < nCol; ++i) { 17 | printf(" %s = %s\n", 18 | sqlite3_column_name(pStmt, i), 19 | sqlite3_column_text(pStmt, i) 20 | ); 21 | } 22 | } 23 | sqlite3_finalize(pStmt); 24 | sqlite3_close(db); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /ssd1306-cairo-clock.c: -------------------------------------------------------------------------------- 1 | // Draw a digital clock using Cairo on SSD1306 LCD in a Raspberry PI 2 | // $ cc ssd1306-cairo-clock.c `pkg-config --cflags --libs cairo` && ./a.out 3 | // Originally based on https://github.com/pive/rpi1306i2c/blob/master/rpi1306i2c.hpp 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define MEMORYMODE 0x20 18 | #define COLUMNADDR 0x21 19 | #define PAGEADDR 0x22 20 | #define SETSTARTLINE 0x40 21 | #define SETCONTRAST 0x81 22 | #define CHARGEPUMP 0x8D 23 | #define SEGREMAP 0xA0 24 | #define DISPLAYALLON_RESUME 0xA4 25 | #define DISPLAYALLON 0xA5 26 | #define NORMALDISPLAY 0xA6 27 | #define SETMULTIPLEX 0xA8 28 | #define DISPLAYOFF 0xAE 29 | #define DISPLAYON 0xAF 30 | #define SETPAGE 0xB0 31 | #define COMSCANINC 0xC0 32 | #define COMSCANDEC 0xC8 33 | #define SETDISPLAYOFFSET 0xD3 34 | #define SETDISPLAYCLOCKDIV 0xD5 35 | #define SETPRECHARGE 0xD9 36 | #define SETCOMPINS 0xDA 37 | #define SETVCOMDETECT 0xDB 38 | 39 | const uint8_t ssd1306_128x32_init_seq[] = { 40 | 0x80, DISPLAYOFF, 41 | 0x80, SETDISPLAYCLOCKDIV, 0x80, 0x80, 42 | 0x80, SETMULTIPLEX, 0x80, 0x1F, 43 | 0x80, SETDISPLAYOFFSET, 0x80, 0x00, 44 | 0x80, SETSTARTLINE | 0x00, 45 | 0x80, CHARGEPUMP, 0x80, 0x14, 46 | 0x80, SEGREMAP, 47 | 0x80, COMSCANDEC, 48 | 0x80, SETCOMPINS, 0x80, 0x12, 49 | 0x80, SETCONTRAST, 0x80, 0x1,//0x7F, brightness 50 | 0x80, SETPRECHARGE, 0x80, 0x22, 51 | 0x80, SETVCOMDETECT, 0x80, 0x20, 52 | 0x80, MEMORYMODE, 53 | 0x80, DISPLAYALLON_RESUME, 54 | 0x80, NORMALDISPLAY, 55 | 0x80, COLUMNADDR, 0x80, 0, 0x80, 128 - 1, 56 | 0x80, PAGEADDR, 0x80, 0, 0x80, (32 >> 3) - 1, 57 | 0x80, DISPLAYON, 58 | }; 59 | 60 | static void writeBuffer(int deviceNode, const uint8_t *buffer, unsigned size) { 61 | if (write(deviceNode, buffer, size) != size) { 62 | printf("Could not write on the device"); 63 | abort(); 64 | } 65 | } 66 | 67 | static void debug(uint8_t *buffer, unsigned stride) { 68 | for (unsigned i = 0; i < 32; i++) { 69 | for (unsigned j = 0; j < 16; ++j) { 70 | for (unsigned k = 0; k < 8; ++k) { 71 | printf(buffer[i * stride + j] & 1 << k ? "*" : " "); 72 | } 73 | } 74 | printf("|\n"); 75 | } 76 | } 77 | 78 | int main() { 79 | const int deviceNode = open("/dev/i2c-1", O_RDWR); 80 | const uint8_t addr = 0x3C; 81 | if (deviceNode < 0 || ioctl(deviceNode, I2C_SLAVE, addr) < 0) { 82 | printf("Could not open\n"); 83 | abort(); 84 | } 85 | 86 | writeBuffer(deviceNode, ssd1306_128x32_init_seq, sizeof(ssd1306_128x32_init_seq)); 87 | 88 | const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_A1, 128); 89 | assert(stride == 16); 90 | uint8_t data[512]; 91 | cairo_surface_t *cairo_surface = cairo_image_surface_create_for_data( 92 | data, CAIRO_FORMAT_A1, 128, 32, stride 93 | ); 94 | cairo_t *cr = cairo_create(cairo_surface); 95 | cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); 96 | cairo_set_font_size(cr, 42); 97 | cairo_set_source_rgb(cr, 1, 1, 1); 98 | 99 | uint8_t buffer[513] = {SETSTARTLINE}; 100 | while (1) { 101 | const time_t now = time(0); 102 | struct tm *tm = localtime(&now); 103 | char str[8] = {}; 104 | snprintf(str, 6, "%02d%c%02d", tm->tm_hour, now % 2 ? ':' : ' ', tm->tm_min); 105 | 106 | memset(data, 0, stride * 32); 107 | cairo_move_to(cr, 0, 32); 108 | cairo_show_text(cr, str); 109 | // debug(data, stride); 110 | 111 | for (unsigned i = 0; i < sizeof(buffer) - 1; ++i) { 112 | unsigned x = 127 - (i % 128); 113 | unsigned y = (i / 128) * 8; 114 | #define P(j) ((unsigned) !!(data[x / 8 + (y + j) * 16] & (1 << (x % 8))) << j) 115 | buffer[i + 1] = P(0) | P(1) | P(2) | P(3) | P(4) | P(5) | P(6) | P(7); 116 | #undef P 117 | } 118 | writeBuffer(deviceNode, buffer, sizeof(buffer)); 119 | usleep(1000000); 120 | } 121 | 122 | cairo_surface_destroy(cairo_surface); 123 | cairo_destroy(cr); 124 | close(deviceNode); 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /ssd1306.c: -------------------------------------------------------------------------------- 1 | // Display something on SSD1306 LCD in a Raspberry PI 2 | // $ cc ssd1306.c && ./a.out 3 | // Originally based on https://github.com/pive/rpi1306i2c/blob/master/rpi1306i2c.hpp 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define MEMORYMODE 0x20 14 | #define COLUMNADDR 0x21 15 | #define PAGEADDR 0x22 16 | #define SETSTARTLINE 0x40 17 | #define SETCONTRAST 0x81 18 | #define CHARGEPUMP 0x8D 19 | #define SEGREMAP 0xA0 20 | #define DISPLAYALLON_RESUME 0xA4 21 | #define DISPLAYALLON 0xA5 22 | #define NORMALDISPLAY 0xA6 23 | #define SETMULTIPLEX 0xA8 24 | #define DISPLAYOFF 0xAE 25 | #define DISPLAYON 0xAF 26 | #define SETPAGE 0xB0 27 | #define COMSCANINC 0xC0 28 | #define COMSCANDEC 0xC8 29 | #define SETDISPLAYOFFSET 0xD3 30 | #define SETDISPLAYCLOCKDIV 0xD5 31 | #define SETPRECHARGE 0xD9 32 | #define SETCOMPINS 0xDA 33 | #define SETVCOMDETECT 0xDB 34 | 35 | const uint8_t ssd1306_128x32_init_seq[] = { 36 | 0x80, DISPLAYOFF, 37 | 0x80, SETDISPLAYCLOCKDIV, 0x80, 0x80, 38 | 0x80, SETMULTIPLEX, 0x80, 0x1F, 39 | 0x80, SETDISPLAYOFFSET, 0x80, 0x00, 40 | 0x80, SETSTARTLINE | 0x00, 41 | 0x80, CHARGEPUMP, 0x80, 0x14, 42 | 0x80, SEGREMAP, 43 | 0x80, COMSCANDEC, 44 | 0x80, SETCOMPINS, 0x80, 0x12, 45 | 0x80, SETCONTRAST, 0x80, 0x1,//0x7F, brightness 46 | 0x80, SETPRECHARGE, 0x80, 0x22, 47 | 0x80, SETVCOMDETECT, 0x80, 0x20, 48 | 0x80, MEMORYMODE, 49 | 0x80, DISPLAYALLON_RESUME, 50 | 0x80, NORMALDISPLAY, 51 | 0x80, COLUMNADDR, 0x80, 0, 0x80, 128 - 1, 52 | 0x80, PAGEADDR, 0x80, 0, 0x80, (32 >> 3) - 1, 53 | 0x80, DISPLAYON, 54 | }; 55 | 56 | // This image is brought from https://github.com/dwhinham/mt32-pi/blob/ee645df6e/include/lcd/images.h#L71-L105 57 | const uint8_t image[] = { 58 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 59 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 60 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000011, 0b10000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 61 | 0b00000000, 0b00111111, 0b11100000, 0b00000011, 0b11111100, 0b00001111, 0b11100000, 0b00111111, 0b11110000, 0b11111111, 0b11111111, 0b11100000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 62 | 0b00000000, 0b00111111, 0b11111000, 0b00000011, 0b11111111, 0b00011111, 0b11110000, 0b11111111, 0b11111110, 0b11111111, 0b11111111, 0b11111000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 63 | 0b00000000, 0b00111111, 0b11111000, 0b00000111, 0b11111111, 0b10011111, 0b11110001, 0b11111111, 0b11111110, 0b11111111, 0b11111111, 0b11111100, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 64 | 0b00000000, 0b00111111, 0b11111100, 0b00000111, 0b11111111, 0b10011111, 0b11110011, 0b11111111, 0b11111100, 0b11111111, 0b11111111, 0b11111100, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 65 | 0b00000000, 0b00111111, 0b11111100, 0b00000111, 0b11111111, 0b10011111, 0b11100111, 0b11111111, 0b11111101, 0b11111111, 0b11111111, 0b11111100, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 66 | 0b00000000, 0b01111111, 0b11111100, 0b00001111, 0b11111111, 0b10001111, 0b11001111, 0b11111111, 0b11111001, 0b11111111, 0b11111111, 0b11111100, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 67 | 0b00000000, 0b01111111, 0b11111100, 0b00001111, 0b11111111, 0b10000011, 0b00001111, 0b11111000, 0b00000001, 0b11111111, 0b11111111, 0b11111100, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 68 | 0b00000000, 0b01111111, 0b11111100, 0b00011111, 0b11111111, 0b10000000, 0b00001111, 0b11110000, 0b00000000, 0b00000011, 0b11111100, 0b00000000, 0b01110000, 0b00000000, 0b00000000, 0b11000000, 69 | 0b00000000, 0b01111111, 0b11111100, 0b00011111, 0b11111111, 0b10111110, 0b00001111, 0b11110000, 0b00000000, 0b00000011, 0b11111100, 0b00000111, 0b11111110, 0b00001111, 0b11110011, 0b11000000, 70 | 0b00000000, 0b01111110, 0b11111100, 0b00111111, 0b01111111, 0b10111111, 0b10001111, 0b11111000, 0b00000000, 0b00000011, 0b11111100, 0b00011111, 0b11111111, 0b10001111, 0b11110111, 0b11000000, 71 | 0b00000000, 0b11111110, 0b11111100, 0b00111111, 0b01111111, 0b00111111, 0b10001111, 0b11111110, 0b00000000, 0b00000111, 0b11111000, 0b00111111, 0b11111111, 0b10001111, 0b11111111, 0b11000000, 72 | 0b00000000, 0b11111110, 0b11111100, 0b01111110, 0b11111111, 0b00111111, 0b10001111, 0b11111111, 0b10000000, 0b00000111, 0b11111000, 0b01111111, 0b11111111, 0b11001111, 0b11111111, 0b11000000, 73 | 0b00000000, 0b11111110, 0b11111100, 0b01111110, 0b11111111, 0b00111111, 0b10000111, 0b11111111, 0b11000000, 0b00000111, 0b11111000, 0b11111111, 0b00011111, 0b11011111, 0b11111111, 0b10000000, 74 | 0b00000000, 0b11111110, 0b11111100, 0b01111100, 0b11111111, 0b01111111, 0b10000111, 0b11111111, 0b11100000, 0b00000111, 0b11111000, 0b11111110, 0b00011111, 0b11011111, 0b11111111, 0b10000000, 75 | 0b00000001, 0b11111110, 0b11111100, 0b11111100, 0b11111111, 0b01111111, 0b10000011, 0b11111111, 0b11110000, 0b00000111, 0b11111001, 0b11111100, 0b00111111, 0b11011111, 0b11111000, 0b00000000, 76 | 0b00000001, 0b11111100, 0b11111110, 0b11111001, 0b11111110, 0b01111111, 0b10000000, 0b11111111, 0b11110000, 0b00001111, 0b11110001, 0b11111111, 0b11111111, 0b10011111, 0b11100000, 0b00000000, 77 | 0b00000001, 0b11111100, 0b11111111, 0b11111001, 0b11111110, 0b01111111, 0b10000000, 0b00111111, 0b11111000, 0b00001111, 0b11110001, 0b11111111, 0b11111111, 0b10011111, 0b11100000, 0b00000000, 78 | 0b00000001, 0b11111100, 0b11111111, 0b11111001, 0b11111110, 0b11111111, 0b00000000, 0b00001111, 0b11111000, 0b00001111, 0b11110011, 0b11111111, 0b11111111, 0b00111111, 0b11000000, 0b00000000, 79 | 0b00000001, 0b11111100, 0b11111111, 0b11110001, 0b11111110, 0b11111111, 0b00000000, 0b00001111, 0b11111000, 0b00001111, 0b11110011, 0b11111111, 0b11111100, 0b00111111, 0b11000000, 0b00000000, 80 | 0b00000011, 0b11111100, 0b01111111, 0b11110001, 0b11111100, 0b11111111, 0b00110000, 0b00000111, 0b11111000, 0b00001111, 0b11110011, 0b11111111, 0b10000000, 0b00111111, 0b11000000, 0b00000000, 81 | 0b00000011, 0b11111000, 0b01111111, 0b11100011, 0b11111100, 0b11111111, 0b00111100, 0b00001111, 0b11111000, 0b00011111, 0b11100011, 0b11111100, 0b00000000, 0b00111111, 0b11000000, 0b00000000, 82 | 0b00000011, 0b11111000, 0b01111111, 0b11100011, 0b11111100, 0b11111110, 0b00111111, 0b11111111, 0b11110000, 0b00011111, 0b11100011, 0b11111110, 0b00000110, 0b00111111, 0b10000000, 0b00000000, 83 | 0b00000011, 0b11111000, 0b01111111, 0b11000011, 0b11111100, 0b11111110, 0b00111111, 0b11111111, 0b11110000, 0b00011111, 0b11100001, 0b11111111, 0b11111110, 0b01111111, 0b10000000, 0b00000000, 84 | 0b00000011, 0b11111000, 0b01111111, 0b11000011, 0b11111100, 0b11111110, 0b00111111, 0b11111111, 0b11100000, 0b00011111, 0b11100001, 0b11111111, 0b11111110, 0b01111111, 0b10000000, 0b00000000, 85 | 0b00000011, 0b11110000, 0b01111111, 0b10000011, 0b11111000, 0b11111110, 0b01111111, 0b11111111, 0b11000000, 0b00011111, 0b11100000, 0b11111111, 0b11111110, 0b00111111, 0b10000000, 0b00000000, 86 | 0b00000001, 0b11110000, 0b01111111, 0b10000001, 0b11111000, 0b01111110, 0b00111111, 0b11111111, 0b10000000, 0b00001111, 0b11000000, 0b01111111, 0b11111100, 0b00011111, 0b10000000, 0b00000000, 87 | 0b00000000, 0b11110000, 0b01111111, 0b00000000, 0b01111000, 0b00111100, 0b00001111, 0b11111110, 0b00000000, 0b00000011, 0b11000000, 0b00011111, 0b11110000, 0b00001111, 0b00000000, 0b00000000, 88 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 89 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 90 | }; 91 | 92 | static void writeBuffer(int deviceNode, const uint8_t *buffer, unsigned size) { 93 | if (write(deviceNode, buffer, size) != size) { 94 | printf("Could not write on the device"); 95 | abort(); 96 | } 97 | } 98 | 99 | int main() { 100 | const int deviceNode = open("/dev/i2c-1", O_RDWR); 101 | const uint8_t addr = 0x3C; 102 | if (deviceNode < 0 || ioctl(deviceNode, I2C_SLAVE, addr) < 0) { 103 | printf("Could not open\n"); 104 | abort(); 105 | } 106 | 107 | writeBuffer(deviceNode, ssd1306_128x32_init_seq, sizeof(ssd1306_128x32_init_seq)); 108 | 109 | uint8_t buffer[513] = {SETSTARTLINE}; 110 | unsigned tick = 0; 111 | while (1) { 112 | ++tick; 113 | for (unsigned i = 0; i < sizeof(buffer) - 1; ++i) { 114 | unsigned x = 127 - ((i - tick) % 128); 115 | unsigned y = (i / 128) * 8; 116 | #define P(j) ((unsigned) !!(image[x / 8 + (y + j) * 16] & (1 << (7 - (x % 8)))) << j) 117 | buffer[i + 1] = P(0) | P(1) | P(2) | P(3) | P(4) | P(5) | P(6) | P(7); 118 | #undef P 119 | } 120 | writeBuffer(deviceNode, buffer, sizeof(buffer)); 121 | usleep(10000); 122 | } 123 | 124 | close(deviceNode); 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /v8-run.cc: -------------------------------------------------------------------------------- 1 | 2 | // brew install v8 3 | /* clang++ v8-run.cc -I /usr/local/Cellar/v8/?*?/libexec/include \ 4 | -L /usr/local/Cellar/v8/?*?/libexec \ 5 | -lv8 -lv8 -lv8_libplatform -lchrome_zlib -lv8_libbase \ 6 | -Wall -std=c++14 -DV8_COMPRESS_POINTERS && ./a.out 7 | */ 8 | // https://chromium.googlesource.com/v8/v8/+/refs/heads/master/samples/hello-world.cc 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | int main(int argc, char* argv[]) { 17 | // Initialize V8. 18 | v8::V8::InitializeICUDefaultLocation(argv[0]); 19 | v8::V8::InitializeExternalStartupData(argv[0]); 20 | std::unique_ptr platform = v8::platform::NewDefaultPlatform(); 21 | v8::V8::InitializePlatform(platform.get()); 22 | v8::V8::Initialize(); 23 | // Create a new Isolate and make it the current one. 24 | v8::Isolate::CreateParams create_params; 25 | create_params.array_buffer_allocator = 26 | v8::ArrayBuffer::Allocator::NewDefaultAllocator(); 27 | v8::Isolate* isolate = v8::Isolate::New(create_params); 28 | { 29 | v8::Isolate::Scope isolate_scope(isolate); 30 | // Create a stack-allocated handle scope. 31 | v8::HandleScope handle_scope(isolate); 32 | // Create a new context. 33 | v8::Local context = v8::Context::New(isolate); 34 | // Enter the context for compiling and running the hello world script. 35 | v8::Context::Scope context_scope(context); 36 | { 37 | // Create a string containing the JavaScript source code. 38 | v8::Local source = 39 | v8::String::NewFromUtf8Literal(isolate, "'Hello' + ', World!'"); 40 | // Compile the source code. 41 | v8::Local script = 42 | v8::Script::Compile(context, source).ToLocalChecked(); 43 | // Run the script to get the result. 44 | v8::Local result = script->Run(context).ToLocalChecked(); 45 | // Convert the result to an UTF8 string and print it. 46 | v8::String::Utf8Value utf8(isolate, result); 47 | printf("%s\n", *utf8); 48 | } 49 | { 50 | // Use the JavaScript API to generate a WebAssembly module. 51 | // 52 | // |bytes| contains the binary format for the following module: 53 | // 54 | // (func (export "add") (param i32 i32) (result i32) 55 | // get_local 0 56 | // get_local 1 57 | // i32.add) 58 | // 59 | const char csource[] = R"( 60 | let bytes = new Uint8Array([ 61 | 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 62 | 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 63 | 0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01, 64 | 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b 65 | ]); 66 | let module = new WebAssembly.Module(bytes); 67 | let instance = new WebAssembly.Instance(module); 68 | instance.exports.add(3, 4); 69 | )"; 70 | // Create a string containing the JavaScript source code. 71 | v8::Local source = 72 | v8::String::NewFromUtf8Literal(isolate, csource); 73 | // Compile the source code. 74 | v8::Local script = 75 | v8::Script::Compile(context, source).ToLocalChecked(); 76 | // Run the script to get the result. 77 | v8::Local result = script->Run(context).ToLocalChecked(); 78 | // Convert the result to a uint32 and print it. 79 | uint32_t number = result->Uint32Value(context).ToChecked(); 80 | printf("3 + 4 = %u\n", number); 81 | } 82 | } 83 | // Dispose the isolate and tear down V8. 84 | isolate->Dispose(); 85 | v8::V8::Dispose(); 86 | v8::V8::ShutdownPlatform(); 87 | delete create_params.array_buffer_allocator; 88 | return 0; 89 | } -------------------------------------------------------------------------------- /win32-gui.c: -------------------------------------------------------------------------------- 1 | // x86_64-w64-mingw32-gcc win32-gui.c && wine64 a.exe 2 | // https://docs.microsoft.com/en-us/windows/win32/learnwin32/your-first-windows-program 3 | #ifndef UNICODE 4 | #define UNICODE 5 | #endif 6 | 7 | #include 8 | 9 | LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 10 | 11 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 12 | LPSTR lpCmdLine, int nCmdShow) { 13 | const wchar_t CLASS_NAME[] = L"Sample Window Class"; 14 | WNDCLASS wc = {.lpfnWndProc = WindowProc, 15 | .hInstance = hInstance, 16 | .lpszClassName = CLASS_NAME}; 17 | RegisterClass(&wc); 18 | HWND hwnd = 19 | CreateWindowEx(0, // Optional window styles. 20 | CLASS_NAME, // Window class 21 | L"Learn to Program Windows", // Window text 22 | WS_OVERLAPPEDWINDOW, // Window style 23 | // Size and position 24 | CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 25 | NULL, // Parent window 26 | NULL, // Menu 27 | hInstance, // Instance handle 28 | NULL // Additional application data 29 | ); 30 | if (!hwnd) 31 | return 1; 32 | ShowWindow(hwnd, nCmdShow); 33 | MSG msg = {}; 34 | while (GetMessage(&msg, NULL, 0, 0)) { 35 | TranslateMessage(&msg); 36 | DispatchMessage(&msg); 37 | } 38 | return 0; 39 | } 40 | 41 | LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, 42 | LPARAM lParam) { 43 | switch (uMsg) { 44 | case WM_DESTROY: 45 | PostQuitMessage(0); 46 | return 0; 47 | case WM_PAINT: { 48 | PAINTSTRUCT ps; 49 | HDC hdc = BeginPaint(hwnd, &ps); 50 | FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1)); 51 | EndPaint(hwnd, &ps); 52 | } 53 | return 0; 54 | } 55 | return DefWindowProc(hwnd, uMsg, wParam, lParam); 56 | } 57 | -------------------------------------------------------------------------------- /xlib-gui.c: -------------------------------------------------------------------------------- 1 | // gcc xlib-gui.c `pkg-config --cflags --libs x11` -Wall && ./a.out 2 | // https://rosettacode.org/wiki/Window_creation/X11#C 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | int main() { 10 | Display *d = XOpenDisplay(NULL); 11 | if (!d) 12 | return 1; 13 | 14 | int s = DefaultScreen(d); 15 | Window w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1, 16 | BlackPixel(d, s), WhitePixel(d, s)); 17 | XSelectInput(d, w, ExposureMask | KeyPressMask); 18 | XMapWindow(d, w); 19 | 20 | while (1) { 21 | XEvent e; 22 | XNextEvent(d, &e); 23 | if (e.type == Expose) { 24 | XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10); 25 | const char *msg = "Hello, World!"; 26 | XDrawString(d, w, DefaultGC(d, s), 10, 50, msg, strlen(msg)); 27 | } 28 | if (e.type == KeyPress) 29 | break; 30 | } 31 | 32 | XCloseDisplay(d); 33 | return 0; 34 | } --------------------------------------------------------------------------------