| 1 | module render_sokol |
| 2 | |
| 3 | /********************************************************************** |
| 4 | * |
| 5 | * BMP render module utility functions |
| 6 | * |
| 7 | * Copyright (c) 2021 Dario Deledda. All rights reserved. |
| 8 | * Use of this source code is governed by an MIT license |
| 9 | * that can be found in the LICENSE file. |
| 10 | * |
| 11 | * Note: |
| 12 | * |
| 13 | * TODO: |
| 14 | **********************************************************************/ |
| 15 | import math |
| 16 | import gg |
| 17 | import sokol.sgl |
| 18 | import sokol.gfx |
| 19 | import x.ttf |
| 20 | |
| 21 | // TTF_render_Sokol is a structure containing data for rendering a TTF font as a sokol texture. |
| 22 | pub struct TTF_render_Sokol { |
| 23 | pub mut: |
| 24 | bmp &ttf.BitMap = unsafe { nil } // Base bitmap render |
| 25 | // rendering fields |
| 26 | sg_img gfx.Image // sokol image |
| 27 | sg_smp gfx.Sampler // sokol sampler |
| 28 | scale_reduct f32 = 2.0 // scale of the cpu texture for filtering |
| 29 | device_dpi int = 72 // device DPI |
| 30 | } |
| 31 | |
| 32 | /****************************************************************************** |
| 33 | * |
| 34 | * Render functions |
| 35 | * |
| 36 | ******************************************************************************/ |
| 37 | // format_texture formats the BMP (bitmap). |
| 38 | pub fn (mut tf_skl TTF_render_Sokol) format_texture() { |
| 39 | tf_skl.bmp.format_texture() |
| 40 | } |
| 41 | |
| 42 | // create_text prepares the text `in_txt` in size `in_font_size` as a sokol texture. |
| 43 | pub fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32) { |
| 44 | scale_reduct := tf_skl.scale_reduct |
| 45 | device_dpi := tf_skl.device_dpi |
| 46 | font_size := in_font_size //* scale_reduct |
| 47 | |
| 48 | // Formula: (font_size * device dpi) / (72dpi * em_unit) |
| 49 | // scale := ((1.0 * device_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size |
| 50 | scale := f32(font_size * device_dpi) / f32(72 * int(tf_skl.bmp.tf.units_per_em)) |
| 51 | // ttf.dprintln("Scale: ${scale}") |
| 52 | |
| 53 | tf_skl.bmp.scale = scale * scale_reduct |
| 54 | w, h := tf_skl.bmp.get_bbox(in_txt) |
| 55 | tf_skl.bmp.width = int(w) |
| 56 | tf_skl.bmp.height = int(h + 8) |
| 57 | sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp |
| 58 | |
| 59 | // RAM buffer |
| 60 | if sz > tf_skl.bmp.buf_size { |
| 61 | if sz > 0 { |
| 62 | unsafe { free(tf_skl.bmp.buf) } |
| 63 | } |
| 64 | ttf.dprintln('create_text Alloc: ${sz} bytes') |
| 65 | tf_skl.bmp.buf = unsafe { malloc_noscan(sz) } |
| 66 | tf_skl.bmp.buf_size = sz |
| 67 | } |
| 68 | |
| 69 | tf_skl.bmp.init_filler() |
| 70 | |
| 71 | // draw the text |
| 72 | mut y_base := int((tf_skl.bmp.tf.y_max - tf_skl.bmp.tf.y_min) * tf_skl.bmp.scale) |
| 73 | tf_skl.bmp.set_pos(0, y_base) |
| 74 | tf_skl.bmp.clear() |
| 75 | tf_skl.bmp.draw_text(in_txt) |
| 76 | tf_skl.format_texture() |
| 77 | } |
| 78 | |
| 79 | // create_text_block prepares a block of text as a sokol texture. |
| 80 | pub fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h int, in_font_size f32) { |
| 81 | scale_reduct := tf_skl.scale_reduct |
| 82 | device_dpi := tf_skl.device_dpi |
| 83 | font_size := in_font_size //* scale_reduct |
| 84 | // Formula: (font_size * device dpi) / (72dpi * em_unit) |
| 85 | // scale := ((1.0 * device_dpi )/ f32(72 * tf_skl.bmp.tf.units_per_em))* font_size |
| 86 | scale := f32(font_size * device_dpi) / f32(72 * int(tf_skl.bmp.tf.units_per_em)) |
| 87 | // ttf.dprintln("Scale: ${scale}") |
| 88 | |
| 89 | tf_skl.bmp.scale = scale * scale_reduct |
| 90 | w := in_w |
| 91 | h := in_h |
| 92 | tf_skl.bmp.width = int(w * scale_reduct + 0.5) |
| 93 | tf_skl.bmp.height = int((h + 2) * scale_reduct + 0.5) |
| 94 | sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp |
| 95 | |
| 96 | // if true { return } |
| 97 | |
| 98 | // RAM buffer |
| 99 | if sz > tf_skl.bmp.buf_size { |
| 100 | if sz > 0 { |
| 101 | unsafe { free(tf_skl.bmp.buf) } |
| 102 | } |
| 103 | ttf.dprintln('Alloc: ${sz} bytes') |
| 104 | tf_skl.bmp.buf = unsafe { malloc_noscan(sz) } |
| 105 | tf_skl.bmp.buf_size = sz |
| 106 | } |
| 107 | |
| 108 | tf_skl.bmp.init_filler() |
| 109 | |
| 110 | // draw the text |
| 111 | mut y_base := int((tf_skl.bmp.tf.y_max - tf_skl.bmp.tf.y_min) * tf_skl.bmp.scale) |
| 112 | tf_skl.bmp.set_pos(0, y_base) |
| 113 | tf_skl.bmp.clear() |
| 114 | |
| 115 | tf_skl.bmp.draw_text_block(in_txt, x: 0, y: 0, w: w, h: h) |
| 116 | tf_skl.format_texture() |
| 117 | } |
| 118 | |
| 119 | /****************************************************************************** |
| 120 | * |
| 121 | * Sokol Render functions |
| 122 | * |
| 123 | ******************************************************************************/ |
| 124 | // create_texture creates the sokol texture from the internal buffer state. |
| 125 | pub fn (mut tf_skl TTF_render_Sokol) create_texture() { |
| 126 | w := tf_skl.bmp.width |
| 127 | h := tf_skl.bmp.height |
| 128 | sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp |
| 129 | mut img_desc := gfx.ImageDesc{ |
| 130 | width: w |
| 131 | height: h |
| 132 | num_mipmaps: 0 |
| 133 | // usage: .dynamic |
| 134 | label: &char(unsafe { nil }) |
| 135 | d3d11_texture: 0 |
| 136 | } |
| 137 | // comment for dynamic |
| 138 | img_desc.data.subimage[0][0] = gfx.Range{ |
| 139 | ptr: tf_skl.bmp.buf |
| 140 | size: usize(sz) |
| 141 | } |
| 142 | |
| 143 | simg := gfx.make_image(&img_desc) |
| 144 | // free(tf_skl.bmp.buf) // DONT FREE IF Dynamic |
| 145 | |
| 146 | mut smp_desc := gfx.SamplerDesc{ |
| 147 | min_filter: .linear |
| 148 | mag_filter: .linear |
| 149 | wrap_u: .clamp_to_edge |
| 150 | wrap_v: .clamp_to_edge |
| 151 | } |
| 152 | |
| 153 | ssmp := gfx.make_sampler(&smp_desc) |
| 154 | |
| 155 | tf_skl.sg_img = simg |
| 156 | tf_skl.sg_smp = ssmp |
| 157 | } |
| 158 | |
| 159 | // destroy_texture detroys the internal sokol texture. |
| 160 | pub fn (tf_skl TTF_render_Sokol) destroy_texture() { |
| 161 | gfx.destroy_image(tf_skl.sg_img) |
| 162 | gfx.destroy_sampler(tf_skl.sg_smp) |
| 163 | } |
| 164 | |
| 165 | // update_text_texture updates the sokol texture with current internal state. |
| 166 | // NOTE: Only use if `.dynamic` is set. |
| 167 | pub fn (mut tf_skl TTF_render_Sokol) update_text_texture() { |
| 168 | sz := tf_skl.bmp.width * tf_skl.bmp.height * tf_skl.bmp.bp |
| 169 | mut tmp_sbc := gfx.ImageData{} |
| 170 | tmp_sbc.subimage[0][0] = gfx.Range{ |
| 171 | ptr: tf_skl.bmp.buf |
| 172 | size: usize(sz) |
| 173 | } |
| 174 | gfx.update_image(tf_skl.sg_img, &tmp_sbc) |
| 175 | } |
| 176 | |
| 177 | // draw_text_bmp renders the internal state to the current sokol pipeline. |
| 178 | pub fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) { |
| 179 | // width := tf_skl.bmp.width >> 1 |
| 180 | // height := tf_skl.bmp.height >> 1 |
| 181 | sgl.push_matrix() |
| 182 | |
| 183 | width := tf_skl.bmp.width / (tf_skl.scale_reduct) |
| 184 | height := tf_skl.bmp.height / (tf_skl.scale_reduct) |
| 185 | |
| 186 | u0 := f32(0.0) |
| 187 | v0 := f32(0.0) |
| 188 | u1 := f32(1.0) |
| 189 | v1 := f32(1.0) |
| 190 | x0 := f32(0) |
| 191 | y0 := f32(0) |
| 192 | x1 := f32(width) * ctx.scale |
| 193 | y1 := f32(height) * ctx.scale |
| 194 | |
| 195 | ca := f32(math.cos(tf_skl.bmp.angle)) |
| 196 | sa := f32(math.sin(tf_skl.bmp.angle)) |
| 197 | m := [ |
| 198 | f32(ca), |
| 199 | -sa, |
| 200 | 0, |
| 201 | 0, |
| 202 | sa, |
| 203 | ca, |
| 204 | 0, |
| 205 | 0, |
| 206 | 0, |
| 207 | 0, |
| 208 | 1, |
| 209 | 0, |
| 210 | x * ctx.scale, |
| 211 | y * ctx.scale, |
| 212 | 0, |
| 213 | 1, |
| 214 | ] |
| 215 | sgl.mult_matrix(m) |
| 216 | |
| 217 | sgl.load_pipeline(ctx.pipeline.alpha) |
| 218 | sgl.enable_texture() |
| 219 | sgl.texture(tf_skl.sg_img, tf_skl.sg_smp) |
| 220 | sgl.begin_quads() |
| 221 | sgl.c4b(255, 255, 255, 255) |
| 222 | sgl.v2f_t2f(x0, y0, u0, v0) |
| 223 | sgl.v2f_t2f(x1, y0, u1, v0) |
| 224 | sgl.v2f_t2f(x1, y1, u1, v1) |
| 225 | sgl.v2f_t2f(x0, y1, u0, v1) |
| 226 | sgl.end() |
| 227 | sgl.disable_texture() |
| 228 | sgl.pop_matrix() |
| 229 | } |
| 230 | |