1 /* 2 * Copyright (c) 2007-2013 Scott Lembcke and Howling Moon Software 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 module demo.ChipmunkDemoTextSupport; 23 24 import core.stdc.stdlib; 25 26 import glad.gl.all; 27 28 import demo.dchip; 29 30 import demo.ChipmunkDemoShaderSupport; 31 import demo.VeraMoBd_ttf_sdf; 32 import demo.types; 33 34 //#define ChipmunkDemoTextDrawString(...) 35 36 //#define Scale 3.0f 37 enum Scale = 0.70f; 38 enum LineHeight = 18.0f * Scale; 39 40 __gshared GLuint program; 41 __gshared GLuint texture; 42 43 struct v2f 44 { 45 GLfloat x = 0, y = 0; 46 } 47 48 struct Vertex 49 { 50 v2f vertex, tex_coord; 51 Color color; 52 } 53 54 struct Triangle 55 { 56 Vertex a, b, c; 57 } 58 59 __gshared GLuint vao = 0; 60 __gshared GLuint vbo = 0; 61 62 // char -> glyph indexes generated by the lonesock tool. 63 __gshared int[256] glyph_indexes; 64 65 void ChipmunkDemoTextInit() 66 { 67 GLint vshader = CompileShader(GL_VERTEX_SHADER, 68 q{ 69 #version 110 70 71 attribute vec2 vertex; 72 attribute vec2 tex_coord; 73 attribute vec4 color; 74 75 varying vec2 v_tex_coord; 76 varying vec4 v_color; 77 78 void main(){ 79 // TODO get rid of the GL 2.x matrix bit eventually? 80 gl_Position = gl_ModelViewProjectionMatrix * vec4(vertex, 0.0, 1.0); 81 82 v_color = color; 83 v_tex_coord = tex_coord; 84 } 85 }); 86 87 GLint fshader = CompileShader(GL_FRAGMENT_SHADER, 88 q{ 89 #version 110 90 91 uniform sampler2D u_texture; 92 93 varying vec2 v_tex_coord; 94 varying vec4 v_color; 95 96 float aa_step(float t1, float t2, float f) 97 { 98 //return step(t2, f); 99 return smoothstep(t1, t2, f); 100 } 101 102 void main() 103 { 104 float sdf = texture2D(u_texture, v_tex_coord).a; 105 106 //float fw = fwidth(sdf)*0.5; 107 float fw = length(vec2(dFdx(sdf), dFdy(sdf))) * 0.5; 108 109 float alpha = aa_step(0.5 - fw, 0.5 + fw, sdf); 110 gl_FragColor = v_color * (v_color.a * alpha); 111 112 // gl_FragColor = vec4(1, 0, 0, 1); 113 } 114 }); 115 116 program = LinkProgram(vshader, fshader); 117 CheckGLErrors(); 118 119 // GLint index = -1;//glGetUniformLocation(program, "u_texture"); 120 // glUniform1i(index, 0); 121 // CheckGLErrors(); 122 123 // Setu VBO and VAO. 124 version (OSX) 125 { 126 glGenVertexArraysAPPLE(1, &vao); 127 glBindVertexArrayAPPLE(vao); 128 } 129 else 130 { 131 glGenVertexArrays(1, &vao); 132 glBindVertexArray(vao); 133 } 134 135 glGenBuffers(1, &vbo); 136 glBindBuffer(GL_ARRAY_BUFFER, vbo); 137 138 mixin(SET_ATTRIBUTE("program", "Vertex", "vertex", "GL_FLOAT")); 139 mixin(SET_ATTRIBUTE("program", "Vertex", "tex_coord", "GL_FLOAT")); 140 mixin(SET_ATTRIBUTE("program", "Vertex", "color", "GL_FLOAT")); 141 142 glBindBuffer(GL_ARRAY_BUFFER, 0); 143 144 version (OSX) 145 { 146 glBindVertexArrayAPPLE(0); 147 } 148 else 149 { 150 glBindVertexArray(0); 151 } 152 153 CheckGLErrors(); 154 155 // Load the SDF font texture. 156 glGenTextures(1, &texture); 157 glBindTexture(GL_TEXTURE_2D, texture); 158 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, sdf_tex_width, sdf_tex_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, sdf_data.ptr); 159 glGenerateMipmap(GL_TEXTURE_2D); 160 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 161 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 162 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 163 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 164 CheckGLErrors(); 165 166 // Fill in the glyph index array. 167 for (int i = 0; i < sdf_num_chars; i++) 168 { 169 int char_index = sdf_spacing[i * 8]; 170 glyph_indexes[char_index] = i; 171 } 172 } 173 174 auto MAX(T)(T a, T b) 175 { 176 return a > b ? a : b; 177 } 178 179 size_t triangle_capacity = 0; 180 GLsizei triangle_count = 0; 181 Triangle* triangle_buffer = null; 182 183 Triangle* PushTriangles(size_t count) 184 { 185 if (triangle_count + count > triangle_capacity) 186 { 187 triangle_capacity += MAX(triangle_capacity, count); 188 triangle_buffer = cast(Triangle*)realloc(triangle_buffer, triangle_capacity * Triangle.sizeof); 189 } 190 191 Triangle* buffer = triangle_buffer + triangle_count; 192 triangle_count += count; 193 return buffer; 194 } 195 196 GLfloat PushChar(int character, GLfloat x, GLfloat y, Color color) 197 { 198 int i = glyph_indexes[character]; 199 GLfloat w = cast(GLfloat)sdf_tex_width; 200 GLfloat h = cast(GLfloat)sdf_tex_height; 201 202 GLfloat gw = cast(GLfloat)sdf_spacing[i * 8 + 3]; 203 GLfloat gh = cast(GLfloat)sdf_spacing[i * 8 + 4]; 204 205 GLfloat txmin = sdf_spacing[i * 8 + 1] / w; 206 GLfloat tymin = sdf_spacing[i * 8 + 2] / h; 207 GLfloat txmax = txmin + gw / w; 208 GLfloat tymax = tymin + gh / h; 209 210 GLfloat s = Scale / scale_factor; 211 GLfloat xmin = x + sdf_spacing[i * 8 + 5] / scale_factor * Scale; 212 GLfloat ymin = y + (sdf_spacing[i * 8 + 6] / scale_factor - gh) * Scale; 213 GLfloat xmax = xmin + gw * Scale; 214 GLfloat ymax = ymin + gh * Scale; 215 216 Vertex a = { { xmin, ymin }, { txmin, tymax }, color }; 217 Vertex b = { { xmin, ymax }, { txmin, tymin }, color }; 218 Vertex c = { { xmax, ymax }, { txmax, tymin }, color }; 219 Vertex d = { { xmax, ymin }, { txmax, tymax }, color }; 220 221 Triangle* triangles = PushTriangles(2); 222 Triangle t0 = { a, b, c }; 223 triangles[0] = t0; 224 Triangle t1 = { a, c, d }; 225 triangles[1] = t1; 226 227 return sdf_spacing[i * 8 + 7] * s; 228 } 229 230 void ChipmunkDemoTextDrawString(cpVect pos, in char[] str) 231 { 232 Color c = LAColor(1.0f, 1.0f); 233 GLfloat x = cast(GLfloat)pos.x, y = cast(GLfloat)pos.y; 234 235 for (size_t i = 0, len = str.length; i < len; i++) 236 { 237 if (str[i] == '\n') 238 { 239 y -= LineHeight; 240 x = cast(GLfloat)pos.x; 241 242 // } else if(str[i] == '*'){ // print out the last demo key 243 // glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, 'A' + demoCount - 1); 244 } 245 else 246 if (str[i] == '\0') 247 { 248 break; 249 } 250 else 251 { 252 x += cast(GLfloat)PushChar(str[i], x, y, c); 253 } 254 } 255 } 256 257 void ChipmunkDemoTextFlushRenderer() 258 { 259 // triangle_count = 0; 260 // ChipmunkDemoTextDrawString(cpv(-300, 0), "0.:,'"); 261 262 glBindBuffer(GL_ARRAY_BUFFER, vbo); 263 glBufferData(GL_ARRAY_BUFFER, Triangle.sizeof * triangle_count, triangle_buffer, GL_STREAM_DRAW); 264 265 glUseProgram(program); 266 267 version (OSX) 268 { 269 glBindVertexArrayAPPLE(vao); 270 } 271 else 272 { 273 glBindVertexArray(vao); 274 } 275 276 glDrawArrays(GL_TRIANGLES, 0, cast(GLsizei)(triangle_count * 3)); 277 278 CheckGLErrors(); 279 } 280 281 void ChipmunkDemoTextClearRenderer() 282 { 283 triangle_count = 0; 284 } 285 286 GLsizei pushed_triangle_count = 0; 287 288 void ChipmunkDemoTextPushRenderer() 289 { 290 pushed_triangle_count = triangle_count; 291 } 292 293 void ChipmunkDemoTextPopRenderer() 294 { 295 triangle_count = pushed_triangle_count; 296 }