├── .gitignore ├── README.md ├── todo.txt ├── zen_box2d.h ├── zen_gl.h ├── zen_glez.h ├── zen_glfw.h ├── zen_glfw_imgui.h ├── zen_lib.h ├── zen_lib ├── zen.h ├── zen_arr.h ├── zen_hashmap.h └── zen_math.h ├── zen_sdl.h ├── zen_sdl_audio.h ├── zen_sdl_imgui.h └── zen_squtil.h /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zen 2 | Single header file libraries for C/C++. 3 | 4 | 5 | ## Libraries 6 | 7 | Library | Description 8 | ------------ | ------------- 9 | zen_box2d.h| Debug rendering for Box2D 10 | zen_gl.h* | OpenGL utility 11 | zen_glez.h | Easy OpenGL Library 12 | zen_glfw.h | GLFW Wrapper for games 13 | zen_glfw_imgui.h | GLFW implementation for dear imgui 14 | zen_sdl_audio.h | SDL audio with no dependencies 15 | zen_sdl_imgui.h | SDL implementation for dear imgui 16 | zen_sdl.h | SDL Wrapper for games 17 | zen_squtil.h* | Squirrel Script Utility library 18 | > \* Library is in progress. Don't use it yet. 19 | 20 | ## zen_lib 21 | Library | Description 22 | ------------ | ------------- 23 | zen_arr.h| stb array and stretch buffer 24 | zen_hashmap.h | stb hash and map library 25 | zen_math.h | Math for games 26 | zen.h | Acme library 27 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | ; Script generated by the Inno Setup Script Wizard. 2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! 3 | 4 | #define BaseDir "..\" 5 | #define MyAppName "appname" 6 | #define MyAppVersion "4.2" 7 | #define MyAppPublisher "ZenToad Games" 8 | #define MyAppURL "https://url" 9 | #define MyAppExeName "rogue.exe" 10 | 11 | [Setup] 12 | ; NOTE: The value of AppId uniquely identifies this application. 13 | ; Do not use the same AppId value in installers for other applications. 14 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) 15 | AppId={{A3211E1F-D1A1-4151-838C-C95A11CCE019} 16 | AppName={#MyAppName} 17 | AppVersion={#MyAppVersion} 18 | ;AppVerName={#MyAppName} {#MyAppVersion} 19 | AppPublisher={#MyAppPublisher} 20 | AppPublisherURL={#MyAppURL} 21 | AppSupportURL={#MyAppURL} 22 | AppUpdatesURL={#MyAppURL} 23 | DefaultDirName={pf}\dirname 24 | DefaultGroupName={#MyAppName} 25 | OutputDir={#BaseDir}\Installation 26 | OutputBaseFilename=InstallFileName.{#MyAppVersion} 27 | SetupIconFile={#BaseDir}\support\import1.ico 28 | Compression=lzma 29 | ChangesAssociations=yes 30 | SolidCompression=yes 31 | LicenseFile={#BaseDir}\support\license.txt 32 | 33 | [Languages] 34 | Name: "english"; MessagesFile: "compiler:Default.isl" 35 | 36 | [Tasks] 37 | Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked 38 | 39 | [Files] 40 | Source: "{#BaseDir}\file1.bat"; DestDir: "{app}"; Flags: ignoreversion 41 | Source: "{#BaseDir}\file1.bat"; DestDir: "{app}"; Flags: ignoreversion 42 | Source: "{#BaseDir}\file1.bat"; DestDir: "{app}"; Flags: ignoreversion 43 | Source: "{#BaseDir}\file1.bat"; DestDir: "{app}"; Flags: ignoreversion 44 | Source: "{#BaseDir}\support\file1.bat"; DestDir: "{sys}"; DestName: "file1.bat"; Flags: sharedfile uninsnosharedfileprompt 64bit 45 | Source: "{#BaseDir}\support\file1.bat"; DestDir: "{sys}"; DestName: "file1.bat"; Flags: sharedfile uninsnosharedfileprompt 64bit 46 | Source: "{#BaseDir}\support\file1.bat"; DestDir: "{sys}"; DestName: "file1.bat"; Flags: sharedfile uninsnosharedfileprompt 64bit 47 | Source: "{#BaseDir}\support\file1.bat"; DestDir: "{sys}"; DestName: "file1.bat"; Flags: sharedfile uninsnosharedfileprompt 64bit 48 | Source: "{#BaseDir}\support\file1.bat"; DestDir: "{sys}"; DestName: "file1.bat"; Flags: sharedfile uninsnosharedfileprompt 64bit 49 | Source: "{#BaseDir}\jre\*"; DestDir: "{app}\jre"; Flags: ignoreversion recursesubdirs createallsubdirs 50 | Source: "{#BaseDir}\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion recursesubdirs createallsubdirs 51 | Source: "{#BaseDir}\bin\*"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs 52 | Source: "{#BaseDir}\support\*"; DestDir: "{app}\support"; Flags: ignoreversion recursesubdirs createallsubdirs 53 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files 54 | 55 | [Icons] 56 | Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\support\Transparent.ico" 57 | Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"; IconFilename: "{app}\support\delete.ico" 58 | Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon; IconFilename: "{app}\support\Transparent.ico" 59 | 60 | [Registry] 61 | ; Set the PATH 62 | Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "NAME"; ValueData: "{app}"; Flags: preservestringtype uninsdeletekey 63 | Root: HKCR; Subkey: ".ext"; ValueType: string; ValueName: ""; ValueData: 64 | "guidata"; Flags: uninsdeletevalue 65 | 66 | 67 | [Setup] 68 | ChangesEnvironment=yes 69 | 70 | [Run] 71 | Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: shellexec postinstall skipifsilent 72 | 73 | 74 | -------------------------------------------------------------------------------- /zen_box2d.h: -------------------------------------------------------------------------------- 1 | // 2 | // This is a modified version of the Box2D software 3 | // Copyright (c) 2006-2013 Erin Catto http://www.box2d.org 4 | // 5 | // This software is provided 'as-is', without any express or implied 6 | // warranty. In no event will the authors be held liable for any damages 7 | // arising from the use of this software. 8 | // Permission is granted to anyone to use this software for any purpose, 9 | // including commercial applications, and to alter it and redistribute it 10 | // freely, subject to the following restrictions: 11 | // 1. The origin of this software must not be misrepresented; you must not 12 | // claim that you wrote the original software. If you use this software 13 | // in a product, an acknowledgment in the product documentation would be 14 | // appreciated but is not required. 15 | // 2. Altered source versions must be plainly marked as such, and must not be 16 | // misrepresented as being the original software. 17 | // 3. This notice may not be removed or altered from any source distribution. 18 | // 19 | // 20 | 21 | #if !defined(__ZEN_BOX2D_H__) 22 | #define __ZEN_BOX2D_H__ 23 | 24 | 25 | #if defined(ZBOX_STATIC) 26 | #define ZBOXDEF static 27 | #else 28 | #define ZBOXDEF extern 29 | #endif 30 | 31 | #if defined(ZEN_LIB_DEV) 32 | #include "Box2D/Box2D.h" 33 | #endif 34 | 35 | 36 | struct b2AABB; 37 | struct GLRenderPoints; 38 | struct GLRenderLines; 39 | struct GLRenderTriangles; 40 | 41 | // 42 | struct Camera 43 | { 44 | Camera() 45 | { 46 | m_center.Set(0.0f, 0.0f); 47 | m_width = 780; 48 | m_height = 780; 49 | } 50 | 51 | b2Vec2 ConvertScreenToWorld(const b2Vec2& screenPoint); 52 | b2Vec2 ConvertWorldToScreen(const b2Vec2& worldPoint); 53 | void BuildProjectionMatrix(float32* m, float32 zBias); 54 | 55 | b2Vec2 m_center; 56 | int32 m_width; 57 | int32 m_height; 58 | }; 59 | 60 | // This class implements debug drawing callbacks that are invoked 61 | // inside b2World::Step. 62 | class DebugDraw : public b2Draw { 63 | 64 | public: 65 | DebugDraw(); 66 | ~DebugDraw(); 67 | 68 | void Create(); 69 | void Destroy(); 70 | 71 | void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override; 72 | 73 | void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override; 74 | 75 | void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) override; 76 | 77 | void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) override; 78 | 79 | void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override; 80 | 81 | void DrawTransform(const b2Transform& xf) override; 82 | 83 | void DrawPoint(const b2Vec2& p, float32 size, const b2Color& color) override; 84 | 85 | void DrawString(int x, int y, const char* string, ...); 86 | 87 | void DrawString(const b2Vec2& p, const char* string, ...); 88 | 89 | void DrawAABB(b2AABB* aabb, const b2Color& color); 90 | 91 | void Flush(); 92 | 93 | private: 94 | GLRenderPoints* m_points; 95 | GLRenderLines* m_lines; 96 | GLRenderTriangles* m_triangles; 97 | }; 98 | 99 | 100 | #endif // __ZEN_BOX2D_H__ 101 | 102 | 103 | #if defined(ZEN_BOX2D_IMPLEMENTATION) || defined(ZEN_LIB_DEV) 104 | 105 | 106 | #if defined(ZEN_LIB_DEV) 107 | #include 108 | #include 109 | #endif 110 | 111 | #define BUFFER_OFFSET(x) ((const void*) (x)) 112 | 113 | DebugDraw g_debugDraw; 114 | Camera g_camera; 115 | 116 | b2Vec2 Camera::ConvertScreenToWorld(const b2Vec2& ps) 117 | { 118 | float32 w = float32(m_width); 119 | float32 h = float32(m_height); 120 | float32 u = ps.x / w; 121 | float32 v = (h - ps.y) / h; 122 | 123 | float32 ratio = w / h; 124 | b2Vec2 extents(ratio * 25.0f, 25.0f); 125 | extents *= 1.0f; 126 | 127 | b2Vec2 lower = m_center - extents; 128 | b2Vec2 upper = m_center + extents; 129 | 130 | b2Vec2 pw; 131 | pw.x = (1.0f - u) * lower.x + u * upper.x; 132 | pw.y = (1.0f - v) * lower.y + v * upper.y; 133 | printf("screen to world: (%f, %f)\n", ps.x, ps.y); 134 | return pw; 135 | } 136 | 137 | // 138 | b2Vec2 Camera::ConvertWorldToScreen(const b2Vec2& pw) 139 | { 140 | float32 w = float32(m_width); 141 | float32 h = float32(m_height); 142 | b2Vec2 extents(w, h); 143 | 144 | b2Vec2 lower = m_center - extents; 145 | b2Vec2 upper = m_center + extents; 146 | 147 | float32 u = (pw.x - lower.x) / (upper.x - lower.x); 148 | float32 v = (pw.y - lower.y) / (upper.y - lower.y); 149 | 150 | b2Vec2 ps; 151 | ps.x = u * w; 152 | ps.y = (1.0f - v) * h; 153 | 154 | printf("World to screen: (%f, %f)\n", ps.x, ps.y); 155 | return ps; 156 | } 157 | 158 | // Convert from world coordinates to normalized device coordinates. 159 | // http://www.songho.ca/opengl/gl_projectionmatrix.html 160 | void Camera::BuildProjectionMatrix(float32* m, float32 zBias) 161 | { 162 | float32 w = float32(m_width); 163 | float32 h = float32(m_height); 164 | b2Vec2 extents(w, h); 165 | 166 | b2Vec2 lower = m_center - extents; 167 | b2Vec2 upper = m_center + extents; 168 | 169 | m[0] = 2.0f / (upper.x - lower.x); 170 | m[1] = 0.0f; 171 | m[2] = 0.0f; 172 | m[3] = 0.0f; 173 | 174 | m[4] = 0.0f; 175 | m[5] = 2.0f / (upper.y - lower.y); 176 | m[6] = 0.0f; 177 | m[7] = 0.0f; 178 | 179 | m[8] = 0.0f; 180 | m[9] = 0.0f; 181 | m[10] = 1.0f; 182 | m[11] = 0.0f; 183 | 184 | m[12] = -(upper.x + lower.x) / (upper.x - lower.x); 185 | m[13] = -(upper.y + lower.y) / (upper.y - lower.y); 186 | //m[14] = zBias; 187 | m[14] = 0.0f; 188 | m[15] = 1.0f; 189 | } 190 | 191 | // 192 | static void sCheckGLError() 193 | { 194 | GLenum errCode = glGetError(); 195 | if (errCode != GL_NO_ERROR) 196 | { 197 | fprintf(stderr, "OpenGL error = %d\n", errCode); 198 | assert(false); 199 | } 200 | } 201 | 202 | // Prints shader compilation errors 203 | static void sPrintLog(GLuint object) 204 | { 205 | GLint log_length = 0; 206 | if (glIsShader(object)) 207 | glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length); 208 | else if (glIsProgram(object)) 209 | glGetProgramiv(object, GL_INFO_LOG_LENGTH, &log_length); 210 | else 211 | { 212 | fprintf(stderr, "printlog: Not a shader or a program\n"); 213 | return; 214 | } 215 | 216 | char* log = (char*)malloc(log_length); 217 | 218 | if (glIsShader(object)) 219 | glGetShaderInfoLog(object, log_length, NULL, log); 220 | else if (glIsProgram(object)) 221 | glGetProgramInfoLog(object, log_length, NULL, log); 222 | 223 | fprintf(stderr, "%s", log); 224 | free(log); 225 | } 226 | 227 | 228 | // 229 | static GLuint sCreateShaderFromString(const char* source, GLenum type) 230 | { 231 | GLuint res = glCreateShader(type); 232 | const char* sources[] = { source }; 233 | glShaderSource(res, 1, sources, NULL); 234 | glCompileShader(res); 235 | GLint compile_ok = GL_FALSE; 236 | glGetShaderiv(res, GL_COMPILE_STATUS, &compile_ok); 237 | if (compile_ok == GL_FALSE) 238 | { 239 | fprintf(stderr, "Error compiling shader of type %d!\n", type); 240 | sPrintLog(res); 241 | glDeleteShader(res); 242 | return 0; 243 | } 244 | 245 | return res; 246 | } 247 | 248 | // 249 | static GLuint sCreateShaderProgram(const char* vs, const char* fs) 250 | { 251 | GLuint vsId = sCreateShaderFromString(vs, GL_VERTEX_SHADER); 252 | GLuint fsId = sCreateShaderFromString(fs, GL_FRAGMENT_SHADER); 253 | assert(vsId != 0 && fsId != 0); 254 | 255 | GLuint programId = glCreateProgram(); 256 | glAttachShader(programId, vsId); 257 | glAttachShader(programId, fsId); 258 | glBindFragDataLocation(programId, 0, "color"); 259 | glLinkProgram(programId); 260 | 261 | glDeleteShader(vsId); 262 | glDeleteShader(fsId); 263 | 264 | GLint status = GL_FALSE; 265 | glGetProgramiv(programId, GL_LINK_STATUS, &status); 266 | assert(status != GL_FALSE); 267 | 268 | return programId; 269 | } 270 | 271 | // 272 | struct GLRenderPoints 273 | { 274 | void Create() 275 | { 276 | const char* vs = \ 277 | "#version 400\n" 278 | "uniform mat4 projectionMatrix;\n" 279 | "layout(location = 0) in vec2 v_position;\n" 280 | "layout(location = 1) in vec4 v_color;\n" 281 | "layout(location = 2) in float v_size;\n" 282 | "out vec4 f_color;\n" 283 | "void main(void)\n" 284 | "{\n" 285 | " f_color = v_color;\n" 286 | " gl_Position = projectionMatrix * vec4(v_position, 0.0f, 1.0f);\n" 287 | " gl_PointSize = v_size;\n" 288 | "}\n"; 289 | 290 | const char* fs = \ 291 | "#version 400\n" 292 | "in vec4 f_color;\n" 293 | "out vec4 color;\n" 294 | "void main(void)\n" 295 | "{\n" 296 | " color = f_color;\n" 297 | "}\n"; 298 | 299 | m_programId = sCreateShaderProgram(vs, fs); 300 | m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix"); 301 | m_vertexAttribute = 0; 302 | m_colorAttribute = 1; 303 | m_sizeAttribute = 2; 304 | 305 | // Generate 306 | glGenVertexArrays(1, &m_vaoId); 307 | glGenBuffers(3, m_vboIds); 308 | 309 | glBindVertexArray(m_vaoId); 310 | glEnableVertexAttribArray(m_vertexAttribute); 311 | glEnableVertexAttribArray(m_colorAttribute); 312 | glEnableVertexAttribArray(m_sizeAttribute); 313 | 314 | // Vertex buffer 315 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]); 316 | glVertexAttribPointer(m_vertexAttribute, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 317 | glBufferData(GL_ARRAY_BUFFER, sizeof(m_vertices), m_vertices, GL_DYNAMIC_DRAW); 318 | 319 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]); 320 | glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 321 | glBufferData(GL_ARRAY_BUFFER, sizeof(m_colors), m_colors, GL_DYNAMIC_DRAW); 322 | 323 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); 324 | glVertexAttribPointer(m_sizeAttribute, 1, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 325 | glBufferData(GL_ARRAY_BUFFER, sizeof(m_sizes), m_sizes, GL_DYNAMIC_DRAW); 326 | 327 | sCheckGLError(); 328 | 329 | // Cleanup 330 | glBindBuffer(GL_ARRAY_BUFFER, 0); 331 | glBindVertexArray(0); 332 | 333 | m_count = 0; 334 | } 335 | 336 | void Destroy() 337 | { 338 | if (m_vaoId) 339 | { 340 | glDeleteVertexArrays(1, &m_vaoId); 341 | glDeleteBuffers(2, m_vboIds); 342 | m_vaoId = 0; 343 | } 344 | 345 | if (m_programId) 346 | { 347 | glDeleteProgram(m_programId); 348 | m_programId = 0; 349 | } 350 | } 351 | 352 | void Vertex(const b2Vec2& v, const b2Color& c, float32 size) 353 | { 354 | if (m_count == e_maxVertices) 355 | Flush(); 356 | 357 | m_vertices[m_count] = v; 358 | m_colors[m_count] = c; 359 | m_sizes[m_count] = size; 360 | ++m_count; 361 | } 362 | 363 | void Flush() 364 | { 365 | if (m_count == 0) 366 | return; 367 | 368 | glUseProgram(m_programId); 369 | 370 | float32 proj[16] = { 0.0f }; 371 | g_camera.BuildProjectionMatrix(proj, 0.0f); 372 | 373 | glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, proj); 374 | 375 | glBindVertexArray(m_vaoId); 376 | 377 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]); 378 | glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b2Vec2), m_vertices); 379 | 380 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]); 381 | glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b2Color), m_colors); 382 | 383 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[2]); 384 | glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(float32), m_sizes); 385 | 386 | glEnable(GL_PROGRAM_POINT_SIZE); 387 | glDrawArrays(GL_POINTS, 0, m_count); 388 | glDisable(GL_PROGRAM_POINT_SIZE); 389 | 390 | sCheckGLError(); 391 | 392 | glBindBuffer(GL_ARRAY_BUFFER, 0); 393 | glBindVertexArray(0); 394 | glUseProgram(0); 395 | 396 | m_count = 0; 397 | } 398 | 399 | enum { e_maxVertices = 512 }; 400 | b2Vec2 m_vertices[e_maxVertices]; 401 | b2Color m_colors[e_maxVertices]; 402 | float32 m_sizes[e_maxVertices]; 403 | 404 | int32 m_count; 405 | 406 | GLuint m_vaoId; 407 | GLuint m_vboIds[3]; 408 | GLuint m_programId; 409 | GLint m_projectionUniform; 410 | GLint m_vertexAttribute; 411 | GLint m_colorAttribute; 412 | GLint m_sizeAttribute; 413 | }; 414 | 415 | // 416 | struct GLRenderLines 417 | { 418 | void Create() 419 | { 420 | const char* vs = \ 421 | "#version 400\n" 422 | "uniform mat4 projectionMatrix;\n" 423 | "layout(location = 0) in vec2 v_position;\n" 424 | "layout(location = 1) in vec4 v_color;\n" 425 | "out vec4 f_color;\n" 426 | "void main(void)\n" 427 | "{\n" 428 | " f_color = v_color;\n" 429 | " gl_Position = projectionMatrix * vec4(v_position, 0.0f, 1.0f);\n" 430 | "}\n"; 431 | 432 | const char* fs = \ 433 | "#version 400\n" 434 | "in vec4 f_color;\n" 435 | "out vec4 color;\n" 436 | "void main(void)\n" 437 | "{\n" 438 | " color = f_color;\n" 439 | "}\n"; 440 | 441 | m_programId = sCreateShaderProgram(vs, fs); 442 | m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix"); 443 | m_vertexAttribute = 0; 444 | m_colorAttribute = 1; 445 | 446 | // Generate 447 | glGenVertexArrays(1, &m_vaoId); 448 | glGenBuffers(2, m_vboIds); 449 | 450 | glBindVertexArray(m_vaoId); 451 | glEnableVertexAttribArray(m_vertexAttribute); 452 | glEnableVertexAttribArray(m_colorAttribute); 453 | 454 | // Vertex buffer 455 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]); 456 | glVertexAttribPointer(m_vertexAttribute, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 457 | glBufferData(GL_ARRAY_BUFFER, sizeof(m_vertices), m_vertices, GL_DYNAMIC_DRAW); 458 | 459 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]); 460 | glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 461 | glBufferData(GL_ARRAY_BUFFER, sizeof(m_colors), m_colors, GL_DYNAMIC_DRAW); 462 | 463 | sCheckGLError(); 464 | 465 | // Cleanup 466 | glBindBuffer(GL_ARRAY_BUFFER, 0); 467 | glBindVertexArray(0); 468 | 469 | m_count = 0; 470 | } 471 | 472 | void Destroy() 473 | { 474 | if (m_vaoId) 475 | { 476 | glDeleteVertexArrays(1, &m_vaoId); 477 | glDeleteBuffers(2, m_vboIds); 478 | m_vaoId = 0; 479 | } 480 | 481 | if (m_programId) 482 | { 483 | glDeleteProgram(m_programId); 484 | m_programId = 0; 485 | } 486 | } 487 | 488 | void Vertex(const b2Vec2& v, const b2Color& c) 489 | { 490 | if (m_count == e_maxVertices) 491 | Flush(); 492 | 493 | m_vertices[m_count] = v; 494 | m_colors[m_count] = c; 495 | ++m_count; 496 | } 497 | 498 | void Flush() 499 | { 500 | if (m_count == 0) 501 | return; 502 | 503 | glUseProgram(m_programId); 504 | 505 | float32 proj[16] = { 0.0f }; 506 | g_camera.BuildProjectionMatrix(proj, 0.1f); 507 | 508 | glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, proj); 509 | 510 | glBindVertexArray(m_vaoId); 511 | 512 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]); 513 | glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b2Vec2), m_vertices); 514 | 515 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]); 516 | glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b2Color), m_colors); 517 | 518 | glDrawArrays(GL_LINES, 0, m_count); 519 | 520 | sCheckGLError(); 521 | 522 | glBindBuffer(GL_ARRAY_BUFFER, 0); 523 | glBindVertexArray(0); 524 | glUseProgram(0); 525 | 526 | m_count = 0; 527 | } 528 | 529 | enum { e_maxVertices = 2 * 512 }; 530 | b2Vec2 m_vertices[e_maxVertices]; 531 | b2Color m_colors[e_maxVertices]; 532 | 533 | int32 m_count; 534 | 535 | GLuint m_vaoId; 536 | GLuint m_vboIds[2]; 537 | GLuint m_programId; 538 | GLint m_projectionUniform; 539 | GLint m_vertexAttribute; 540 | GLint m_colorAttribute; 541 | }; 542 | 543 | // 544 | struct GLRenderTriangles 545 | { 546 | void Create() 547 | { 548 | const char* vs = \ 549 | "#version 400\n" 550 | "uniform mat4 projectionMatrix;\n" 551 | "layout(location = 0) in vec2 v_position;\n" 552 | "layout(location = 1) in vec4 v_color;\n" 553 | "out vec4 f_color;\n" 554 | "void main(void)\n" 555 | "{\n" 556 | " f_color = v_color;\n" 557 | " gl_Position = projectionMatrix * vec4(v_position, 0.0f, 1.0f);\n" 558 | "}\n"; 559 | 560 | const char* fs = \ 561 | "#version 400\n" 562 | "in vec4 f_color;\n" 563 | "out vec4 color;\n" 564 | "void main(void)\n" 565 | "{\n" 566 | " color = f_color;\n" 567 | "}\n"; 568 | 569 | m_programId = sCreateShaderProgram(vs, fs); 570 | m_projectionUniform = glGetUniformLocation(m_programId, "projectionMatrix"); 571 | m_vertexAttribute = 0; 572 | m_colorAttribute = 1; 573 | 574 | // Generate 575 | glGenVertexArrays(1, &m_vaoId); 576 | glGenBuffers(2, m_vboIds); 577 | 578 | glBindVertexArray(m_vaoId); 579 | glEnableVertexAttribArray(m_vertexAttribute); 580 | glEnableVertexAttribArray(m_colorAttribute); 581 | 582 | // Vertex buffer 583 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]); 584 | glVertexAttribPointer(m_vertexAttribute, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 585 | glBufferData(GL_ARRAY_BUFFER, sizeof(m_vertices), m_vertices, GL_DYNAMIC_DRAW); 586 | 587 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]); 588 | glVertexAttribPointer(m_colorAttribute, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 589 | glBufferData(GL_ARRAY_BUFFER, sizeof(m_colors), m_colors, GL_DYNAMIC_DRAW); 590 | 591 | sCheckGLError(); 592 | 593 | // Cleanup 594 | glBindBuffer(GL_ARRAY_BUFFER, 0); 595 | glBindVertexArray(0); 596 | 597 | m_count = 0; 598 | } 599 | 600 | void Destroy() 601 | { 602 | if (m_vaoId) 603 | { 604 | glDeleteVertexArrays(1, &m_vaoId); 605 | glDeleteBuffers(2, m_vboIds); 606 | m_vaoId = 0; 607 | } 608 | 609 | if (m_programId) 610 | { 611 | glDeleteProgram(m_programId); 612 | m_programId = 0; 613 | } 614 | } 615 | 616 | void Vertex(const b2Vec2& v, const b2Color& c) 617 | { 618 | if (m_count == e_maxVertices) 619 | Flush(); 620 | 621 | m_vertices[m_count] = v; 622 | m_colors[m_count] = c; 623 | ++m_count; 624 | } 625 | 626 | void Flush() 627 | { 628 | if (m_count == 0) 629 | return; 630 | 631 | glUseProgram(m_programId); 632 | 633 | float32 proj[16] = { 0.0f }; 634 | g_camera.BuildProjectionMatrix(proj, 0.2f); 635 | 636 | glUniformMatrix4fv(m_projectionUniform, 1, GL_FALSE, proj); 637 | 638 | glBindVertexArray(m_vaoId); 639 | 640 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[0]); 641 | glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b2Vec2), m_vertices); 642 | 643 | glBindBuffer(GL_ARRAY_BUFFER, m_vboIds[1]); 644 | glBufferSubData(GL_ARRAY_BUFFER, 0, m_count * sizeof(b2Color), m_colors); 645 | 646 | glEnable(GL_BLEND); 647 | glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 648 | glDrawArrays(GL_TRIANGLES, 0, m_count); 649 | glDisable(GL_BLEND); 650 | 651 | sCheckGLError(); 652 | 653 | glBindBuffer(GL_ARRAY_BUFFER, 0); 654 | glBindVertexArray(0); 655 | glUseProgram(0); 656 | 657 | m_count = 0; 658 | } 659 | 660 | enum { e_maxVertices = 3 * 512 }; 661 | b2Vec2 m_vertices[e_maxVertices]; 662 | b2Color m_colors[e_maxVertices]; 663 | 664 | int32 m_count; 665 | 666 | GLuint m_vaoId; 667 | GLuint m_vboIds[2]; 668 | GLuint m_programId; 669 | GLint m_projectionUniform; 670 | GLint m_vertexAttribute; 671 | GLint m_colorAttribute; 672 | }; 673 | 674 | // 675 | DebugDraw::DebugDraw() 676 | { 677 | m_points = NULL; 678 | m_lines = NULL; 679 | m_triangles = NULL; 680 | } 681 | 682 | // 683 | DebugDraw::~DebugDraw() 684 | { 685 | b2Assert(m_points == NULL); 686 | b2Assert(m_lines == NULL); 687 | b2Assert(m_triangles == NULL); 688 | } 689 | 690 | // 691 | void DebugDraw::Create() 692 | { 693 | m_points = new GLRenderPoints; 694 | m_points->Create(); 695 | m_lines = new GLRenderLines; 696 | m_lines->Create(); 697 | m_triangles = new GLRenderTriangles; 698 | m_triangles->Create(); 699 | } 700 | 701 | // 702 | void DebugDraw::Destroy() 703 | { 704 | m_points->Destroy(); 705 | delete m_points; 706 | m_points = NULL; 707 | 708 | m_lines->Destroy(); 709 | delete m_lines; 710 | m_lines = NULL; 711 | 712 | m_triangles->Destroy(); 713 | delete m_triangles; 714 | m_triangles = NULL; 715 | } 716 | 717 | // 718 | void DebugDraw::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) 719 | { 720 | b2Vec2 p1 = vertices[vertexCount - 1]; 721 | for (int32 i = 0; i < vertexCount; ++i) 722 | { 723 | b2Vec2 p2 = vertices[i]; 724 | m_lines->Vertex(p1, color); 725 | m_lines->Vertex(p2, color); 726 | p1 = p2; 727 | } 728 | } 729 | 730 | // 731 | void DebugDraw::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) 732 | { 733 | b2Color fillColor(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); 734 | 735 | for (int32 i = 1; i < vertexCount - 1; ++i) 736 | { 737 | m_triangles->Vertex(vertices[0], fillColor); 738 | m_triangles->Vertex(vertices[i], fillColor); 739 | m_triangles->Vertex(vertices[i+1], fillColor); 740 | } 741 | 742 | b2Vec2 p1 = vertices[vertexCount - 1]; 743 | for (int32 i = 0; i < vertexCount; ++i) 744 | { 745 | b2Vec2 p2 = vertices[i]; 746 | m_lines->Vertex(p1, color); 747 | m_lines->Vertex(p2, color); 748 | p1 = p2; 749 | } 750 | } 751 | 752 | // 753 | void DebugDraw::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) 754 | { 755 | const float32 k_segments = 16.0f; 756 | const float32 k_increment = 2.0f * b2_pi / k_segments; 757 | float32 sinInc = sinf(k_increment); 758 | float32 cosInc = cosf(k_increment); 759 | b2Vec2 r1(1.0f, 0.0f); 760 | b2Vec2 v1 = center + radius * r1; 761 | for (int32 i = 0; i < k_segments; ++i) 762 | { 763 | // Perform rotation to avoid additional trigonometry. 764 | b2Vec2 r2; 765 | r2.x = cosInc * r1.x - sinInc * r1.y; 766 | r2.y = sinInc * r1.x + cosInc * r1.y; 767 | b2Vec2 v2 = center + radius * r2; 768 | m_lines->Vertex(v1, color); 769 | m_lines->Vertex(v2, color); 770 | r1 = r2; 771 | v1 = v2; 772 | } 773 | } 774 | 775 | // 776 | void DebugDraw::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) 777 | { 778 | const float32 k_segments = 16.0f; 779 | const float32 k_increment = 2.0f * b2_pi / k_segments; 780 | float32 sinInc = sinf(k_increment); 781 | float32 cosInc = cosf(k_increment); 782 | b2Vec2 v0 = center; 783 | b2Vec2 r1(cosInc, sinInc); 784 | b2Vec2 v1 = center + radius * r1; 785 | b2Color fillColor(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); 786 | for (int32 i = 0; i < k_segments; ++i) 787 | { 788 | // Perform rotation to avoid additional trigonometry. 789 | b2Vec2 r2; 790 | r2.x = cosInc * r1.x - sinInc * r1.y; 791 | r2.y = sinInc * r1.x + cosInc * r1.y; 792 | b2Vec2 v2 = center + radius * r2; 793 | m_triangles->Vertex(v0, fillColor); 794 | m_triangles->Vertex(v1, fillColor); 795 | m_triangles->Vertex(v2, fillColor); 796 | r1 = r2; 797 | v1 = v2; 798 | } 799 | 800 | r1.Set(1.0f, 0.0f); 801 | v1 = center + radius * r1; 802 | for (int32 i = 0; i < k_segments; ++i) 803 | { 804 | b2Vec2 r2; 805 | r2.x = cosInc * r1.x - sinInc * r1.y; 806 | r2.y = sinInc * r1.x + cosInc * r1.y; 807 | b2Vec2 v2 = center + radius * r2; 808 | m_lines->Vertex(v1, color); 809 | m_lines->Vertex(v2, color); 810 | r1 = r2; 811 | v1 = v2; 812 | } 813 | 814 | // Draw a line fixed in the circle to animate rotation. 815 | b2Vec2 p = center + radius * axis; 816 | m_lines->Vertex(center, color); 817 | m_lines->Vertex(p, color); 818 | } 819 | 820 | // 821 | void DebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) 822 | { 823 | m_lines->Vertex(p1, color); 824 | m_lines->Vertex(p2, color); 825 | } 826 | 827 | // 828 | void DebugDraw::DrawTransform(const b2Transform& xf) 829 | { 830 | const float32 k_axisScale = 0.4f; 831 | b2Color red(1.0f, 0.0f, 0.0f); 832 | b2Color green(0.0f, 1.0f, 0.0f); 833 | b2Vec2 p1 = xf.p, p2; 834 | 835 | m_lines->Vertex(p1, red); 836 | p2 = p1 + k_axisScale * xf.q.GetXAxis(); 837 | m_lines->Vertex(p2, red); 838 | 839 | m_lines->Vertex(p1, green); 840 | p2 = p1 + k_axisScale * xf.q.GetYAxis(); 841 | m_lines->Vertex(p2, green); 842 | } 843 | 844 | // 845 | void DebugDraw::DrawPoint(const b2Vec2& p, float32 size, const b2Color& color) 846 | { 847 | m_points->Vertex(p, color, size); 848 | } 849 | 850 | // 851 | void DebugDraw::DrawString(int x, int y, const char *string, ...) 852 | { 853 | va_list arg; 854 | va_start(arg, string); 855 | ImGui::Begin("Overlay", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar); 856 | ImGui::SetCursorPos(ImVec2(float(x), float(y))); 857 | ImGui::TextColoredV(ImColor(230, 153, 153, 255), string, arg); 858 | ImGui::End(); 859 | va_end(arg); 860 | } 861 | 862 | // 863 | void DebugDraw::DrawString(const b2Vec2& pw, const char *string, ...) 864 | { 865 | b2Vec2 ps = g_camera.ConvertWorldToScreen(pw); 866 | 867 | va_list arg; 868 | va_start(arg, string); 869 | ImGui::Begin("Overlay", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar); 870 | ImGui::SetCursorPos(ImVec2(ps.x, ps.y)); 871 | ImGui::TextColoredV(ImColor(230, 153, 153, 255), string, arg); 872 | ImGui::End(); 873 | va_end(arg); 874 | } 875 | 876 | // 877 | void DebugDraw::DrawAABB(b2AABB* aabb, const b2Color& c) 878 | { 879 | b2Vec2 p1 = aabb->lowerBound; 880 | b2Vec2 p2 = b2Vec2(aabb->upperBound.x, aabb->lowerBound.y); 881 | b2Vec2 p3 = aabb->upperBound; 882 | b2Vec2 p4 = b2Vec2(aabb->lowerBound.x, aabb->upperBound.y); 883 | 884 | m_lines->Vertex(p1, c); 885 | m_lines->Vertex(p2, c); 886 | 887 | m_lines->Vertex(p2, c); 888 | m_lines->Vertex(p3, c); 889 | 890 | m_lines->Vertex(p3, c); 891 | m_lines->Vertex(p4, c); 892 | 893 | m_lines->Vertex(p4, c); 894 | m_lines->Vertex(p1, c); 895 | } 896 | 897 | // 898 | void DebugDraw::Flush() 899 | { 900 | m_triangles->Flush(); 901 | m_lines->Flush(); 902 | m_points->Flush(); 903 | } 904 | 905 | 906 | #endif // ZEN_BOX2D_IMPLEMENTATION 907 | 908 | -------------------------------------------------------------------------------- /zen_glfw.h: -------------------------------------------------------------------------------- 1 | /* zen_glfw.h - v0.42 - GLFW wrapper -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_GLFW_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_GLFW_IMPLEMENTATION 11 | #include "zen_glfw.h" 12 | 13 | zlib license: 14 | Full license at bottom of file. 15 | 16 | */ 17 | 18 | #ifndef __ZEN_GLFW_H__ 19 | #define __ZEN_GLFW_H__ 20 | 21 | 22 | #ifdef ZEN_GLFW_STATIC 23 | #define ZGLFWDEF static 24 | #else 25 | #define ZGLFWDEF extern 26 | #endif 27 | 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | 34 | #if defined(ZEN_LIB_DEV) 35 | #include "GLFW/glfw3.h" 36 | #if defined(_WIN32) 37 | #define GLFW_EXPOSE_NATIVE_WIN32 38 | #include "GLFW/glfw3native.h" 39 | #endif 40 | #endif 41 | 42 | 43 | #define ZGLFW_KEY_DOWN(glfw,key) glfw->keys[GLFW_KEY_##key] 44 | #define ZGLFW_KEY_DOWN_ONCE(glfw,key) glfw->keys[GLFW_KEY_##key] == 1 45 | 46 | 47 | typedef struct ZGLFW { 48 | 49 | const char *window_title; 50 | 51 | int major_version; 52 | int minor_version; 53 | int window_cursor_mode; 54 | int window_background; 55 | int should_close; 56 | 57 | int window_width; 58 | int window_height; 59 | float window_widthf; 60 | float window_heightf; 61 | 62 | int display_width; 63 | int display_height; 64 | float display_widthf; 65 | float display_heightf; 66 | 67 | double current_time; 68 | double last_time; 69 | double delta_time; 70 | double total_time; 71 | int total_frames; 72 | 73 | float mouse_x; 74 | float mouse_y; 75 | float mouse_dx; 76 | float mouse_dy; 77 | float last_mouse_x; 78 | float last_mouse_y; 79 | float mouse_scroll; 80 | int mouse_button[3]; 81 | 82 | GLFWwindow* window; 83 | 84 | void (*error_callback)(int, const char*); 85 | void (*key_callback)(GLFWwindow*, int, int, int, int); 86 | void (*window_size_callback)(GLFWwindow*, int, int); 87 | void (*character_callback)(GLFWwindow*, unsigned int); 88 | void (*mouse_button_callback)(GLFWwindow*, int, int, int); 89 | void (*scroll_callback)(GLFWwindow*, double, double); 90 | 91 | int keys[GLFW_KEY_LAST]; 92 | 93 | } ZGLFW; 94 | 95 | 96 | ZGLFWDEF ZGLFW *zglfw_create(const char *title, int width, int height, int major = 4, int minor = 4); 97 | ZGLFWDEF void zglfw_init(ZGLFW *glfw); 98 | ZGLFWDEF void zglfw_show_window(ZGLFW *glfw); 99 | ZGLFWDEF int zglfw_is_running(ZGLFW *glfw); 100 | ZGLFWDEF void zglfw_begin(ZGLFW *glfw); 101 | ZGLFWDEF void zglfw_end(ZGLFW *glfw); 102 | ZGLFWDEF void zglfw_quit(ZGLFW *glfw); 103 | ZGLFWDEF void zglfw_destroy(ZGLFW *glfw); 104 | 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | 110 | 111 | 112 | #endif //__ZEN_GLFW_H__ 113 | 114 | 115 | 116 | //------------------------------------------ 117 | // Implementation 118 | //------------------------------------------ 119 | // 120 | #if defined(ZEN_GLFW_IMPLEMENTATION) || defined(ZEN_LIB_DEV) 121 | 122 | 123 | #if defined(ZEN_LIB_DEV) 124 | #include 125 | #include "zen_lib/zen.h" 126 | #endif 127 | 128 | 129 | typedef void* (* GLADloadproc)(const char *name); 130 | int gladLoadGLLoader(GLADloadproc load); 131 | 132 | 133 | static void zglfw_default_error_callback(int, const char *description) { 134 | fprintf(stderr, "Error: %s\n", description); 135 | } 136 | 137 | 138 | static void zglfw_default_key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { 139 | ZGLFW *glfw = (ZGLFW *)glfwGetWindowUserPointer(window); 140 | if (glfw) { 141 | if (action) { 142 | glfw->keys[key]++; 143 | } else { 144 | glfw->keys[key] = 0; 145 | } 146 | } 147 | } 148 | 149 | 150 | static void zglfw_default_window_size_callback(GLFWwindow*, int width, int height) { 151 | glViewport(0, 0, width, height); 152 | } 153 | 154 | 155 | static void zglfw_default_character_callback(GLFWwindow*, unsigned int character) { 156 | zout("Types: %c", character); 157 | } 158 | 159 | 160 | static void zglfw_default_mouse_button_callback(GLFWwindow *window, int button, int action, int) { 161 | ZGLFW *glfw = (ZGLFW *)glfwGetWindowUserPointer(window); 162 | if (glfw) { 163 | if (action == GLFW_PRESS) 164 | glfw->mouse_button[button] = 1; 165 | else 166 | glfw->mouse_button[button] = 0; 167 | } 168 | } 169 | 170 | 171 | static void zglfw_default_scroll_callback(GLFWwindow *window, double /*xoffset*/, double yoffset) { 172 | ZGLFW *glfw = (ZGLFW *)glfwGetWindowUserPointer(window); 173 | if (glfw) { 174 | glfw->mouse_scroll += yoffset; 175 | } 176 | } 177 | 178 | 179 | ZGLFWDEF ZGLFW *zglfw_create(const char *title, int width, int height, int major, int minor) { 180 | 181 | 182 | ZGLFW *glfw = ZEN_CALLOC(ZGLFW, 1); 183 | GB_ASSERT_NOT_NULL(glfw); 184 | 185 | glfw->window_title = title; 186 | glfw->major_version = major; 187 | glfw->minor_version = minor; 188 | glfw->window_width = width; 189 | glfw->window_height = height; 190 | glfw->window_background = 0xFF333333; 191 | glfw->window_cursor_mode = GLFW_CURSOR_NORMAL; 192 | 193 | return glfw; 194 | 195 | } 196 | 197 | 198 | ZGLFWDEF void zglfw_destroy(ZGLFW *glfw) { 199 | free(glfw); 200 | } 201 | 202 | 203 | ZGLFWDEF void zglfw_init(ZGLFW *glfw) { 204 | 205 | if (glfw->error_callback) { 206 | glfwSetErrorCallback(glfw->error_callback); 207 | } else { 208 | glfwSetErrorCallback(zglfw_default_error_callback); 209 | } 210 | 211 | if (!glfwInit()) { 212 | exit(EXIT_FAILURE); 213 | } 214 | 215 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, glfw->major_version); 216 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, glfw->minor_version); 217 | glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); 218 | 219 | glfwWindowHint(GLFW_SAMPLES, 4); 220 | 221 | glfw->window = glfwCreateWindow(glfw->window_width, glfw->window_height, glfw->window_title, NULL, NULL); 222 | if (!glfw->window) { 223 | glfwTerminate(); 224 | exit(EXIT_FAILURE); 225 | } 226 | 227 | glfwSetWindowUserPointer(glfw->window, glfw); 228 | 229 | if (glfw->key_callback) { 230 | glfwSetKeyCallback(glfw->window, glfw->key_callback); 231 | } else { 232 | glfwSetKeyCallback(glfw->window, zglfw_default_key_callback); 233 | } 234 | 235 | if (glfw->window_size_callback) { 236 | glfwSetWindowSizeCallback(glfw->window, glfw->window_size_callback); 237 | } else { 238 | glfwSetWindowSizeCallback(glfw->window, zglfw_default_window_size_callback); 239 | } 240 | 241 | if (glfw->character_callback) { 242 | glfwSetCharCallback(glfw->window, glfw->character_callback); 243 | } else { 244 | glfwSetCharCallback(glfw->window, zglfw_default_character_callback); 245 | } 246 | 247 | if (glfw->mouse_button_callback) { 248 | glfwSetMouseButtonCallback(glfw->window, glfw->mouse_button_callback); 249 | } else { 250 | glfwSetMouseButtonCallback(glfw->window, zglfw_default_mouse_button_callback); 251 | } 252 | 253 | if (glfw->scroll_callback) { 254 | glfwSetScrollCallback(glfw->window, glfw->scroll_callback); 255 | } else { 256 | glfwSetScrollCallback(glfw->window, zglfw_default_scroll_callback); 257 | } 258 | 259 | glfwSetInputMode(glfw->window, GLFW_CURSOR, glfw->window_cursor_mode); 260 | 261 | glfwMakeContextCurrent(glfw->window); 262 | gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); 263 | glfwSwapInterval(1); 264 | 265 | printf("OpenGL Loaded\n"); 266 | printf("Vendor: %s\n", glGetString(GL_VENDOR)); 267 | printf("Renderer: %s\n", glGetString(GL_RENDERER)); 268 | printf("Version: %s\n", glGetString(GL_VERSION)); 269 | 270 | glfw->current_time = glfwGetTime(); 271 | glfw->last_time = glfw->current_time; 272 | glfw->delta_time = 0.0; 273 | glfw->total_time = 0.0; 274 | glfw->total_frames = 0; 275 | 276 | } 277 | 278 | 279 | ZGLFWDEF void zglfw_show_window(ZGLFW *glfw) { 280 | glfwShowWindow(glfw->window); 281 | } 282 | 283 | 284 | ZGLFWDEF int zglfw_is_running(ZGLFW *glfw) { 285 | int should_close = glfw->should_close || glfwWindowShouldClose(glfw->window); 286 | return !should_close; 287 | } 288 | 289 | 290 | ZGLFWDEF void zglfw_begin(ZGLFW *glfw) { 291 | 292 | glfw->last_time = glfw->current_time; 293 | glfw->current_time = glfwGetTime(); 294 | glfw->delta_time = glfw->current_time - glfw->last_time; 295 | glfw->total_time += glfw->delta_time; 296 | glfw->total_frames++; 297 | 298 | double x, y; 299 | glfwGetCursorPos(glfw->window, &x, &y); 300 | 301 | glfw->last_mouse_x = glfw->mouse_x; 302 | glfw->last_mouse_y = glfw->mouse_y; 303 | glfw->mouse_x = cast(float)x; 304 | glfw->mouse_y = cast(float)y; 305 | glfw->mouse_dx = glfw->mouse_x - glfw->last_mouse_x; 306 | glfw->mouse_dy = glfw->mouse_y - glfw->last_mouse_y; 307 | 308 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 309 | 310 | int r = glfw->window_background & 0xFF; 311 | int g = (glfw->window_background >> 8) & 0xFF; 312 | int b = (glfw->window_background >> 16) & 0xFF; 313 | int a = (glfw->window_background >> 24) & 0xFF; 314 | glClearColor(r / 255.99f, g / 255.99f, b / 255.99f, a / 255.99f); 315 | 316 | glfwGetWindowSize(glfw->window, &glfw->window_width, &glfw->window_height); 317 | glfw->window_widthf = glfw->window_width; 318 | glfw->window_heightf = glfw->window_height; 319 | 320 | glfwGetFramebufferSize(glfw->window, &glfw->display_width, &glfw->display_height); 321 | glfw->display_widthf = glfw->display_width; 322 | glfw->display_heightf = glfw->display_height; 323 | 324 | } 325 | 326 | 327 | ZGLFWDEF void zglfw_end(ZGLFW *glfw) { 328 | 329 | for (int i = 32; i < GLFW_KEY_LAST; ++i) { 330 | if (glfw->keys[i]) { 331 | glfw->keys[i]++; 332 | } 333 | } 334 | 335 | for (int i = 0; i < 3; ++i) { 336 | if (glfw->mouse_button[i]) { 337 | glfw->mouse_button[i]++; 338 | } 339 | } 340 | 341 | glfw->mouse_scroll = 0.0f; 342 | glfwPollEvents(); 343 | glfwSwapBuffers(glfw->window); 344 | } 345 | 346 | 347 | ZGLFWDEF void zglfw_quit(ZGLFW *glfw) { 348 | int ms = (int)(1.0e3 * glfw->total_time / glfw->total_frames); 349 | zout("\n%d (ms)\n", ms); 350 | glfwDestroyWindow(glfw->window); 351 | glfwTerminate(); 352 | } 353 | 354 | 355 | #endif // ZEN_GLFW_IMPLEMENTATION 356 | 357 | /* 358 | zlib license: 359 | 360 | Copyright (c) 2017 Timothy Wright https://github.com/ZenToad 361 | 362 | This software is provided 'as-is', without any express or implied 363 | warranty. In no event will the authors be held liable for any damages 364 | arising from the use of this software. 365 | 366 | Permission is granted to anyone to use this software for any purpose, 367 | including commercial applications, and to alter it and redistribute it 368 | freely, subject to the following restrictions: 369 | 370 | 1. The origin of this software must not be misrepresented; you must not 371 | claim that you wrote the original software. If you use this software 372 | in a product, an acknowledgment in the product documentation would be 373 | appreciated but is not required. 374 | 2. Altered source versions must be plainly marked as such, and must not be 375 | misrepresented as being the original software. 376 | 3. This notice may not be removed or altered from any source distribution. 377 | */ 378 | -------------------------------------------------------------------------------- /zen_glfw_imgui.h: -------------------------------------------------------------------------------- 1 | /* zen_imgui.h - v0.42 - GLFW imgui implementation -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_IMGUI_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_IMGUI_IMPLEMENTATION 11 | #include "zen_imgui.h" 12 | 13 | Full license at bottom of file. 14 | 15 | */ 16 | 17 | #ifndef __ZEN_IMGUI_H__ 18 | #define __ZEN_IMGUI_H__ 19 | 20 | #ifdef ZEN_IMGUI_STATIC 21 | #define ZIMGUIDEF static 22 | #else 23 | #define ZIMGUIDEF extern 24 | #endif 25 | 26 | #if defined(ZEN_LIB_DEV) 27 | #include "zen_glfw.h" 28 | #endif 29 | 30 | ZIMGUIDEF void zen_imgui_init(ZGLFW *glfw); 31 | ZIMGUIDEF void zen_imgui_begin(ZGLFW *glfw); 32 | ZIMGUIDEF void zen_imgui_end(); 33 | ZIMGUIDEF void zen_imgui_quit(); 34 | 35 | 36 | #endif //__ZEN_IMGUI_H__ 37 | 38 | 39 | 40 | 41 | #if defined(ZEN_IMGUI_IMPLEMENTATION) || defined(ZEN_LIB_DEV) 42 | 43 | #if defined(ZEN_LIB_DEV) 44 | #include "zen_gl.h" 45 | #include "zen_glfw.h" 46 | #include "imgui.h" 47 | #endif 48 | 49 | typedef struct ZenImguiState_t { 50 | 51 | GLuint vbo; 52 | GLuint ebo; 53 | GLuint vao; 54 | 55 | ZGLShader zen_imgui_shader; 56 | 57 | } ZenImguiState_t; 58 | 59 | static ZenImguiState_t __zen_imgui_state = {0}; 60 | 61 | static ImFont* __zen_imgui_default_font; 62 | //static ImFont* __zen_imgui_custion_font; 63 | 64 | 65 | ZIMGUIDEF void zen_imgui_begin(ZGLFW *glfw) { 66 | 67 | ImGuiIO& io = ImGui::GetIO(); 68 | 69 | // Setup display size (every frame to accommodate for window resizing) 70 | int w = glfw->window_width; 71 | int h = glfw->window_height; 72 | int display_w = glfw->display_width; 73 | int display_h = glfw->display_height; 74 | 75 | io.DisplaySize = ImVec2((float)w, (float)h); 76 | io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); 77 | 78 | io.DeltaTime = glfw->delta_time; 79 | 80 | // Setup inputs 81 | // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) 82 | // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.) 83 | if (glfwGetWindowAttrib(glfw->window, GLFW_FOCUSED)) { 84 | io.MousePos = ImVec2(glfw->mouse_x, glfw->mouse_y); 85 | } else { 86 | io.MousePos = ImVec2(-1,-1); 87 | } 88 | 89 | for (int i = 0; i < 3; i++) { 90 | io.MouseDown[i] = glfw->mouse_button[i] ? true : false; 91 | } 92 | 93 | io.MouseWheel = glfw->mouse_scroll; 94 | 95 | for (int i = 32; i < GLFW_KEY_LAST; ++i) { 96 | io.KeysDown[i] = glfw->keys[i] ? true : false; 97 | } 98 | 99 | 100 | // Hide OS mouse cursor if ImGui is drawing it 101 | glfwSetInputMode(glfw->window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); 102 | 103 | // Start the frame 104 | ImGui::NewFrame(); 105 | 106 | } 107 | 108 | ZIMGUIDEF void zen_imgui_end() { 109 | ImGui::Render(); 110 | } 111 | 112 | static const char* zen_imgui_default_get_clipboard_callback(void* user_data) { 113 | return glfwGetClipboardString((GLFWwindow*)user_data); 114 | } 115 | 116 | static void zen_imgui_default_set_clipboard_callback(void* user_data, const char* text) { 117 | glfwSetClipboardString((GLFWwindow*)user_data, text); 118 | } 119 | 120 | ZIMGUIDEF void zen_imgui_quit() { 121 | ImGui::Shutdown(); 122 | } 123 | 124 | static void zen_imgui_create_font() { 125 | // Build texture atlas 126 | ImGuiIO& io = ImGui::GetIO(); 127 | unsigned char* pixels; 128 | int width, height; 129 | // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely 130 | // to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept 131 | // than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. 132 | __zen_imgui_default_font = io.Fonts->AddFontDefault(); 133 | //__zen_imgui_custion_font = io.Fonts->AddFontFromFileTTF("res/PressStart2P.ttf", 16); 134 | 135 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 136 | 137 | // Upload texture to graphics system 138 | GLint last_texture; 139 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 140 | glActiveTexture(GL_TEXTURE0 + 1); 141 | GLuint font_texture; 142 | glGenTextures(1, &font_texture); 143 | glBindTexture(GL_TEXTURE_2D, font_texture); 144 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 145 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 146 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 147 | 148 | // Store our identifier 149 | io.Fonts->TexID = (void *)(intptr_t)font_texture; 150 | 151 | // Restore state 152 | glBindTexture(GL_TEXTURE_2D, last_texture); 153 | 154 | } 155 | 156 | // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) 157 | // If text or lines are blurry when integrating ImGui in your engine: 158 | // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) 159 | ZIMGUIDEF void zen_imgui_render(ImDrawData* draw_data) { 160 | 161 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) 162 | ImGuiIO& io = ImGui::GetIO(); 163 | int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); 164 | int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); 165 | if (fb_width == 0 || fb_height == 0) 166 | return; 167 | draw_data->ScaleClipRects(io.DisplayFramebufferScale); 168 | 169 | // Backup GL state 170 | GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); 171 | GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 172 | GLint last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, &last_active_texture); 173 | GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 174 | GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer); 175 | GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 176 | GLint last_blend_src; glGetIntegerv(GL_BLEND_SRC, &last_blend_src); 177 | GLint last_blend_dst; glGetIntegerv(GL_BLEND_DST, &last_blend_dst); 178 | GLint last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); 179 | GLint last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); 180 | GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); 181 | GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); 182 | GLboolean last_enable_blend = glIsEnabled(GL_BLEND); 183 | GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); 184 | GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); 185 | GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); 186 | 187 | // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled 188 | glEnable(GL_BLEND); 189 | glBlendEquation(GL_FUNC_ADD); 190 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 191 | glDisable(GL_CULL_FACE); 192 | glDisable(GL_DEPTH_TEST); 193 | glEnable(GL_SCISSOR_TEST); 194 | glActiveTexture(GL_TEXTURE0 + 1); 195 | 196 | // Setup viewport, orthographic projection matrix 197 | glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); 198 | const float ortho_projection[4][4] = 199 | { 200 | { 2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f }, 201 | { 0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f }, 202 | { 0.0f, 0.0f, -1.0f, 0.0f }, 203 | {-1.0f, 1.0f, 0.0f, 1.0f }, 204 | }; 205 | 206 | ZGLShader *shader = &__zen_imgui_state.zen_imgui_shader; 207 | ZenImguiState_t *state = &__zen_imgui_state; 208 | glUseProgram(shader->program); 209 | zgl_set_uniform_int(shader, "Texture", 1); 210 | zgl_set_uniform_mat4(shader, "ProjMtx", &ortho_projection[0][0]); 211 | 212 | glBindVertexArray(state->vao); 213 | 214 | for (int n = 0; n < draw_data->CmdListsCount; n++) 215 | { 216 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 217 | const ImDrawIdx* idx_buffer_offset = 0; 218 | 219 | glBindBuffer(GL_ARRAY_BUFFER, state->vbo); 220 | glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); 221 | 222 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state->ebo); 223 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); 224 | 225 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 226 | { 227 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 228 | if (pcmd->UserCallback) 229 | { 230 | pcmd->UserCallback(cmd_list, pcmd); 231 | } 232 | else 233 | { 234 | glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); 235 | glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); 236 | glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); 237 | } 238 | idx_buffer_offset += pcmd->ElemCount; 239 | } 240 | } 241 | 242 | // Restore modified GL state 243 | glUseProgram(last_program); 244 | glActiveTexture(last_active_texture); 245 | glBindTexture(GL_TEXTURE_2D, last_texture); 246 | glBindVertexArray(last_vertex_array); 247 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 248 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer); 249 | glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); 250 | glBlendFunc(last_blend_src, last_blend_dst); 251 | if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); 252 | if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); 253 | if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); 254 | if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); 255 | glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); 256 | glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); 257 | } 258 | 259 | //bool ImGui_ImplGlfwGL3_CreateDeviceObjects() 260 | static void zen_imgui_setup_shaders() { 261 | 262 | GLint last_texture, last_array_buffer, last_vertex_array; 263 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 264 | glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 265 | glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 266 | 267 | const GLchar *vertex_shader = 268 | "#version 420 core\n" 269 | "uniform mat4 ProjMtx;\n" 270 | "in vec2 Position;\n" 271 | "in vec2 UV;\n" 272 | "in vec4 Color;\n" 273 | "out vec2 Frag_UV;\n" 274 | "out vec4 Frag_Color;\n" 275 | "void main()\n" 276 | "{\n" 277 | " Frag_UV = UV;\n" 278 | " Frag_Color = Color;\n" 279 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" 280 | "}\n"; 281 | 282 | const GLchar* fragment_shader = 283 | "#version 420 core\n" 284 | "uniform sampler2D Texture;\n" 285 | "in vec2 Frag_UV;\n" 286 | "in vec4 Frag_Color;\n" 287 | "out vec4 Out_Color;\n" 288 | "void main()\n" 289 | "{\n" 290 | " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" 291 | "}\n"; 292 | 293 | b32 result = zgl_create_shader(&__zen_imgui_state.zen_imgui_shader, vertex_shader, fragment_shader); 294 | 295 | if (!result) { 296 | exit(EXIT_FAILURE); 297 | } 298 | 299 | ZGLShader *shader = &__zen_imgui_state.zen_imgui_shader; 300 | glUseProgram(shader->program); 301 | 302 | glGenVertexArrays(1, &__zen_imgui_state.vao); 303 | glBindVertexArray(__zen_imgui_state.vao); 304 | __zen_imgui_state.vbo = zgl_make_vbo(NULL, 0, GL_STREAM_DRAW); 305 | __zen_imgui_state.ebo = zgl_make_ebo(NULL, 0, GL_STREAM_DRAW); 306 | zgl_bind_vbo(__zen_imgui_state.vbo); 307 | 308 | int32 loc = glGetAttribLocation(shader->program, "Position"); 309 | assert(loc != -1 && "Position"); 310 | zgl_vert_ptr_aa(loc, 2, ImDrawVert, pos); 311 | loc = glGetAttribLocation(shader->program, "UV"); 312 | assert(loc != -1 && "UV"); 313 | zgl_vert_ptr_aa(loc, 2, ImDrawVert, uv); 314 | loc = glGetAttribLocation(shader->program, "Color"); 315 | assert(loc != -1 && "Color"); 316 | zgl_vert_ptr_aa_u8n(loc, 4, ImDrawVert, col); 317 | 318 | zen_imgui_create_font(); 319 | 320 | // Restore modified GL state 321 | glBindTexture(GL_TEXTURE_2D, last_texture); 322 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 323 | glBindVertexArray(last_vertex_array); 324 | 325 | } 326 | 327 | ZIMGUIDEF void zen_imgui_init(ZGLFW *glfw) { 328 | 329 | // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. 330 | ImGuiIO& io = ImGui::GetIO(); 331 | io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; 332 | io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; 333 | io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; 334 | io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; 335 | io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; 336 | io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; 337 | io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; 338 | io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; 339 | io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; 340 | io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; 341 | io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; 342 | io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; 343 | io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; 344 | io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; 345 | io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; 346 | io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; 347 | io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; 348 | io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; 349 | io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; 350 | 351 | // Alternatively you can set this to NULL and call ImGui::GetDrawData() 352 | // after ImGui::Render() to get the same ImDrawData pointer. 353 | io.RenderDrawListsFn = zen_imgui_render; 354 | io.SetClipboardTextFn = zen_imgui_default_set_clipboard_callback; 355 | io.GetClipboardTextFn = zen_imgui_default_get_clipboard_callback; 356 | io.ClipboardUserData = glfw->window; 357 | #ifdef _WIN32 358 | io.ImeWindowHandle = glfwGetWin32Window(glfw->window); 359 | #endif 360 | 361 | zen_imgui_setup_shaders(); 362 | } 363 | 364 | #endif //ZEN_IMGUI_IMPLEMENTATION 365 | 366 | // Public Domain (www.unlicense.org) 367 | // This is free and unencumbered software released into the public domain. 368 | // Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 369 | // software, either in source code form or as a compiled binary, for any purpose, 370 | // commercial or non-commercial, and by any means. 371 | // In jurisdictions that recognize copyright laws, the author or authors of this 372 | // software dedicate any and all copyright interest in the software to the public 373 | // domain. We make this dedication for the benefit of the public at large and to 374 | // the detriment of our heirs and successors. We intend this dedication to be an 375 | // overt act of relinquishment in perpetuity of all present and future rights to 376 | // this software under copyright law. 377 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 378 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 379 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 380 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 381 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 382 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 383 | -------------------------------------------------------------------------------- /zen_lib.h: -------------------------------------------------------------------------------- 1 | #if defined(ZEN_LIB_IMPLEMENTATION) 2 | 3 | #define ZEN_H_IMPLEMENTATION 4 | #define ZEN_ARR_IMPLEMENTATION 5 | #define ZEN_MATH_IMPLEMENTATION 6 | #define ZEN_HASHMAP_IMPLEMENTATION 7 | 8 | #endif 9 | 10 | 11 | #if !defined(__ZEN_LIB_H__) 12 | #define __ZEN_LIB_H__ 13 | 14 | 15 | #if !defined(ZEN_LIB_NO_INCLUDES) 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | 24 | #include "zen_lib/zen.h" 25 | #include "zen_lib/zen_arr.h" 26 | #include "zen_lib/zen_math.h" 27 | #include "zen_lib/zen_hashmap.h" 28 | 29 | 30 | #endif //__ZEN_LIB_H__ 31 | -------------------------------------------------------------------------------- /zen_lib/zen.h: -------------------------------------------------------------------------------- 1 | /* zen.h - v0.42 - public domain utility -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_H_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_H_IMPLEMENTATION 11 | #include "zen_lib/zen.h" 12 | 13 | Full license at bottom of file. 14 | 15 | */ 16 | 17 | #ifndef ZEN_H_INCLUDE 18 | #define ZEN_H_INCLUDE 19 | 20 | //@TODO: need some kind of cross platform file i/o 21 | //maybe look at SDL? 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #if defined(ZEN_LIB_DEV) 27 | #include 28 | #endif 29 | 30 | 31 | #if !defined(int32_t) 32 | #include 33 | typedef int8_t int8; 34 | typedef int16_t int16; 35 | typedef int32_t int32; 36 | typedef int64_t int64; 37 | typedef uint8_t uint8; 38 | typedef uint16_t uint16; 39 | typedef uint32_t uint32; 40 | typedef uint64_t uint64; 41 | typedef int32 b32; 42 | #endif 43 | 44 | #if !defined(size_t) || !defined(ptrdiff_t) 45 | #include 46 | #endif 47 | 48 | typedef size_t usize; 49 | typedef ptrdiff_t isize; 50 | typedef intptr_t psize; 51 | 52 | 53 | #define cast(Type) (Type) 54 | #define zen_sizeof(x) cast(isize)(sizeof(x)) 55 | 56 | 57 | #if !defined(ZEN_MALLOC) 58 | #define ZEN_MALLOC(T) (T *)malloc(zen_sizeof(T)) 59 | #endif 60 | 61 | #if !defined(ZEN_MALLOC_ARRAY) 62 | #define ZEN_MALLOC_ARRAY(T,count) (T *)malloc(zen_sizeof(T) * (count)) 63 | #endif 64 | 65 | #if !defined(ZEN_CALLOC) 66 | #define ZEN_CALLOC(T,count) (T*)calloc((count), zen_sizeof(T)) 67 | #endif 68 | 69 | #define zdebug(M, ...) fprintf(stdout, "DEBUG %s:%d: " M "\n",\ 70 | __FILE__, __LINE__, ##__VA_ARGS__) 71 | 72 | #define zen_min(a,b) (a) <= (b) ? (a) : (b) 73 | #define zen_max(a,b) (a) >= (b) ? (a) : (b) 74 | #define zen_at_least(a,b) zen_max(a,b) 75 | #define zen_at_most(a,b) zen_min(a,b) 76 | #define zen_clamp(a,min,max) zen_at_least(min,zen_at_most(max,a)) 77 | #define zen_clamp_01(a) zen_at_least(0.0,zen_at_most(1.0,a)) 78 | 79 | 80 | #define zdebug(M, ...) fprintf(stdout, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) 81 | #define zout(M, ...) fprintf(stdout, M "\n", ##__VA_ARGS__) 82 | 83 | #define zfout(v) fprintf(stdout, #v ": %.4f\n", v) 84 | #define ziout(v) fprintf(stdout, #v ": %d\n", v) 85 | 86 | 87 | #define zen_offset(x) ((const void*) (x)) 88 | #define zen_offset_of(Type, element) ((isize)&(((Type *)0)->element)) 89 | 90 | 91 | #ifndef zen_inline 92 | #if defined(_MSC_VER) 93 | #if _MSC_VER < 1300 94 | #define zen_inline 95 | #else 96 | #define zen_inline __forceinline 97 | #endif 98 | #else 99 | #define zen_inline __attribute__ ((__always_inline__)) inline 100 | #endif 101 | #endif 102 | 103 | 104 | 105 | //////////////////////////////////////////////////////////////// 106 | // 107 | // Debug Ginger Bill's gb.h 108 | // 109 | // 110 | 111 | 112 | #ifndef GB_DEBUG_TRAP 113 | #if defined(_MSC_VER) 114 | #if _MSC_VER < 1300 115 | #define GB_DEBUG_TRAP() __asm int 3 /* Trap to debugger! */ 116 | #else 117 | #define GB_DEBUG_TRAP() __debugbreak() 118 | #endif 119 | #else 120 | #define GB_DEBUG_TRAP() raise(SIGTRAP) 121 | #endif 122 | #endif 123 | 124 | #ifndef GB_ASSERT_MSG 125 | #define GB_ASSERT_MSG(cond, msg, ...) do { \ 126 | if (!(cond)) { \ 127 | gb_assert_handler(#cond, __FILE__, __LINE__, msg, ##__VA_ARGS__); \ 128 | GB_DEBUG_TRAP(); \ 129 | } \ 130 | } while (0) 131 | #endif 132 | 133 | #ifndef GB_ASSERT 134 | #define GB_ASSERT(cond) GB_ASSERT_MSG(cond, NULL) 135 | #endif 136 | 137 | #ifndef GB_ASSERT_NOT_NULL 138 | #define GB_ASSERT_NOT_NULL(ptr) GB_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL") 139 | #endif 140 | 141 | // NOTE(bill): Things that shouldn't happen with a message! 142 | #ifndef GB_PANIC 143 | #define GB_PANIC(msg, ...) GB_ASSERT_MSG(0, msg, ##__VA_ARGS__) 144 | #endif 145 | 146 | #ifdef ZEN_H_STATIC 147 | #define ZENHDEF static 148 | #else 149 | #define ZENHDEF extern 150 | #endif 151 | 152 | 153 | ZENHDEF void gb_assert_handler(char const *condition, char const *file, int line, char const *msg, ...); 154 | 155 | 156 | ////////////////////////////////////////////////////////////////////////////// 157 | // 158 | // Random Numbers via Meresenne Twister or LCG 159 | // 160 | // stb.h 161 | 162 | ZENHDEF unsigned long stb_srandLCG(unsigned long seed); 163 | ZENHDEF unsigned long stb_randLCG(void); 164 | ZENHDEF double stb_frandLCG(void); 165 | 166 | ZENHDEF void stb_srand(unsigned long seed); 167 | ZENHDEF unsigned long stb_rand(void); 168 | ZENHDEF double stb_frand(void); 169 | ZENHDEF void stb_shuffle(void *p, size_t n, size_t sz, 170 | unsigned long seed); 171 | ZENHDEF void stb_reverse(void *p, size_t n, size_t sz); 172 | 173 | ZENHDEF unsigned long stb_randLCG_explicit(unsigned long seed); 174 | 175 | #define stb_rand_define(x,y) \ 176 | \ 177 | unsigned long x(void) \ 178 | { \ 179 | static unsigned long stb__rand = y; \ 180 | stb__rand = stb__rand * 2147001325 + 715136305; /* BCPL */ \ 181 | return 0x31415926 ^ ((stb__rand >> 16) + (stb__rand << 16)); \ 182 | } 183 | 184 | 185 | #ifdef __cplusplus 186 | } 187 | #endif 188 | 189 | 190 | #endif // ZEN_H_INCLUDE 191 | 192 | 193 | //------------------------------------------ 194 | // 195 | // Implementation 196 | // 197 | //------------------------------------------ 198 | #ifdef ZEN_H_IMPLEMENTATION 199 | 200 | 201 | // The static array needs a 202 | // max, count, and cmp. Do we really 203 | // need the cmp? Could just pass in a func ptr... cmp(void *a, void *b); 204 | // Can we do the same tricks... 205 | // 206 | 207 | #if 0 208 | 209 | so how can this work... 210 | 211 | #define MakeStatic(prefix, type, size, data) 212 | typedef struct ##prefix_StaticArray_##type { 213 | int n = 0; 214 | int m = size; 215 | ##data a[size]; 216 | } __##prefix_StaticArray_##type; 217 | 218 | #define static_array(prefix,type) __##prefix_StaticArray_##type.a; 219 | #define static_add(a,v) 220 | int n = ((int *)(a) - 2)[0]; 221 | int m = ((int *)(a) - 2)[1]; 222 | GB_ASSERT(m > n); 223 | a[((int *)(a) - 2)[0]++] = v; 224 | 225 | 226 | MakeStatic(arr, int, 64, int); 227 | int *static = static_array(arr,int); 228 | 229 | static_add(static, 32); 230 | 231 | can this work? Would be cool; 232 | 233 | #endif 234 | 235 | #if 0 236 | template 237 | class HashmapNode_t { 238 | K key; 239 | V value; 240 | uint32_t hash; 241 | 242 | public: 243 | HashmapNode_t(K key, V value) : key(key), value(value) { } 244 | virtual ~HashmapNode_t() { } 245 | 246 | }; 247 | 248 | 249 | template 250 | class Hashmap_t { 251 | 252 | int num_buckets = 0; 253 | 254 | HashmapNode_t **buckets; 255 | int (*compare)(K a, K b); 256 | 257 | uint32_t hash(K key); 258 | int getNode(HashmapNode_t *bucket, uint32_t hash); 259 | 260 | public: 261 | 262 | Hashmap_t(int buckets, int (*compare)(K, V)); 263 | virtual ~Hashmap_t(); 264 | 265 | V get(K key); 266 | void set(K key, V value); 267 | V remove(K key); 268 | void traverse(int (*traverse)(HashmapNode_t *)); 269 | 270 | }; 271 | 272 | 273 | template 274 | Hashmap_t::Hashmap_t(int num_buckets, int (*compare)(K,V)) { 275 | this->num_buckets = num_buckets; 276 | this->compare = compare; 277 | for (int i = 0; i < num_buckets; ++i) 278 | stb_arr_push(this->buckets, NULL); 279 | } 280 | 281 | template 282 | Hashmap_t::~Hashmap_t() { 283 | for (int i = 0; i < stb_arr_len(buckets); ++i) { 284 | auto *bucket = buckets[i]; 285 | for (int j = 0; j < stb_arr_len(bucket); ++j) { 286 | auto *node = bucket[j]; 287 | GB_ASSERT_NOT_NULL(node); 288 | free(node); 289 | } 290 | stb_arr_free(bucket); 291 | } 292 | stb_arr_free(buckets); 293 | } 294 | 295 | template 296 | int Hashmap_t::getNode(HashmapNode_t *bucket, uint32_t hash) { 297 | for (int i = 0; i < stb_arr_len(bucket); i++) { 298 | auto *node = bucket[i]; 299 | if (node && node->hash == hash) { 300 | return i; 301 | } 302 | } 303 | return -1; 304 | } 305 | 306 | template 307 | V Hashmap_t::get(K key) { 308 | 309 | uint32_t hash = hash(key); 310 | int bucket_index = hash % num_buckets; 311 | GB_ASSERT_MSG(bucket_index >= 0, "Invalid bucket_index found: %d", bucket_index); 312 | 313 | auto *bucket = buckets[bucket_index]; 314 | if (bucket == NULL) return NULL; // not found 315 | 316 | int i = getNode(hash, bucket); 317 | if (i == -1) return NULL; 318 | 319 | auto *node = bucket[i]; 320 | GB_ASSERT_MSG(node != NULL, "Failed to get node from bucket when it should exist."); 321 | 322 | return node->value; 323 | 324 | } 325 | 326 | template 327 | void Hashmap_t::set(K key, V value) { 328 | uint32_t hash = hash(key); 329 | int bucket_index = hash % num_buckets; 330 | GB_ASSERT_MSG(bucket_index >= 0, "Invalid bucket_index found: %d", bucket_index); 331 | 332 | auto *bucket = buckets[bucket_index]; 333 | for (int i = 0; i < stb_arr_len(bucket); ++i) { 334 | auto *node = bucket[i]; 335 | if (node && node->hash == hash) { 336 | node->value = value; 337 | return; 338 | } 339 | } 340 | 341 | HashmapNode_t *node = new HashmapNode_t(key, value); 342 | GB_ASSERT_NOT_NULL(node); 343 | 344 | stb_arr_push(buckets[bucket_index], node); 345 | } 346 | 347 | template 348 | V Hashmap_t::remove(K key) { 349 | 350 | uint32_t hash = hash(key); 351 | int bucket_index = hash % num_buckets; 352 | GB_ASSERT_MSG(bucket_index >= 0, "Invalid bucket_index found: %d", bucket_index); 353 | 354 | auto *bucket = buckets[bucket_index]; 355 | if (bucket == NULL) return NULL; // not found 356 | 357 | int i = getNode(hash, bucket); 358 | if (i == -1) return NULL; 359 | 360 | auto *node = bucket[i]; 361 | GB_ASSERT_NOT_NULL(node); 362 | V value = node->value; 363 | 364 | if (i != stb_arr_lastn(bucket)) { 365 | stb_arr_fastdelete(bucket, i); 366 | } 367 | delete node; 368 | 369 | return value; 370 | 371 | } 372 | 373 | template 374 | void Hashmap_t::traverse(int (*traverse)(HashmapNode_t *)) { 375 | 376 | for (int i = 0; i < stb_arr_len(buckets); i++) { 377 | auto *bucket = buckets[i]; 378 | if (bucket) { 379 | for (int j = 0; j < stb_arr_len(bucket); j++) { 380 | auto *node = bucket[j]; 381 | int rc = traverse_cb(node); 382 | if (rc != 0) 383 | return; 384 | } 385 | } 386 | } 387 | 388 | } 389 | 390 | #endif 391 | 392 | #if 0 393 | // Static array ideas 394 | // TODO really easy static array list 395 | // needs an array, size, count(n), and cmp() func 396 | typedef struct StaticArray { 397 | enum{ MAX=512 }; 398 | int a[MAX]; 399 | int n = 0; 400 | bool (*cmp)(int a, int b); 401 | } StaticArray; 402 | 403 | 404 | void add(StaticArray *arr, int v) { 405 | GB_ASSERT(arr->MAX > arr->n); 406 | arr->a[arr->n++] = v; 407 | } 408 | 409 | void remove_index(StaticArray *arr, int i) { 410 | if (i < 0 || i >= arr->n) 411 | return; // not in list 412 | if (i < arr->n - 1) // wasn't last 413 | arr->a[i] = arr->a[arr->n-1]; 414 | arr->n--; 415 | } 416 | 417 | int find_index(StaticArray *arr, int v) { 418 | for (int i = 0; i < arr->n; ++i) { 419 | if(arr->cmp(arr->a[i],v)) 420 | return i; 421 | } 422 | return -1; 423 | } 424 | 425 | void remove(StaticArray *arr, int v) { 426 | remove_index(arr, find_index(arr, v)); 427 | } 428 | 429 | #endif 430 | 431 | 432 | 433 | #if 0 434 | // Simple hashmap ideas 435 | #define DEFAULT_NUMBER_OF_BUCKETS 100 436 | 437 | typedef int (*Hashmap_compare) (const char *a, const char *b); 438 | typedef uint32_t(*Hashmap_hash) (const char *key); 439 | typedef struct HashmapNode { 440 | 441 | const char *key; 442 | gbString data; 443 | uint32_t hash; 444 | 445 | } HashmapNode; 446 | 447 | typedef HashmapNode * HashmapBucket; 448 | 449 | typedef struct Hashmap { 450 | 451 | HashmapBucket **buckets; 452 | Hashmap_compare compare; 453 | Hashmap_hash hash; 454 | 455 | } Hashmap; 456 | 457 | 458 | typedef int (*Hashmap_traverse_cb) (HashmapNode * node); 459 | 460 | /** 461 | * Simple Bob Jenkins's hash algorithm taken from the 462 | * wikipedia description. 463 | */ 464 | uint32_t default_hash(const char *a) { 465 | size_t len = strlen(a); 466 | uint32_t hash = 0; 467 | uint32_t i = 0; 468 | 469 | for (hash = i = 0; i < len; ++i) { 470 | hash += a[i]; 471 | hash += (hash << 10); 472 | hash ^= (hash >> 6); 473 | } 474 | 475 | hash += (hash << 3); 476 | hash ^= (hash >> 11); 477 | hash += (hash << 15); 478 | 479 | return hash; 480 | } 481 | 482 | 483 | int default_compare(const char *a, const char *b) { 484 | return strcmp(a, b); 485 | } 486 | 487 | 488 | Hashmap *Hashmap_create(Hashmap_compare compare, Hashmap_hash hash) { 489 | 490 | Hashmap *map = ZEN_CALLOC(Hashmap, 1); 491 | GB_ASSERT_NOT_NULL(map); 492 | 493 | map->compare = compare == NULL ? default_compare : compare; 494 | map->hash = hash == NULL ? default_hash : hash; 495 | 496 | for (int i = 0; i < DEFAULT_NUMBER_OF_BUCKETS; ++i) 497 | stb_arr_push(map->buckets, NULL); 498 | 499 | return map; 500 | 501 | } 502 | 503 | 504 | void Hashmap_destroy(Hashmap * map) { 505 | 506 | if (map) { 507 | for (int i = 0; i < stb_arr_len(map->buckets); ++i) { 508 | HashmapBucket *bucket = map->buckets[i]; 509 | for (int j = 0; j < stb_arr_len(bucket); ++j) { 510 | HashmapNode *node = bucket[j]; 511 | GB_ASSERT_NOT_NULL(node); 512 | free(node); 513 | } 514 | stb_arr_free(bucket); 515 | } 516 | stb_arr_free(map->buckets); 517 | } 518 | free(map); 519 | 520 | } 521 | 522 | 523 | static inline int Hashmap_get_node(Hashmap *map, uint32_t hash, HashmapBucket *bucket, const char *key) { 524 | 525 | for (int i = 0; i < stb_arr_len(bucket); i++) { 526 | HashmapNode *node = bucket[i]; 527 | if (node && node->hash == hash) { 528 | return i; 529 | } 530 | } 531 | 532 | return -1; 533 | } 534 | 535 | 536 | gbString Hashmap_get(Hashmap *map, const char *key) { 537 | 538 | uint32_t hash = map->hash(key); 539 | int bucket_index = hash % DEFAULT_NUMBER_OF_BUCKETS; 540 | GB_ASSERT_MSG(bucket_index >= 0, "Invalid bucket_index found: %d", bucket_index); 541 | 542 | HashmapBucket *bucket = map->buckets[bucket_index]; 543 | if (bucket == NULL) return NULL; // not found 544 | 545 | int i = Hashmap_get_node(map, hash, bucket, key); 546 | if (i == -1) return NULL; 547 | 548 | HashmapNode *node = bucket[i]; 549 | GB_ASSERT_MSG(node != NULL, "Failed to get node from bucket when it should exist."); 550 | 551 | return node->data; 552 | 553 | } 554 | 555 | 556 | int Hashmap_traverse(Hashmap * map, Hashmap_traverse_cb traverse_cb) { 557 | 558 | for (int i = 0; i < stb_arr_len(map->buckets); i++) { 559 | HashmapBucket *bucket = map->buckets[i]; 560 | if (bucket) { 561 | for (int j = 0; j < stb_arr_len(bucket); j++) { 562 | HashmapNode *node = bucket[j]; 563 | int rc = traverse_cb(node); 564 | if (rc != 0) 565 | return rc; 566 | } 567 | } 568 | } 569 | 570 | return 0; 571 | } 572 | 573 | 574 | gbString Hashmap_delete(Hashmap *map, const char *key) { 575 | 576 | uint32_t hash = map->hash(key); 577 | int bucket_index = hash % DEFAULT_NUMBER_OF_BUCKETS; 578 | GB_ASSERT_MSG(bucket_index >= 0, "Invalid bucket_index found: %d", bucket_index); 579 | 580 | HashmapBucket *bucket = map->buckets[bucket_index]; 581 | if (bucket == NULL) return NULL; // not found 582 | 583 | int i = Hashmap_get_node(map, hash, bucket, key); 584 | if (i == -1) return NULL; 585 | 586 | HashmapNode *node = bucket[i]; 587 | GB_ASSERT_NOT_NULL(node); 588 | gbString data = node->data; 589 | 590 | if (i != stb_arr_lastn(bucket)) { 591 | stb_arr_fastdelete(bucket, i); 592 | } 593 | free(node); 594 | 595 | return data; 596 | } 597 | 598 | int count_new = 0; 599 | 600 | void Hashmap_set(Hashmap *map, const char *key, gbString data) { 601 | 602 | uint32_t hash = map->hash(key); 603 | int bucket_index = hash % DEFAULT_NUMBER_OF_BUCKETS; 604 | GB_ASSERT_MSG(bucket_index >= 0, "Invalid bucket_index found: %d", bucket_index); 605 | 606 | HashmapBucket *bucket = map->buckets[bucket_index]; 607 | for (int i = 0; i < stb_arr_len(bucket); ++i) { 608 | HashmapNode *node = bucket[i]; 609 | if (node && node->hash == hash) { 610 | node->data = data; 611 | return; 612 | } 613 | } 614 | 615 | HashmapNode *node = ZEN_CALLOC(HashmapNode, 1); 616 | GB_ASSERT_NOT_NULL(node); 617 | 618 | node->key = key; 619 | node->data = data; 620 | node->hash = hash; 621 | 622 | stb_arr_push(map->buckets[bucket_index], node); 623 | count_new++; 624 | 625 | } 626 | 627 | #endif 628 | 629 | 630 | 631 | //////////////////////////////////////////////////////////////// 632 | // 633 | // Debug Ginger Bill's gb.h 634 | // 635 | // 636 | 637 | 638 | void gb_assert_handler(char const *condition, char const *file, int line, char const *msg, ...) { 639 | fprintf(stderr, "%s:%d: Assert Failure: ", file, line); 640 | if (condition) 641 | fprintf(stderr, "`%s` ", condition); 642 | if (msg) { 643 | va_list va; 644 | va_start(va, msg); 645 | vfprintf(stderr, msg, va); 646 | va_end(va); 647 | } 648 | fprintf(stderr, "\n"); 649 | } 650 | 651 | 652 | ////////////////////////////////////////////////////////////////////////////// 653 | // 654 | // Random Numbers via Meresenne Twister or LCG 655 | // 656 | // stb.h 657 | // 658 | 659 | typedef struct { char d[4]; } stb__4; 660 | typedef struct { char d[8]; } stb__8; 661 | 662 | 663 | // optimize the small cases, though you shouldn't be calling this for those! 664 | static void stb_swap(void *p, void *q, size_t sz) 665 | { 666 | char buffer[256]; 667 | if (p == q) return; 668 | if (sz == 4) { 669 | stb__4 temp = * ( stb__4 *) p; 670 | * (stb__4 *) p = * ( stb__4 *) q; 671 | * (stb__4 *) q = temp; 672 | return; 673 | } else if (sz == 8) { 674 | stb__8 temp = * ( stb__8 *) p; 675 | * (stb__8 *) p = * ( stb__8 *) q; 676 | * (stb__8 *) q = temp; 677 | return; 678 | } 679 | 680 | while (sz > sizeof(buffer)) { 681 | stb_swap(p, q, sizeof(buffer)); 682 | p = (char *) p + sizeof(buffer); 683 | q = (char *) q + sizeof(buffer); 684 | sz -= sizeof(buffer); 685 | } 686 | 687 | memcpy(buffer, p , sz); 688 | memcpy(p , q , sz); 689 | memcpy(q , buffer, sz); 690 | } 691 | 692 | unsigned long stb_randLCG_explicit(unsigned long seed) 693 | { 694 | return seed * 2147001325 + 715136305; 695 | } 696 | 697 | static unsigned long stb__rand_seed=0; 698 | 699 | unsigned long stb_srandLCG(unsigned long seed) 700 | { 701 | unsigned long previous = stb__rand_seed; 702 | stb__rand_seed = seed; 703 | return previous; 704 | } 705 | 706 | unsigned long stb_randLCG(void) 707 | { 708 | stb__rand_seed = stb__rand_seed * 2147001325 + 715136305; // BCPL generator 709 | // shuffle non-random bits to the middle, and xor to decorrelate with seed 710 | return 0x31415926 ^ ((stb__rand_seed >> 16) + (stb__rand_seed << 16)); 711 | } 712 | 713 | double stb_frandLCG(void) 714 | { 715 | return stb_randLCG() / ((double) (1 << 16) * (1 << 16)); 716 | } 717 | 718 | void stb_shuffle(void *p, size_t n, size_t sz, unsigned long seed) 719 | { 720 | char *a; 721 | unsigned long old_seed = 0; 722 | size_t i; 723 | if (seed) 724 | old_seed = stb_srandLCG(seed); 725 | a = (char *) p + (n-1) * sz; 726 | 727 | for (i=n; i > 1; --i) { 728 | int j = stb_randLCG() % i; 729 | stb_swap(a, (char *) p + j * sz, sz); 730 | a -= sz; 731 | } 732 | if (seed) 733 | stb_srandLCG(old_seed); 734 | } 735 | 736 | void stb_reverse(void *p, size_t n, size_t sz) 737 | { 738 | size_t i,j = n-1; 739 | for (i=0; i < j; ++i,--j) { 740 | stb_swap((char *) p + i * sz, (char *) p + j * sz, sz); 741 | } 742 | } 743 | 744 | // public domain Mersenne Twister by Michael Brundage 745 | #define STB__MT_LEN 624 746 | 747 | int stb__mt_index = STB__MT_LEN*sizeof(unsigned long)+1; 748 | unsigned long stb__mt_buffer[STB__MT_LEN]; 749 | 750 | void stb_srand(unsigned long seed) 751 | { 752 | int i; 753 | unsigned long old = stb_srandLCG(seed); 754 | for (i = 0; i < STB__MT_LEN; i++) 755 | stb__mt_buffer[i] = stb_randLCG(); 756 | stb_srandLCG(old); 757 | stb__mt_index = STB__MT_LEN*sizeof(unsigned long); 758 | } 759 | 760 | #define STB__MT_IA 397 761 | #define STB__MT_IB (STB__MT_LEN - STB__MT_IA) 762 | #define STB__UPPER_MASK 0x80000000 763 | #define STB__LOWER_MASK 0x7FFFFFFF 764 | #define STB__MATRIX_A 0x9908B0DF 765 | #define STB__TWIST(b,i,j) ((b)[i] & STB__UPPER_MASK) | ((b)[j] & STB__LOWER_MASK) 766 | #define STB__MAGIC(s) (((s)&1)*STB__MATRIX_A) 767 | 768 | unsigned long stb_rand() 769 | { 770 | unsigned long * b = stb__mt_buffer; 771 | int idx = stb__mt_index; 772 | unsigned long s,r; 773 | int i; 774 | 775 | if (idx >= STB__MT_LEN*sizeof(unsigned long)) { 776 | if (idx > STB__MT_LEN*sizeof(unsigned long)) 777 | stb_srand(0); 778 | idx = 0; 779 | i = 0; 780 | for (; i < STB__MT_IB; i++) { 781 | s = STB__TWIST(b, i, i+1); 782 | b[i] = b[i + STB__MT_IA] ^ (s >> 1) ^ STB__MAGIC(s); 783 | } 784 | for (; i < STB__MT_LEN-1; i++) { 785 | s = STB__TWIST(b, i, i+1); 786 | b[i] = b[i - STB__MT_IB] ^ (s >> 1) ^ STB__MAGIC(s); 787 | } 788 | 789 | s = STB__TWIST(b, STB__MT_LEN-1, 0); 790 | b[STB__MT_LEN-1] = b[STB__MT_IA-1] ^ (s >> 1) ^ STB__MAGIC(s); 791 | } 792 | stb__mt_index = idx + sizeof(unsigned long); 793 | 794 | r = *(unsigned long *)((unsigned char *)b + idx); 795 | 796 | r ^= (r >> 11); 797 | r ^= (r << 7) & 0x9D2C5680; 798 | r ^= (r << 15) & 0xEFC60000; 799 | r ^= (r >> 18); 800 | 801 | return r; 802 | } 803 | 804 | 805 | int stb_rand_range(int min, int max) { 806 | int a = zen_min(min, max); 807 | int b = zen_max(min, max); 808 | int diff = b - a + 1; 809 | return a + stb_rand() % diff; 810 | } 811 | 812 | 813 | double stb_frand(void) { 814 | return stb_rand() / ((double) (1 << 16) * (1 << 16)); 815 | } 816 | 817 | #endif // ZEN_IMPLEMENTATION 818 | 819 | 820 | // Public Domain (www.unlicense.org) 821 | // This is free and unencumbered software released into the public domain. 822 | // Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 823 | // software, either in source code form or as a compiled binary, for any purpose, 824 | // commercial or non-commercial, and by any means. 825 | // In jurisdictions that recognize copyright laws, the author or authors of this 826 | // software dedicate any and all copyright interest in the software to the public 827 | // domain. We make this dedication for the benefit of the public at large and to 828 | // the detriment of our heirs and successors. We intend this dedication to be an 829 | // overt act of relinquishment in perpetuity of all present and future rights to 830 | // this software under copyright law. 831 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 832 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 833 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 834 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 835 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 836 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 837 | // 838 | -------------------------------------------------------------------------------- /zen_lib/zen_arr.h: -------------------------------------------------------------------------------- 1 | /* zen_arr.h - v0.42 - Arrays -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_ARR_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_ARR_IMPLEMENTATION 11 | #include "zen_arr.h" 12 | 13 | This is stb_arr and stretchy_buffer 14 | Full license at bottom of file. 15 | 16 | */ 17 | 18 | 19 | #if !defined(__ZEN_ARR_H__) 20 | #define __ZEN_ARR_H__ 21 | 22 | 23 | #if defined(__cplusplus) 24 | extern "C" { 25 | #endif 26 | 27 | 28 | #if defined(ZEN_ARR_STATIC) 29 | #define ZARRDEF static 30 | #else 31 | #define ZARRDEF extern 32 | #endif 33 | 34 | //////////////////////////////////////////////////////////////////////////////////// 35 | // 36 | // stretchy_buffer.h stb libraries 37 | // 38 | // 39 | 40 | 41 | #ifndef NO_STRETCHY_BUFFER_SHORT_NAMES 42 | #define sb_free stb_sb_free 43 | #define sb_push stb_sb_push 44 | #define sb_count stb_sb_count 45 | #define sb_add stb_sb_add 46 | #define sb_last stb_sb_last 47 | #define sb_pop stb_sb_pop 48 | #endif 49 | 50 | #define stb_sb_free(a) ((a) ? free(stb__sbraw(a)),0 : 0) 51 | #define stb_sb_push(a,v) (stb__sbmaybegrow(a,1), (a)[stb__sbn(a)++] = (v)) 52 | #define stb_sb_count(a) ((a) ? stb__sbn(a) : 0) 53 | #define stb_sb_add(a,n) (stb__sbmaybegrow(a,n), stb__sbn(a)+=(n), &(a)[stb__sbn(a)-(n)]) 54 | #define stb_sb_last(a) ((a)[stb__sbn(a)-1]) 55 | #define stb_sb_pop(a) ((a)[--stb__sbn(a)]) 56 | 57 | #define stb__sbraw(a) ((int *) (a) - 2) 58 | #define stb__sbm(a) stb__sbraw(a)[0] 59 | #define stb__sbn(a) stb__sbraw(a)[1] 60 | 61 | #define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a)) 62 | #define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0) 63 | #define stb__sbgrow(a,n) (*((void **)&(a)) = stb__sbgrowf((a), (n), sizeof(*(a)))) 64 | 65 | 66 | ////////////////////////////////////////////////////////////////////////////// 67 | // 68 | // stb_arr 69 | // 70 | // An stb_arr is directly useable as a pointer (use the actual type in your 71 | // definition), but when it resizes, it returns a new pointer and you can't 72 | // use the old one, so you have to be careful to copy-in-out as necessary. 73 | // 74 | // Use a NULL pointer as a 0-length array. 75 | // 76 | // float *my_array = NULL, *temp; 77 | // 78 | // // add elements on the end one at a time 79 | // stb_arr_push(my_array, 0.0f); 80 | // stb_arr_push(my_array, 1.0f); 81 | // stb_arr_push(my_array, 2.0f); 82 | // 83 | // assert(my_array[1] == 2.0f); 84 | // 85 | // // add an uninitialized element at the end, then assign it 86 | // *stb_arr_add(my_array) = 3.0f; 87 | // 88 | // // add three uninitialized elements at the end 89 | // temp = stb_arr_addn(my_array,3); 90 | // temp[0] = 4.0f; 91 | // temp[1] = 5.0f; 92 | // temp[2] = 6.0f; 93 | // 94 | // assert(my_array[5] == 5.0f); 95 | // 96 | // // remove the last one 97 | // stb_arr_pop(my_array); 98 | // 99 | // assert(stb_arr_len(my_array) == 6); 100 | 101 | 102 | // simple functions written on top of other functions 103 | // 104 | 105 | #define stb_arr_empty(a) ( stb_arr_len(a) == 0 ) 106 | #define stb_arr_add(a) ( stb_arr_addn((a),1) ) 107 | #define stb_arr_push(a,v) ( *stb_arr_add(a)=(v) ) 108 | 109 | 110 | typedef struct { 111 | int len, limit; 112 | unsigned int signature; 113 | } stb__arr; 114 | 115 | 116 | #define stb_arr_signature 0x51bada7b // ends with 0123 in decimal 117 | 118 | 119 | // access the header block stored before the data 120 | #define stb_arrhead(a) /*lint --e(826)*/ (((stb__arr *) (psize)(a)) - 1) 121 | #define stb_arrhead2(a) /*lint --e(826)*/ (((stb__arr *) (psize)(a)) - 1) 122 | 123 | 124 | #ifdef STB_DEBUG 125 | #define stb_arr_check(a) assert(!a || stb_arrhead(a)->signature == stb_arr_signature) 126 | #define stb_arr_check2(a) assert(!a || stb_arrhead2(a)->signature == stb_arr_signature) 127 | #else 128 | #define stb_arr_check(a) ((void) 0) 129 | #define stb_arr_check2(a) ((void) 0) 130 | #endif 131 | 132 | 133 | // ARRAY LENGTH 134 | 135 | // get the array length; special case if pointer is NULL 136 | #define stb_arr_len(a) (a ? stb_arrhead(a)->len : 0) 137 | #define stb_arr_len2(a) ((stb__arr *) (a) ? stb_arrhead2(a)->len : 0) 138 | #define stb_arr_lastn(a) (stb_arr_len(a)-1) 139 | 140 | // check whether a given index is valid -- tests 0 <= i < stb_arr_len(a) 141 | #define stb_arr_valid(a,i) (a ? (int) (i) < stb_arrhead(a)->len : 0) 142 | 143 | // change the array length so is is exactly N entries long, creating 144 | // uninitialized entries as needed 145 | #define stb_arr_setlen(a,n) \ 146 | (stb__arr_setlen((void **) &(a), sizeof(a[0]), (n))) 147 | 148 | // change the array length so that N is a valid index (that is, so 149 | // it is at least N entries long), creating uninitialized entries as needed 150 | #define stb_arr_makevalid(a,n) \ 151 | (stb_arr_len(a) < (n)+1 ? stb_arr_setlen(a,(n)+1),(a) : (a)) 152 | 153 | // remove the last element of the array, returning it 154 | #define stb_arr_pop(a) ((stb_arr_check(a), (a))[--stb_arrhead(a)->len]) 155 | 156 | // access the last element in the array 157 | #define stb_arr_last(a) ((stb_arr_check(a), (a))[stb_arr_len(a)-1]) 158 | 159 | // is iterator at end of list? 160 | #define stb_arr_end(a,i) ((i) >= &(a)[stb_arr_len(a)]) 161 | 162 | // (internal) change the allocated length of the array 163 | #define stb_arr__grow(a,n) (stb_arr_check(a), stb_arrhead(a)->len += (n)) 164 | 165 | // add N new unitialized elements to the end of the array 166 | #define stb_arr__addn(a,n) /*lint --e(826)*/ \ 167 | ((stb_arr_len(a)+(n) > stb_arrcurmax(a)) \ 168 | ? (stb__arr_addlen((void **) &(a),sizeof(*a),(n)),0) \ 169 | : ((stb_arr__grow(a,n), 0))) 170 | 171 | // add N new unitialized elements to the end of the array, and return 172 | // a pointer to the first new one 173 | #define stb_arr_addn(a,n) (stb_arr__addn((a),n),(a)+stb_arr_len(a)-(n)) 174 | 175 | // add N new uninitialized elements starting at index 'i' 176 | #define stb_arr_insertn(a,i,n) (stb__arr_insertn((void **) &(a), sizeof(*a), i, n)) 177 | 178 | // insert an element at i 179 | #define stb_arr_insert(a,i,v) (stb__arr_insertn((void **) &(a), sizeof(*a), i, 1), ((a)[i] = v)) 180 | 181 | // delete N elements from the middle starting at index 'i' 182 | #define stb_arr_deleten(a,i,n) (stb__arr_deleten((void **) &(a), sizeof(*a), i, n)) 183 | 184 | // delete the i'th element 185 | #define stb_arr_delete(a,i) stb_arr_deleten(a,i,1) 186 | 187 | // delete the i'th element, swapping down from the end 188 | #define stb_arr_fastdelete(a,i) \ 189 | (stb_swap(&a[i], &a[stb_arrhead(a)->len-1], sizeof(*a)), stb_arr_pop(a)) 190 | 191 | 192 | // ARRAY STORAGE 193 | 194 | // get the array maximum storage; special case if NULL 195 | #define stb_arrcurmax(a) (a ? stb_arrhead(a)->limit : 0) 196 | #define stb_arrcurmax2(a) (a ? stb_arrhead2(a)->limit : 0) 197 | 198 | // set the maxlength of the array to n in anticipation of further growth 199 | #define stb_arr_setsize(a,n) (stb_arr_check(a), stb__arr_setsize((void **) &(a),sizeof((a)[0]),n)) 200 | 201 | // make sure maxlength is large enough for at least N new allocations 202 | #define stb_arr_atleast(a,n) (stb_arr_len(a)+(n) > stb_arrcurmax(a) \ 203 | ? stb_arr_setsize((a), (n)) : 0) 204 | 205 | // make a copy of a given array (copies contents via 'memcpy'!) 206 | #define stb_arr_copy(a) stb__arr_copy(a, sizeof((a)[0])) 207 | 208 | // compute the storage needed to store all the elements of the array 209 | #define stb_arr_storage(a) (stb_arr_len(a) * sizeof((a)[0])) 210 | 211 | #define stb_arr_for(v,arr) for((v)=(arr); (v) < (arr)+stb_arr_len(arr); ++(v)) 212 | 213 | 214 | ZARRDEF void stb_arr_free_(void **p); 215 | ZARRDEF void *stb__arr_copy_(void *p, int elem_size); 216 | ZARRDEF void stb__arr_setsize_(void **p, int size, int limit); 217 | ZARRDEF void stb__arr_setlen_(void **p, int size, int newlen); 218 | ZARRDEF void stb__arr_addlen_(void **p, int size, int addlen); 219 | ZARRDEF void stb__arr_deleten_(void **p, int size, int loc, int n); 220 | ZARRDEF void stb__arr_insertn_(void **p, int size, int loc, int n); 221 | 222 | 223 | #define stb_arr_free(p) stb_arr_free_((void **) &(p)) 224 | #define stb__arr_copy stb__arr_copy_ 225 | 226 | 227 | #ifndef STB_MALLOC_WRAPPER 228 | #define stb__arr_setsize stb__arr_setsize_ 229 | #define stb__arr_setlen stb__arr_setlen_ 230 | #define stb__arr_addlen stb__arr_addlen_ 231 | #define stb__arr_deleten stb__arr_deleten_ 232 | #define stb__arr_insertn stb__arr_insertn_ 233 | #else 234 | #define stb__arr_addlen(p,s,n) stb__arr_addlen_(p,s,n,__FILE__,__LINE__) 235 | #define stb__arr_setlen(p,s,n) stb__arr_setlen_(p,s,n,__FILE__,__LINE__) 236 | #define stb__arr_setsize(p,s,n) stb__arr_setsize_(p,s,n,__FILE__,__LINE__) 237 | #define stb__arr_deleten(p,s,i,n) stb__arr_deleten_(p,s,i,n,__FILE__,__LINE__) 238 | #define stb__arr_insertn(p,s,i,n) stb__arr_insertn_(p,s,i,n,__FILE__,__LINE__) 239 | #endif 240 | 241 | 242 | #if defined(__cplusplus) 243 | } 244 | #endif 245 | 246 | 247 | #endif // __ZEN_ARR_H__ 248 | 249 | 250 | //------------------------------------------ 251 | // 252 | // Implementation 253 | // 254 | //------------------------------------------ 255 | #if defined(ZEN_ARR_IMPLEMENTATION) 256 | 257 | 258 | //////////////////////////////////////////////////////////////////////////////////// 259 | // 260 | // stretchy_buffer.h stb libraries 261 | // 262 | // 263 | 264 | 265 | static void * stb__sbgrowf(void *arr, int increment, int itemsize) { 266 | int dbl_cur = arr ? 2*stb__sbm(arr) : 0; 267 | int min_needed = stb_sb_count(arr) + increment; 268 | int m = dbl_cur > min_needed ? dbl_cur : min_needed; 269 | int *p = (int *) realloc(arr ? stb__sbraw(arr) : 0, itemsize * m + sizeof(int)*2); 270 | if (p) { 271 | if (!arr) 272 | p[1] = 0; 273 | p[0] = m; 274 | return p+2; 275 | } else { 276 | #ifdef STRETCHY_BUFFER_OUT_OF_MEMORY 277 | STRETCHY_BUFFER_OUT_OF_MEMORY ; 278 | #endif 279 | return (void *) (2*sizeof(int)); // try to force a NULL pointer exception later 280 | } 281 | } 282 | 283 | //------------------------------------------ 284 | // 285 | // stb_arr implementation 286 | // 287 | // 288 | 289 | 290 | typedef struct { char d[4]; } stb_arr__4; 291 | typedef struct { char d[8]; } stb_arr__8; 292 | 293 | 294 | // optimize the small cases, though you shouldn't be calling this for those! 295 | static void stb_arr_swap(void *p, void *q, size_t sz) 296 | { 297 | char buffer[256]; 298 | if (p == q) return; 299 | if (sz == 4) { 300 | stb_arr__4 temp = * ( stb_arr__4 *) p; 301 | * (stb_arr__4 *) p = * ( stb_arr__4 *) q; 302 | * (stb_arr__4 *) q = temp; 303 | return; 304 | } else if (sz == 8) { 305 | stb_arr__8 temp = * ( stb_arr__8 *) p; 306 | * (stb_arr__8 *) p = * ( stb_arr__8 *) q; 307 | * (stb_arr__8 *) q = temp; 308 | return; 309 | } 310 | 311 | while (sz > sizeof(buffer)) { 312 | stb_swap(p, q, sizeof(buffer)); 313 | p = (char *) p + sizeof(buffer); 314 | q = (char *) q + sizeof(buffer); 315 | sz -= sizeof(buffer); 316 | } 317 | 318 | memcpy(buffer, p , sz); 319 | memcpy(p , q , sz); 320 | memcpy(q , buffer, sz); 321 | } 322 | 323 | ZARRDEF void * stb__arr_copy_(void *p, int elem_size) { 324 | stb__arr *q; 325 | if (p == NULL) return p; 326 | q = (stb__arr *) malloc(sizeof(*q) + elem_size * stb_arrhead2(p)->limit); 327 | stb_arr_check2(p); 328 | memcpy(q, stb_arrhead2(p), sizeof(*q) + elem_size * stb_arrhead2(p)->len); 329 | return q+1; 330 | } 331 | 332 | 333 | ZARRDEF void stb_arr_free_(void **pp) { 334 | void *p = *pp; 335 | stb_arr_check2(p); 336 | if (p) { 337 | stb__arr *q = stb_arrhead2(p); 338 | free(q); 339 | } 340 | *pp = NULL; 341 | } 342 | 343 | 344 | static void stb__arrsize_(void **pp, int size, int limit, int len) { 345 | void *p = *pp; 346 | stb__arr *a; 347 | stb_arr_check2(p); 348 | if (p == NULL) { 349 | if (len == 0 && size == 0) return; 350 | a = (stb__arr *) malloc(sizeof(*a) + size*limit); 351 | a->limit = limit; 352 | a->len = len; 353 | a->signature = stb_arr_signature; 354 | } else { 355 | a = stb_arrhead2(p); 356 | a->len = len; 357 | if (a->limit < limit) { 358 | void *p; 359 | if (a->limit >= 4 && limit < a->limit * 2) 360 | limit = a->limit * 2; 361 | p = realloc(a, sizeof(*a) + limit*size); 362 | if (p) { 363 | a = (stb__arr *) p; 364 | a->limit = limit; 365 | } else { 366 | // throw an error! 367 | } 368 | } 369 | } 370 | a->len = zen_min(a->len, a->limit); 371 | *pp = a+1; 372 | } 373 | 374 | 375 | ZARRDEF void stb__arr_setsize_(void **pp, int size, int limit) { 376 | void *p = *pp; 377 | stb_arr_check2(p); 378 | stb__arrsize_(pp, size, limit, stb_arr_len2(p)); 379 | } 380 | 381 | 382 | ZARRDEF void stb__arr_setlen_(void **pp, int size, int newlen) { 383 | void *p = *pp; 384 | stb_arr_check2(p); 385 | if (stb_arrcurmax2(p) < newlen || p == NULL) { 386 | stb__arrsize_(pp, size, newlen, newlen); 387 | } else { 388 | stb_arrhead2(p)->len = newlen; 389 | } 390 | } 391 | 392 | 393 | ZARRDEF void stb__arr_addlen_(void **p, int size, int addlen) { 394 | stb__arr_setlen_(p, size, stb_arr_len2(*p) + addlen); 395 | } 396 | 397 | 398 | ZARRDEF void stb__arr_insertn_(void **pp, int size, int i, int n) { 399 | void *p = *pp; 400 | if (n) { 401 | int z; 402 | 403 | if (p == NULL) { 404 | stb__arr_addlen_(pp, size, n); 405 | return; 406 | } 407 | 408 | z = stb_arr_len2(p); 409 | stb__arr_addlen_(&p, size, n); 410 | memmove((char *) p + (i+n)*size, (char *) p + i*size, size * (z-i)); 411 | } 412 | *pp = p; 413 | } 414 | 415 | 416 | ZARRDEF void stb__arr_deleten_(void **pp, int size, int i, int n) { 417 | void *p = *pp; 418 | if (n) { 419 | memmove((char *) p + i*size, (char *) p + (i+n)*size, size * (stb_arr_len2(p)-(i+n))); 420 | stb_arrhead2(p)->len -= n; 421 | } 422 | *pp = p; 423 | } 424 | 425 | 426 | #endif // ZEN_ARR_IMPLEMENTATION 427 | 428 | // Public Domain (www.unlicense.org) 429 | // This is free and unencumbered software released into the public domain. 430 | // Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 431 | // software, either in source code form or as a compiled binary, for any purpose, 432 | // commercial or non-commercial, and by any means. 433 | // In jurisdictions that recognize copyright laws, the author or authors of this 434 | // software dedicate any and all copyright interest in the software to the public 435 | // domain. We make this dedication for the benefit of the public at large and to 436 | // the detriment of our heirs and successors. We intend this dedication to be an 437 | // overt act of relinquishment in perpetuity of all present and future rights to 438 | // this software under copyright law. 439 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 440 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 441 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 442 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 443 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 444 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 445 | -------------------------------------------------------------------------------- /zen_lib/zen_hashmap.h: -------------------------------------------------------------------------------- 1 | /* zen_hashmap.h - v0.42 - Arrays -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_ARR_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_HASHMAP_IMPLEMENTATION 11 | #include "zen_hashmap.h" 12 | 13 | This is stb_arr and stretchy_buffer 14 | Full license at bottom of file. 15 | 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // Instantiated data structures 21 | // 22 | // This is an attempt to implement a templated data structure. 23 | // 24 | // Hash table: call stb_define_hash(TYPE,N,KEY,K1,K2,HASH,VALUE) 25 | // TYPE -- will define a structure type containing the hash table 26 | // N -- the name, will prefix functions named: 27 | // N create 28 | // N destroy 29 | // N get 30 | // N set, N add, N update, 31 | // N remove 32 | // KEY -- the type of the key. 'x == y' must be valid 33 | // K1,K2 -- keys never used by the app, used as flags in the hashtable 34 | // HASH -- a piece of code ending with 'return' that hashes key 'k' 35 | // VALUE -- the type of the value. 'x = y' must be valid 36 | // 37 | // Note that stb_define_hash_base can be used to define more sophisticated 38 | // hash tables, e.g. those that make copies of the key or use special 39 | // comparisons (e.g. strcmp). 40 | 41 | #if 0 42 | 43 | stb_declare_hash(extern "C", zen_hash_t, zen_hash_, const char*, const char*); 44 | stb_define_hash_vnull(zen_hash_t, zen_hash_, const char*, NULL, NULL, return default_hash(k);, const char*, NULL); 45 | 46 | 47 | void lets_try_stb_hashmap() { 48 | 49 | zen_hash_t *hash = zen_hash_create(); 50 | zen_hash_init(hash, 512); 51 | 52 | ziout(zen_hash_set(hash, "key1", "value1")); 53 | ziout(zen_hash_set(hash, "key1", "value3")); 54 | ziout(zen_hash_set(hash, "key1", "value4")); 55 | 56 | ziout(zen_hash_add(hash, "key2", "value2")); 57 | ziout(zen_hash_add(hash, "key2", "value2")); 58 | ziout(zen_hash_add(hash, "key2", "value2")); 59 | 60 | 61 | ziout(zen_hash_add(hash, "key4", "value4")); 62 | 63 | zout("key1: %s", zen_hash_get(hash, "key1")); 64 | zout("key2: %s", zen_hash_get(hash, "key2")); 65 | zout("key3: %s", zen_hash_get(hash, "key3")); 66 | 67 | ziout(zen_hash_memory_usage(hash)); 68 | const char *value; 69 | ziout(zen_hash_get_flag(hash, "keyXXX", &value)); 70 | ziout(zen_hash_update(hash, "keyXXX", "poop")); 71 | ziout(zen_hash_update(hash, "key2", "poop")); 72 | 73 | 74 | ziout(zen_hash_remove(hash, "keyXXX", NULL)); 75 | ziout(zen_hash_remove(hash, "key2", NULL)); 76 | 77 | const char *removed = 0; 78 | ziout(zen_hash_remove(hash, "keyXXX", &removed)); 79 | zout("Removed: %s", removed); 80 | ziout(zen_hash_remove(hash, "key4", &removed)); 81 | zout("Removed: %s", removed); 82 | 83 | zen_hash_destroy(hash); 84 | 85 | } 86 | 87 | #endif 88 | 89 | 90 | #if !defined(__ZEN_HASHMAP_H__) 91 | #define __ZEN_HASHMAP_H__ 92 | 93 | 94 | #if defined(__cplusplus) 95 | extern "C" { 96 | #endif 97 | 98 | 99 | #if defined(ZEN_HASH_STATIC) 100 | #define ZHASHDEV static 101 | #else 102 | #define ZHASHDEV extern 103 | #endif 104 | 105 | 106 | #define stb_rehash(x) ((x) + ((x) >> 6) + ((x) >> 19)) 107 | 108 | 109 | #define STB_(prefix,name) stb__##prefix##name 110 | #define STB__(prefix,name) prefix##name 111 | #define STB__use(x) x 112 | #define STB__skip(x) 113 | 114 | 115 | #define stb_declare_hash(PREFIX,TYPE,N,KEY,VALUE) \ 116 | typedef struct stb__st_##TYPE TYPE;\ 117 | PREFIX int STB__(N, init)(TYPE *h, int count);\ 118 | PREFIX int STB__(N, memory_usage)(TYPE *h);\ 119 | PREFIX TYPE * STB__(N, create)(void);\ 120 | PREFIX TYPE * STB__(N, copy)(TYPE *h);\ 121 | PREFIX void STB__(N, destroy)(TYPE *h);\ 122 | PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v);\ 123 | PREFIX VALUE STB__(N,get)(TYPE *a, KEY k);\ 124 | PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v);\ 125 | PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v);\ 126 | PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v);\ 127 | PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v); 128 | 129 | 130 | #define STB_nocopy(x) (x) 131 | #define STB_nodelete(x) 0 132 | #define STB_nofields 133 | #define STB_nonullvalue(x) 134 | #define STB_nullvalue(x) x 135 | #define STB_safecompare(x) x 136 | #define STB_nosafe(x) 137 | #define STB_noprefix 138 | 139 | 140 | #ifdef __GNUC__ 141 | #define STB__nogcc(x) 142 | #else 143 | #define STB__nogcc(x) x 144 | #endif 145 | 146 | 147 | ////////////////////////////////////////////////////////////////////////////// 148 | // 149 | // Hashing 150 | // 151 | // typical use for this is to make a power-of-two hash table. 152 | // 153 | // let N = size of table (2^n) 154 | // let H = stb_hash(str) 155 | // let S = stb_rehash(H) | 1 156 | // 157 | // then hash probe sequence P(i) for i=0..N-1 158 | // P(i) = (H + S*i) & (N-1) 159 | // 160 | // the idea is that H has 32 bits of hash information, but the 161 | // table has only, say, 2^20 entries so only uses 20 of the bits. 162 | // then by rehashing the original H we get 2^12 different probe 163 | // sequences for a given initial probe location. (So it's optimal 164 | // for 64K tables and its optimality decreases past that.) 165 | // 166 | // ok, so I've added something that generates _two separate_ 167 | // 32-bit hashes simultaneously which should scale better to 168 | // very large tables. 169 | 170 | 171 | ZHASHDEV unsigned int stb_hash(char *str); 172 | ZHASHDEV unsigned int stb_hashptr(void *p); 173 | ZHASHDEV unsigned int stb_hashlen(char *str, int len); 174 | ZHASHDEV unsigned int stb_rehash_improved(unsigned int v); 175 | ZHASHDEV unsigned int stb_hash_fast(void *p, int len); 176 | ZHASHDEV unsigned int stb_hash2(char *str, unsigned int *hash2_ptr); 177 | ZHASHDEV unsigned int stb_hash_number(unsigned int hash); 178 | 179 | 180 | #define stb_define_hash_base(PREFIX,TYPE,FIELDS,N,NC,LOAD_FACTOR, \ 181 | KEY,EMPTY,DEL,COPY,DISPOSE,SAFE, \ 182 | VCOMPARE,CCOMPARE,HASH, \ 183 | VALUE,HASVNULL,VNULL) \ 184 | \ 185 | typedef struct \ 186 | { \ 187 | KEY k; \ 188 | VALUE v; \ 189 | } STB_(N,_hashpair); \ 190 | \ 191 | STB__nogcc( typedef struct stb__st_##TYPE TYPE; ) \ 192 | struct stb__st_##TYPE { \ 193 | FIELDS \ 194 | STB_(N,_hashpair) *table; \ 195 | unsigned int mask; \ 196 | int count, limit; \ 197 | int deleted; \ 198 | \ 199 | int delete_threshhold; \ 200 | int grow_threshhold; \ 201 | int shrink_threshhold; \ 202 | unsigned char alloced, has_empty, has_del; \ 203 | VALUE ev; VALUE dv; \ 204 | }; \ 205 | \ 206 | static unsigned int STB_(N, hash)(KEY k) \ 207 | { \ 208 | HASH \ 209 | } \ 210 | \ 211 | PREFIX int STB__(N, init)(TYPE *h, int count) \ 212 | { \ 213 | int i; \ 214 | if (count < 4) count = 4; \ 215 | h->limit = count; \ 216 | h->count = 0; \ 217 | h->mask = count-1; \ 218 | h->deleted = 0; \ 219 | h->grow_threshhold = (int) (count * LOAD_FACTOR); \ 220 | h->has_empty = h->has_del = 0; \ 221 | h->alloced = 0; \ 222 | if (count <= 64) \ 223 | h->shrink_threshhold = 0; \ 224 | else \ 225 | h->shrink_threshhold = (int) (count * (LOAD_FACTOR/2.25)); \ 226 | h->delete_threshhold = (int) (count * (1-LOAD_FACTOR)/2); \ 227 | h->table = (STB_(N,_hashpair)*) malloc(sizeof(h->table[0]) * count); \ 228 | if (h->table == NULL) return 0; \ 229 | /* ideally this gets turned into a memset32 automatically */ \ 230 | for (i=0; i < count; ++i) \ 231 | h->table[i].k = EMPTY; \ 232 | return 1; \ 233 | } \ 234 | \ 235 | PREFIX int STB__(N, memory_usage)(TYPE *h) \ 236 | { \ 237 | return sizeof(*h) + h->limit * sizeof(h->table[0]); \ 238 | } \ 239 | \ 240 | PREFIX TYPE * STB__(N, create)(void) \ 241 | { \ 242 | TYPE *h = (TYPE *) malloc(sizeof(*h)); \ 243 | if (h) { \ 244 | if (STB__(N, init)(h, 16)) \ 245 | h->alloced = 1; \ 246 | else { free(h); h=NULL; } \ 247 | } \ 248 | return h; \ 249 | } \ 250 | \ 251 | PREFIX void STB__(N, destroy)(TYPE *a) \ 252 | { \ 253 | int i; \ 254 | for (i=0; i < a->limit; ++i) \ 255 | if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k, DEL)) \ 256 | DISPOSE(a->table[i].k); \ 257 | free(a->table); \ 258 | if (a->alloced) \ 259 | free(a); \ 260 | } \ 261 | \ 262 | static void STB_(N, rehash)(TYPE *a, int count); \ 263 | \ 264 | PREFIX int STB__(N,get_flag)(TYPE *a, KEY k, VALUE *v) \ 265 | { \ 266 | unsigned int h = STB_(N, hash)(k); \ 267 | unsigned int n = h & a->mask, s; \ 268 | if (CCOMPARE(k,EMPTY)){ if (a->has_empty) *v = a->ev; return a->has_empty;}\ 269 | if (CCOMPARE(k,DEL)) { if (a->has_del ) *v = a->dv; return a->has_del; }\ 270 | if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 271 | SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \ 272 | if (VCOMPARE(a->table[n].k,k)) { *v = a->table[n].v; return 1; } \ 273 | s = stb_rehash(h) | 1; \ 274 | for(;;) { \ 275 | n = (n + s) & a->mask; \ 276 | if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 277 | SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \ 278 | if (VCOMPARE(a->table[n].k,k)) \ 279 | { *v = a->table[n].v; return 1; } \ 280 | } \ 281 | } \ 282 | \ 283 | HASVNULL( \ 284 | PREFIX VALUE STB__(N,get)(TYPE *a, KEY k) \ 285 | { \ 286 | VALUE v; \ 287 | if (STB__(N,get_flag)(a,k,&v)) return v; \ 288 | else return VNULL; \ 289 | } \ 290 | ) \ 291 | \ 292 | PREFIX int STB__(N,getkey)(TYPE *a, KEY k, KEY *kout) \ 293 | { \ 294 | unsigned int h = STB_(N, hash)(k); \ 295 | unsigned int n = h & a->mask, s; \ 296 | if (CCOMPARE(k,EMPTY)||CCOMPARE(k,DEL)) return 0; \ 297 | if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 298 | SAFE(if (!CCOMPARE(a->table[n].k,DEL))) \ 299 | if (VCOMPARE(a->table[n].k,k)) { *kout = a->table[n].k; return 1; } \ 300 | s = stb_rehash(h) | 1; \ 301 | for(;;) { \ 302 | n = (n + s) & a->mask; \ 303 | if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 304 | SAFE(if (CCOMPARE(a->table[n].k,DEL)) continue;) \ 305 | if (VCOMPARE(a->table[n].k,k)) \ 306 | { *kout = a->table[n].k; return 1; } \ 307 | } \ 308 | } \ 309 | \ 310 | static int STB_(N,addset)(TYPE *a, KEY k, VALUE v, \ 311 | int allow_new, int allow_old, int copy) \ 312 | { \ 313 | unsigned int h = STB_(N, hash)(k); \ 314 | unsigned int n = h & a->mask; \ 315 | int b = -1; \ 316 | if (CCOMPARE(k,EMPTY)) { \ 317 | if (a->has_empty ? allow_old : allow_new) { \ 318 | n=a->has_empty; a->ev = v; a->has_empty = 1; return !n; \ 319 | } else return 0; \ 320 | } \ 321 | if (CCOMPARE(k,DEL)) { \ 322 | if (a->has_del ? allow_old : allow_new) { \ 323 | n=a->has_del; a->dv = v; a->has_del = 1; return !n; \ 324 | } else return 0; \ 325 | } \ 326 | if (!CCOMPARE(a->table[n].k, EMPTY)) { \ 327 | unsigned int s; \ 328 | if (CCOMPARE(a->table[n].k, DEL)) \ 329 | b = n; \ 330 | else if (VCOMPARE(a->table[n].k,k)) { \ 331 | if (allow_old) \ 332 | a->table[n].v = v; \ 333 | return !allow_new; \ 334 | } \ 335 | s = stb_rehash(h) | 1; \ 336 | for(;;) { \ 337 | n = (n + s) & a->mask; \ 338 | if (CCOMPARE(a->table[n].k, EMPTY)) break; \ 339 | if (CCOMPARE(a->table[n].k, DEL)) { \ 340 | if (b < 0) b = n; \ 341 | } else if (VCOMPARE(a->table[n].k,k)) { \ 342 | if (allow_old) \ 343 | a->table[n].v = v; \ 344 | return !allow_new; \ 345 | } \ 346 | } \ 347 | } \ 348 | if (!allow_new) return 0; \ 349 | if (b < 0) b = n; else --a->deleted; \ 350 | a->table[b].k = copy ? COPY(k) : k; \ 351 | a->table[b].v = v; \ 352 | ++a->count; \ 353 | if (a->count > a->grow_threshhold) \ 354 | STB_(N,rehash)(a, a->limit*2); \ 355 | return 1; \ 356 | } \ 357 | \ 358 | PREFIX int STB__(N, set)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,1,1);}\ 359 | PREFIX int STB__(N, add)(TYPE *a, KEY k, VALUE v){return STB_(N,addset)(a,k,v,1,0,1);}\ 360 | PREFIX int STB__(N, update)(TYPE*a,KEY k,VALUE v){return STB_(N,addset)(a,k,v,0,1,1);}\ 361 | \ 362 | PREFIX int STB__(N, remove)(TYPE *a, KEY k, VALUE *v) \ 363 | { \ 364 | unsigned int h = STB_(N, hash)(k); \ 365 | unsigned int n = h & a->mask, s; \ 366 | if (CCOMPARE(k,EMPTY)) { if (a->has_empty) { if(v)*v = a->ev; a->has_empty=0; return 1; } return 0; } \ 367 | if (CCOMPARE(k,DEL)) { if (a->has_del ) { if(v)*v = a->dv; a->has_del =0; return 1; } return 0; } \ 368 | if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 369 | if (SAFE(CCOMPARE(a->table[n].k,DEL) || ) !VCOMPARE(a->table[n].k,k)) { \ 370 | s = stb_rehash(h) | 1; \ 371 | for(;;) { \ 372 | n = (n + s) & a->mask; \ 373 | if (CCOMPARE(a->table[n].k,EMPTY)) return 0; \ 374 | SAFE(if (CCOMPARE(a->table[n].k, DEL)) continue;) \ 375 | if (VCOMPARE(a->table[n].k,k)) break; \ 376 | } \ 377 | } \ 378 | DISPOSE(a->table[n].k); \ 379 | a->table[n].k = DEL; \ 380 | --a->count; \ 381 | ++a->deleted; \ 382 | if (v != NULL) \ 383 | *v = a->table[n].v; \ 384 | if (a->count < a->shrink_threshhold) \ 385 | STB_(N, rehash)(a, a->limit >> 1); \ 386 | else if (a->deleted > a->delete_threshhold) \ 387 | STB_(N, rehash)(a, a->limit); \ 388 | return 1; \ 389 | } \ 390 | \ 391 | PREFIX TYPE * STB__(NC, copy)(TYPE *a) \ 392 | { \ 393 | int i; \ 394 | TYPE *h = (TYPE *) malloc(sizeof(*h)); \ 395 | if (!h) return NULL; \ 396 | if (!STB__(N, init)(h, a->limit)) { free(h); return NULL; } \ 397 | h->count = a->count; \ 398 | h->deleted = a->deleted; \ 399 | h->alloced = 1; \ 400 | h->ev = a->ev; h->dv = a->dv; \ 401 | h->has_empty = a->has_empty; h->has_del = a->has_del; \ 402 | memcpy(h->table, a->table, h->limit * sizeof(h->table[0])); \ 403 | for (i=0; i < a->limit; ++i) \ 404 | if (!CCOMPARE(h->table[i].k,EMPTY) && !CCOMPARE(h->table[i].k,DEL)) \ 405 | h->table[i].k = COPY(h->table[i].k); \ 406 | return h; \ 407 | } \ 408 | \ 409 | static void STB_(N, rehash)(TYPE *a, int count) \ 410 | { \ 411 | int i; \ 412 | TYPE b; \ 413 | STB__(N, init)(&b, count); \ 414 | for (i=0; i < a->limit; ++i) \ 415 | if (!CCOMPARE(a->table[i].k,EMPTY) && !CCOMPARE(a->table[i].k,DEL)) \ 416 | STB_(N,addset)(&b, a->table[i].k, a->table[i].v,1,1,0); \ 417 | free(a->table); \ 418 | a->table = b.table; \ 419 | a->mask = b.mask; \ 420 | a->count = b.count; \ 421 | a->limit = b.limit; \ 422 | a->deleted = b.deleted; \ 423 | a->delete_threshhold = b.delete_threshhold; \ 424 | a->grow_threshhold = b.grow_threshhold; \ 425 | a->shrink_threshhold = b.shrink_threshhold; \ 426 | } 427 | 428 | #define STB_equal(a,b) ((a) == (b)) 429 | 430 | #define stb_define_hash(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE) \ 431 | stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \ 432 | KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \ 433 | STB_equal,STB_equal,HASH, \ 434 | VALUE,STB_nonullvalue,0) 435 | 436 | #define stb_define_hash_vnull(TYPE,N,KEY,EMPTY,DEL,HASH,VALUE,VNULL) \ 437 | stb_define_hash_base(STB_noprefix, TYPE,STB_nofields,N,NC,0.85f, \ 438 | KEY,EMPTY,DEL,STB_nocopy,STB_nodelete,STB_nosafe, \ 439 | STB_equal,STB_equal,HASH, \ 440 | VALUE,STB_nullvalue,VNULL) 441 | 442 | 443 | #if defined(__cplusplus) 444 | } 445 | #endif 446 | 447 | 448 | #endif //__ZEN_HASHMAP_H__ 449 | 450 | 451 | //------------------------------------------ 452 | // 453 | // Implementation 454 | // 455 | // 456 | #if defined(ZEN_HASHMAP_IMPLEMENTATION) 457 | 458 | 459 | ZHASHDEV unsigned int stb_hash(char *str) 460 | { 461 | unsigned int hash = 0; 462 | while (*str) 463 | hash = (hash << 7) + (hash >> 25) + *str++; 464 | return hash + (hash >> 16); 465 | } 466 | 467 | ZHASHDEV unsigned int stb_hashlen(char *str, int len) 468 | { 469 | unsigned int hash = 0; 470 | while (len-- > 0 && *str) 471 | hash = (hash << 7) + (hash >> 25) + *str++; 472 | return hash + (hash >> 16); 473 | } 474 | 475 | ZHASHDEV unsigned int stb_hashptr(void *p) 476 | { 477 | psize x = (psize) p; 478 | 479 | // typically lacking in low bits and high bits 480 | x = stb_rehash(x); 481 | x += x << 16; 482 | 483 | // pearson's shuffle 484 | x ^= x << 3; 485 | x += x >> 5; 486 | x ^= x << 2; 487 | x += x >> 15; 488 | x ^= x << 10; 489 | return stb_rehash(x); 490 | } 491 | 492 | ZHASHDEV unsigned int stb_rehash_improved(unsigned int v) 493 | { 494 | return stb_hashptr((void *)(size_t) v); 495 | } 496 | 497 | ZHASHDEV unsigned int stb_hash2(char *str, unsigned int *hash2_ptr) 498 | { 499 | unsigned int hash1 = 0x3141592c; 500 | unsigned int hash2 = 0x77f044ed; 501 | while (*str) { 502 | hash1 = (hash1 << 7) + (hash1 >> 25) + *str; 503 | hash2 = (hash2 << 11) + (hash2 >> 21) + *str; 504 | ++str; 505 | } 506 | *hash2_ptr = hash2 + (hash1 >> 16); 507 | return hash1 + (hash2 >> 16); 508 | } 509 | 510 | // Paul Hsieh hash 511 | #define stb__get16_slow(p) ((p)[0] + ((p)[1] << 8)) 512 | #if defined(_MSC_VER) 513 | #define stb__get16(p) (*((unsigned short *) (p))) 514 | #else 515 | #define stb__get16(p) stb__get16_slow(p) 516 | #endif 517 | 518 | ZHASHDEV unsigned int stb_hash_fast(void *p, int len) 519 | { 520 | psize *q = (psize *) p; 521 | unsigned int hash = len; 522 | 523 | if (len <= 0 || q == NULL) return 0; 524 | 525 | /* Main loop */ 526 | if (((psize) q & 1) == 0) { 527 | for (;len > 3; len -= 4) { 528 | unsigned int val; 529 | hash += stb__get16(q); 530 | val = (stb__get16(q+2) << 11); 531 | hash = (hash << 16) ^ hash ^ val; 532 | q += 4; 533 | hash += hash >> 11; 534 | } 535 | } else { 536 | for (;len > 3; len -= 4) { 537 | unsigned int val; 538 | hash += stb__get16_slow(q); 539 | val = (stb__get16_slow(q+2) << 11); 540 | hash = (hash << 16) ^ hash ^ val; 541 | q += 4; 542 | hash += hash >> 11; 543 | } 544 | } 545 | 546 | /* Handle end cases */ 547 | switch (len) { 548 | case 3: hash += stb__get16_slow(q); 549 | hash ^= hash << 16; 550 | hash ^= q[2] << 18; 551 | hash += hash >> 11; 552 | break; 553 | case 2: hash += stb__get16_slow(q); 554 | hash ^= hash << 11; 555 | hash += hash >> 17; 556 | break; 557 | case 1: hash += q[0]; 558 | hash ^= hash << 10; 559 | hash += hash >> 1; 560 | break; 561 | case 0: break; 562 | } 563 | 564 | /* Force "avalanching" of final 127 bits */ 565 | hash ^= hash << 3; 566 | hash += hash >> 5; 567 | hash ^= hash << 4; 568 | hash += hash >> 17; 569 | hash ^= hash << 25; 570 | hash += hash >> 6; 571 | 572 | return hash; 573 | } 574 | 575 | ZHASHDEV unsigned int stb_hash_number(unsigned int hash) 576 | { 577 | hash ^= hash << 3; 578 | hash += hash >> 5; 579 | hash ^= hash << 4; 580 | hash += hash >> 17; 581 | hash ^= hash << 25; 582 | hash += hash >> 6; 583 | return hash; 584 | } 585 | 586 | #endif //ZEN_HASHMAP_IMPLEMENTATION 587 | 588 | // Public Domain (www.unlicense.org) 589 | // This is free and unencumbered software released into the public domain. 590 | // Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 591 | // software, either in source code form or as a compiled binary, for any purpose, 592 | // commercial or non-commercial, and by any means. 593 | // In jurisdictions that recognize copyright laws, the author or authors of this 594 | // software dedicate any and all copyright interest in the software to the public 595 | // domain. We make this dedication for the benefit of the public at large and to 596 | // the detriment of our heirs and successors. We intend this dedication to be an 597 | // overt act of relinquishment in perpetuity of all present and future rights to 598 | // this software under copyright law. 599 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 600 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 601 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 602 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 603 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 604 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 605 | -------------------------------------------------------------------------------- /zen_lib/zen_math.h: -------------------------------------------------------------------------------- 1 | /* zen_math.h - v0.42 - Math Library -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_MATH_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_MATH_IMPLEMENTATION 11 | #include "zen_math.h" 12 | 13 | zlib license: 14 | Full license at bottom of file. 15 | 16 | */ 17 | 18 | #ifndef __ZEN_MATN_H__ 19 | #define __ZEN_MATN_H__ 20 | 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #ifndef zout 27 | #include "zen_lib/zen.h" 28 | #endif 29 | 30 | 31 | #ifndef uint8 32 | #include 33 | typedef int8_t int8; 34 | typedef int16_t int16; 35 | typedef int32_t int32; 36 | typedef int64_t int64; 37 | typedef uint8_t uint8; 38 | typedef uint16_t uint16; 39 | typedef uint32_t uint32; 40 | typedef uint64_t uint64; 41 | #endif 42 | 43 | 44 | #ifndef cosf 45 | #include 46 | #endif 47 | 48 | 49 | #ifndef M_PI 50 | #define M_PI 3.14159265358979323846 51 | #endif 52 | 53 | 54 | #define ZM_DEG2RAD M_PI / 180.0 55 | #define ZM_RAD2DEG 180.0 / M_PI 56 | 57 | 58 | #ifdef ZEN_MATH_STATIC 59 | #define ZMATHDEF static 60 | #else 61 | #define ZMATHDEF extern 62 | #endif 63 | 64 | 65 | typedef union Matrix2x2_t { 66 | float m[4]; 67 | } Matrix2x2_t; 68 | 69 | 70 | typedef union Matrix3x3_t { 71 | float m[9]; 72 | } Matrix3x3_t; 73 | 74 | 75 | typedef union Matrix4x4_t { 76 | float m[16]; 77 | } Matrix4x4_t; 78 | 79 | 80 | typedef union Vector2_t { 81 | struct { float x, y; }; 82 | float e[2]; 83 | } Vector2_t; 84 | 85 | 86 | typedef union Vector3_t { 87 | struct { float x, y, z; }; 88 | float e[3]; 89 | } Vector3_t; 90 | 91 | 92 | typedef union Vector4_t { 93 | struct { float x, y, z, w; }; 94 | float e[4]; 95 | } Vector4_t; 96 | 97 | 98 | typedef union Color_t { 99 | struct{ uint8 r, g, b, a; }; 100 | uint32 rgba; 101 | uint8 e[4]; 102 | } Color_t; 103 | 104 | 105 | typedef union Colorf_t { 106 | struct{ float r, g, b, a; }; 107 | float e[4]; 108 | } Colorf_t; 109 | 110 | 111 | typedef struct Transform2d_t { 112 | Vector2_t position; 113 | Vector2_t scale; 114 | float rotation; 115 | } Transform2d_t; 116 | 117 | 118 | typedef struct Transform3d_t { 119 | Vector3_t position; 120 | Vector3_t rotation; 121 | Vector3_t scale; 122 | } Transform3d_t; 123 | 124 | 125 | ZMATHDEF Matrix2x2_t Matrix2x2(); 126 | ZMATHDEF Matrix3x3_t Matrix3x3(); 127 | ZMATHDEF Matrix4x4_t Matrix4x4(); 128 | 129 | 130 | ZMATHDEF Vector2_t Vector2(float x, float y); 131 | ZMATHDEF Vector3_t Vector3(float x, float y, float z); 132 | ZMATHDEF Vector4_t Vector4(float x, float y, float z, float w); 133 | 134 | 135 | ZMATHDEF Color_t Color(uint8 r, uint8 g, uint8 b, uint8 a = 255); 136 | ZMATHDEF Colorf_t Colorf(float r, float g, float b, float a = 1.0f); 137 | 138 | // @TODO(tim):This really doesn't go here 139 | ZMATHDEF Transform2d_t Transform2d(Vector2_t position, float rotation, Vector2_t scale); 140 | ZMATHDEF Transform3d_t Transform3d(Vector3_t position, Vector3_t rotation, Vector3_t scale); 141 | 142 | 143 | ZMATHDEF Vector2_t add_vec2(Vector2_t a, Vector2_t b); 144 | ZMATHDEF Vector2_t sub_vec2(Vector2_t a, Vector2_t b); 145 | ZMATHDEF Vector2_t mul_vec2(Vector2_t v, float s); 146 | ZMATHDEF Vector2_t inv_vec2(Vector2_t v); 147 | ZMATHDEF float dot_vec2(Vector2_t a, Vector2_t b); 148 | ZMATHDEF float len_vec2(Vector2_t a); 149 | ZMATHDEF float len_sqr_vec2(Vector2_t a); 150 | ZMATHDEF Vector2_t norm_vec2(Vector2_t a); 151 | ZMATHDEF Vector2_t lerp_vec2(Vector2_t a, Vector2_t b, float t); 152 | 153 | 154 | ZMATHDEF Vector3_t add_vec3(Vector3_t a, Vector3_t b); 155 | ZMATHDEF Vector3_t sub_vec3(Vector3_t a, Vector3_t b); 156 | ZMATHDEF Vector3_t mul_vec3(Vector3_t v, float s); 157 | ZMATHDEF Vector3_t inv_vec3(Vector3_t v); 158 | ZMATHDEF float dot_vec3(Vector3_t a, Vector3_t b); 159 | ZMATHDEF float len_vec3(Vector3_t a); 160 | ZMATHDEF float len_sqr_vec3(Vector3_t a); 161 | ZMATHDEF Vector3_t norm_vec3(Vector3_t a); 162 | ZMATHDEF Vector3_t lerp_vec3(Vector3_t a, Vector3_t b, float t); 163 | ZMATHDEF Vector3_t cross_vec3(Vector3_t a, Vector3_t b); 164 | 165 | 166 | ZMATHDEF Vector4_t add_vec4(Vector4_t a, Vector4_t b); 167 | ZMATHDEF Vector4_t sub_vec4(Vector4_t a, Vector4_t b); 168 | ZMATHDEF Vector4_t mul_vec4(Vector4_t v, float s); 169 | ZMATHDEF Vector4_t inv_vec4(Vector4_t v); 170 | ZMATHDEF float dot_vec4(Vector4_t a, Vector4_t b); 171 | 172 | 173 | ZMATHDEF Matrix2x2_t mul_mat2x2(Matrix2x2_t a, Matrix2x2_t b); 174 | ZMATHDEF Matrix3x3_t mul_mat3x3(Matrix3x3_t a, Matrix3x3_t b); 175 | ZMATHDEF Matrix4x4_t mul_mat4x4(Matrix4x4_t a, Matrix4x4_t b); 176 | 177 | 178 | ZMATHDEF Vector3_t mul_mat3x3_vec3(Matrix3x3_t m, Vector3_t v); 179 | ZMATHDEF Vector4_t mul_mat4x4_vec4(Matrix4x4_t m, Vector4_t v); 180 | 181 | 182 | ZMATHDEF Matrix3x3_t trans_mat3x3(Matrix3x3_t m, Vector2_t v); 183 | ZMATHDEF Matrix3x3_t rot_mat3x3(Matrix3x3_t m, float rad); 184 | ZMATHDEF Matrix3x3_t scale_mat3x3(Matrix3x3_t m, Vector2_t v); 185 | 186 | 187 | ZMATHDEF Matrix4x4_t trans_mat4x4(Matrix4x4_t m, Vector3_t v); 188 | ZMATHDEF Matrix4x4_t rotx_mat4x4(Matrix4x4_t m, float rad); 189 | ZMATHDEF Matrix4x4_t roty_mat4x4(Matrix4x4_t m, float rad); 190 | ZMATHDEF Matrix4x4_t rotz_mat4x4(Matrix4x4_t m, float rad); 191 | ZMATHDEF Matrix4x4_t rotate_mat4x4(Matrix4x4_t m, Vector3_t rad); 192 | ZMATHDEF Matrix4x4_t scale_mat4x4(Matrix4x4_t m, Vector3_t v); 193 | ZMATHDEF int inverse_mat4x4(Matrix4x4_t mat, Matrix4x4_t *out); 194 | 195 | 196 | ZMATHDEF Matrix4x4_t ortho_mat4x4(float b, float t, float l, float r, float n, float f); 197 | ZMATHDEF Matrix4x4_t frustum_mat4x4(float b, float t, float l, float r, float n, float f); 198 | ZMATHDEF Matrix4x4_t perspective_mat4x4(float fovy, float aspect, float n, float f); 199 | ZMATHDEF Matrix4x4_t look_at_mat4x4(Vector3_t eye, Vector3_t center, Vector3_t up); 200 | 201 | 202 | ZMATHDEF void print_vec2(Vector2_t v); 203 | ZMATHDEF void print_vec3(Vector3_t v); 204 | ZMATHDEF void print_vec4(Vector4_t v); 205 | ZMATHDEF void print_mat2x2(Matrix2x2_t m); 206 | ZMATHDEF void print_mat3x3(Matrix3x3_t m); 207 | ZMATHDEF void print_mat4x4(Matrix4x4_t m); 208 | 209 | 210 | #ifdef __cplusplus 211 | } 212 | #endif 213 | 214 | 215 | #ifdef __cplusplus 216 | 217 | 218 | zen_inline Vector2_t operator+(Vector2_t a) {return a;} 219 | zen_inline Vector2_t operator+(Vector2_t a, Vector2_t b) {return Vector2(a.x + b.x, a.y + b.y);} 220 | zen_inline Vector2_t operator-(Vector2_t a) {return Vector2(-a.x, -a.y);} 221 | zen_inline Vector2_t operator-(Vector2_t a, Vector2_t b) {return Vector2(a.x - b.x, a.y - b.y);} 222 | zen_inline Vector2_t operator*(Vector2_t a, float s) {return Vector2(a.x * s, a.y * s);} 223 | zen_inline Vector2_t operator*(float s, Vector2_t a) {return Vector2(a.x * s, a.y * s);} 224 | zen_inline Vector2_t operator/(Vector2_t a, float s) {return Vector2(a.x / s, a.y / s);} 225 | 226 | 227 | zen_inline Vector2_t& operator+=(Vector2_t &a, Vector2_t b) {return a = a + b;} 228 | zen_inline Vector2_t& operator-=(Vector2_t &a, Vector2_t b) {return a = a - b;} 229 | zen_inline Vector2_t& operator*=(Vector2_t &a, float s) {return a = a * s;} 230 | zen_inline Vector2_t& operator/=(Vector2_t &a, float s) {return a = a / s;} 231 | 232 | 233 | zen_inline Vector3_t operator+(Vector3_t a) {return a;} 234 | zen_inline Vector3_t operator+(Vector3_t a, Vector3_t b) {return Vector3(a.x + b.x, a.y + b.y, a.z + b.z);} 235 | zen_inline Vector3_t operator-(Vector3_t a) {return Vector3(-a.x, -a.y, -a.z);} 236 | zen_inline Vector3_t operator-(Vector3_t a, Vector3_t b) {return Vector3(a.x - b.x, a.y - b.y, a.z - b.z);} 237 | zen_inline Vector3_t operator*(Vector3_t a, float s) {return Vector3(a.x * s, a.y * s, a.z * s);} 238 | zen_inline Vector3_t operator*(float s, Vector3_t a) {return Vector3(a.x * s, a.y * s, a.z * s);} 239 | zen_inline Vector3_t operator/(Vector3_t a, float s) {return Vector3(a.x / s, a.y / s, a.z / s);} 240 | 241 | 242 | zen_inline Vector3_t& operator+=(Vector3_t &a, Vector3_t b) {return a = a + b;} 243 | zen_inline Vector3_t& operator-=(Vector3_t &a, Vector3_t b) {return a = a - b;} 244 | zen_inline Vector3_t& operator*=(Vector3_t &a, float s) {return a = a * s;} 245 | zen_inline Vector3_t& operator/=(Vector3_t &a, float s) {return a = a / s;} 246 | 247 | 248 | zen_inline Colorf_t operator*(Colorf_t c, float s) {return Colorf(c.r * s, c.g * s, c.b * s, c.a * s);} 249 | zen_inline Colorf_t operator*(float s, Colorf_t c) {return Colorf(c.r * s, c.g * s, c.b * s, c.a * s);} 250 | zen_inline Colorf_t& operator*=(Colorf_t &c, float s) {return c = c * s;} 251 | 252 | 253 | zen_inline float len(Vector2_t a) {return len_vec2(a);} 254 | zen_inline float len_sqr(Vector2_t a) {return len_sqr_vec2(a);} 255 | zen_inline float dot(Vector2_t a, Vector2_t b) {return dot_vec2(a, b);} 256 | zen_inline Vector2_t norm(Vector2_t a) {return norm_vec2(a);} 257 | zen_inline Vector2_t lerp(Vector2_t a, Vector2_t b, float t) {return (1.0f - t) * a + t * b;} 258 | 259 | 260 | zen_inline float len(Vector3_t a) {return len_vec3(a);} 261 | zen_inline float len_sqr(Vector3_t a) {return len_sqr_vec3(a);} 262 | zen_inline float dot(Vector3_t a, Vector3_t b) {return dot_vec3(a, b);} 263 | zen_inline Vector3_t norm(Vector3_t a) {return norm_vec3(a);} 264 | zen_inline Vector3_t lerp(Vector3_t a, Vector3_t b, float t) {return (1.0f - t) * a + t * b;} 265 | zen_inline Vector3_t cross(Vector3_t a, Vector3_t b) {return cross_vec3(a, b);} 266 | 267 | 268 | zen_inline Matrix2x2_t operator*(Matrix2x2_t a, Matrix2x2_t b) {return mul_mat2x2(a, b);} 269 | zen_inline Matrix3x3_t operator*(Matrix3x3_t a, Matrix3x3_t b) {return mul_mat3x3(a, b);} 270 | zen_inline Matrix4x4_t operator*(Matrix4x4_t a, Matrix4x4_t b) {return mul_mat4x4(a, b);} 271 | 272 | zen_inline Matrix2x2_t& operator*=(Matrix2x2_t &a, Matrix2x2_t b) {return a = a * b;} 273 | zen_inline Matrix3x3_t& operator*=(Matrix3x3_t &a, Matrix3x3_t b) {return a = a * b;} 274 | zen_inline Matrix4x4_t& operator*=(Matrix4x4_t &a, Matrix4x4_t b) {return a = a * b;} 275 | 276 | zen_inline Vector3_t operator*(Matrix3x3_t m, Vector3_t v) {return mul_mat3x3_vec3(m, v);} 277 | zen_inline Vector4_t operator*(Matrix4x4_t m, Vector4_t v) {return mul_mat4x4_vec4(m, v);} 278 | 279 | zen_inline Vector3_t& operator*=(Vector3_t &a, Matrix3x3_t b) {return a = b * a;} 280 | zen_inline Vector4_t& operator*=(Vector4_t &a, Matrix4x4_t b) {return a = b * a;} 281 | 282 | 283 | zen_inline Matrix3x3_t translate(Vector2_t v) {return trans_mat3x3(Matrix3x3(), v);} 284 | zen_inline Matrix3x3_t rotate2D(float rad) {return rot_mat3x3(Matrix3x3(), rad);} 285 | zen_inline Matrix3x3_t scale(Vector2_t v) {return scale_mat3x3(Matrix3x3_t(), v);} 286 | 287 | 288 | zen_inline Matrix4x4_t translate(Vector3_t v) {return trans_mat4x4(Matrix4x4(), v);} 289 | zen_inline Matrix4x4_t rotx(float rad) {return rotx_mat4x4(Matrix4x4(), rad);} 290 | zen_inline Matrix4x4_t roty(float rad) {return roty_mat4x4(Matrix4x4(), rad);} 291 | zen_inline Matrix4x4_t rotz(float rad) {return rotz_mat4x4(Matrix4x4(), rad);} 292 | zen_inline Matrix4x4_t rotate(Vector3_t v) {return rotate_mat4x4(Matrix4x4(), v);} 293 | zen_inline Matrix4x4_t scale(Vector3_t v) {return scale_mat4x4(Matrix4x4(), v);} 294 | 295 | 296 | zen_inline void print(Vector2_t m) {print_vec2(m);} 297 | zen_inline void print(Vector3_t m) {print_vec3(m);} 298 | zen_inline void print(Vector4_t m) {print_vec4(m);} 299 | 300 | zen_inline void print(Matrix2x2_t m) {print_mat2x2(m);} 301 | zen_inline void print(Matrix3x3_t m) {print_mat3x3(m);} 302 | zen_inline void print(Matrix4x4_t m) {print_mat4x4(m);} 303 | 304 | 305 | #endif 306 | 307 | 308 | #endif // __ZEN_MATN_H__ 309 | 310 | 311 | //------------------------------------------ 312 | // 313 | // 314 | // IMPLEMENTATION 315 | // 316 | // 317 | //------------------------------------------ 318 | 319 | 320 | #ifdef ZEN_MATH_IMPLEMENTATION 321 | 322 | 323 | Color_t COLOR_WHITE = Color(255, 255, 255, 255); 324 | Color_t COLOR_SILVER = Color(191, 191, 191, 255); 325 | Color_t COLOR_GRAY = Color(128, 128, 128, 255); 326 | Color_t COLOR_BLACK = Color(0, 0, 0, 255); 327 | Color_t COLOR_RED = Color(255, 0, 0, 255); 328 | Color_t COLOR_MAROON = Color(128, 0, 0, 255); 329 | Color_t COLOR_YELLOW = Color(255, 255, 0, 255); 330 | Color_t COLOR_OLIVE = Color(128, 128, 0, 255); 331 | Color_t COLOR_LIME = Color(0, 255, 0, 255); 332 | Color_t COLOR_GREEN = Color(0, 128, 0, 255); 333 | Color_t COLOR_AQUA = Color(0, 255, 255, 255); 334 | Color_t COLOR_TEAL = Color(0, 128, 128, 255); 335 | Color_t COLOR_BLUE = Color(0, 0, 255, 255); 336 | Color_t COLOR_NAVY = Color(0, 0, 128, 255); 337 | Color_t COLOR_FUCHSIA = Color(255, 0, 255, 255); 338 | Color_t COLOR_PURPLE = Color(128, 0, 128, 255); 339 | 340 | 341 | Colorf_t COLORF_WHITE = Colorf(255/255.99f, 255/255.99f, 255/255.99f, 255/255.99f); 342 | Colorf_t COLORF_SILVER = Colorf(191/255.99f, 191/255.99f, 191/255.99f, 255/255.99f); 343 | Colorf_t COLORF_GRAY = Colorf(128/255.99f, 128/255.99f, 128/255.99f, 255/255.99f); 344 | Colorf_t COLORF_BLACK = Colorf(0, 0, 0, 255/255.99f); 345 | Colorf_t COLORF_RED = Colorf(191/255.99f, 0, 0, 255/255.99f); 346 | Colorf_t COLORF_MAROON = Colorf(128/255.99f, 0, 0, 255/255.99f); 347 | Colorf_t COLORF_YELLOW = Colorf(255/255.99f, 255/255.99f, 0, 255/255.99f); 348 | Colorf_t COLORF_OLIVE = Colorf(128/255.99f, 128/255.99f, 0, 255/255.99f); 349 | Colorf_t COLORF_LIME = Colorf(0, 255/255.99f, 0, 255/255.99f); 350 | Colorf_t COLORF_GREEN = Colorf(0, 128/255.99f, 0, 255/255.99f); 351 | Colorf_t COLORF_AQUA = Colorf(0, 255/255.99f, 255/255.99f, 255/255.99f); 352 | Colorf_t COLORF_TEAL = Colorf(0, 128/255.99f, 128/255.99f, 255/255.99f); 353 | Colorf_t COLORF_BLUE = Colorf(0, 0, 255/255.99f, 255/255.99f); 354 | Colorf_t COLORF_NAVY = Colorf(0, 0, 128/255.99f, 255/255.99f); 355 | Colorf_t COLORF_FUCHSIA = Colorf(255/255.99f, 0, 255/255.99f, 255/255.99f); 356 | Colorf_t COLORF_PURPLE = Colorf(128/255.99f, 0, 128/255.99f, 255/255.99f); 357 | 358 | 359 | ZMATHDEF Matrix2x2_t Matrix2x2() { 360 | Matrix2x2_t m; 361 | m.m[0] = 1.f; m.m[1] = 0.f; 362 | m.m[2] = 0.f; m.m[3] = 1.f; 363 | return m; 364 | } 365 | 366 | 367 | ZMATHDEF Matrix3x3_t Matrix3x3() { 368 | Matrix3x3_t m; 369 | for (int32 i = 0; i < 9; ++i) 370 | m.m[i] = 0.f; 371 | m.m[0] = 1.f; 372 | m.m[4] = 1.f; 373 | m.m[8] = 1.f; 374 | return m; 375 | } 376 | 377 | 378 | ZMATHDEF Matrix4x4_t Matrix4x4() { 379 | Matrix4x4_t m; 380 | for (int32 i = 0; i < 16; ++i) 381 | m.m[i] = 0.0f; 382 | 383 | m.m[0] = 1.0f; 384 | m.m[5] = 1.0f; 385 | m.m[10] = 1.0f; 386 | m.m[15] = 1.0f; 387 | return m; 388 | } 389 | 390 | 391 | ZMATHDEF Vector2_t Vector2(float x, float y) { 392 | Vector2_t v; 393 | v.x = x; 394 | v.y = y; 395 | return v; 396 | } 397 | 398 | 399 | ZMATHDEF Vector3_t Vector3(float x, float y, float z) { 400 | Vector3_t v; 401 | v.x = x; 402 | v.y = y; 403 | v.z = z; 404 | return v; 405 | } 406 | 407 | 408 | ZMATHDEF Vector4_t Vector4(float x, float y, float z, float w) { 409 | Vector4_t v; 410 | v.x = x; 411 | v.y = y; 412 | v.z = z; 413 | v.w = w; 414 | return v; 415 | } 416 | 417 | 418 | ZMATHDEF Color_t Color(uint8 r, uint8 g, uint8 b, uint8 a) { 419 | Color_t c; 420 | c.r = r; 421 | c.g = g; 422 | c.b = b; 423 | c.a = a; 424 | return c; 425 | } 426 | 427 | 428 | ZMATHDEF Colorf_t Colorf(float r, float g, float b, float a) { 429 | Colorf_t c; 430 | c.r = r; 431 | c.g = g; 432 | c.b = b; 433 | c.a = a; 434 | return c; 435 | } 436 | 437 | 438 | ZMATHDEF Transform2d_t Transform2d(Vector2_t position, float rotation, Vector2_t scale) { 439 | Transform2d_t t; 440 | t.position = position; 441 | t.rotation = rotation; 442 | t.scale = scale; 443 | return t; 444 | } 445 | 446 | ZMATHDEF Transform3d_t Transform3d(Vector3_t position, Vector3_t rotation, Vector3_t scale) { 447 | Transform3d_t t; 448 | t.position = position; 449 | t.rotation = rotation; 450 | t.scale = scale; 451 | return t; 452 | } 453 | 454 | ZMATHDEF Vector2_t add_vec2(Vector2_t a, Vector2_t b) { 455 | return Vector2(a.x + b.x, a.y + b.y); 456 | } 457 | 458 | 459 | ZMATHDEF Vector2_t sub_vec2(Vector2_t a, Vector2_t b) { 460 | return Vector2(a.x - b.x, a.y - b.y); 461 | } 462 | 463 | 464 | ZMATHDEF Vector2_t mul_vec2(Vector2_t v, float s) { 465 | return Vector2(v.x * s, v.y * s); 466 | } 467 | 468 | 469 | ZMATHDEF Vector2_t inv_vec2(Vector2_t v) { 470 | return Vector2(-v.x, -v.y); 471 | } 472 | 473 | 474 | ZMATHDEF float dot_vec2(Vector2_t a, Vector2_t b) { 475 | return a.x * b.x + a.y * b.y; 476 | } 477 | 478 | 479 | ZMATHDEF float len_vec2(Vector2_t a) { 480 | return sqrt(a.x*a.x + a.y*a.y); 481 | } 482 | 483 | 484 | ZMATHDEF float len_sqr_vec2(Vector2_t a) { 485 | return a.x*a.x + a.y*a.y; 486 | } 487 | 488 | 489 | ZMATHDEF Vector2_t norm_vec2(Vector2_t a) { 490 | float len = sqrt(a.x*a.x + a.y*a.y); 491 | if (len == 0.0) return Vector2(0, 0); 492 | return mul_vec2(a, 1.0f / len); 493 | } 494 | 495 | 496 | ZMATHDEF Vector2_t lerp_vec2(Vector2_t a, Vector2_t b, float t) { 497 | Vector2_t result; 498 | result.x = (1.0f - t) * a.x + t * b.x; 499 | result.y = (1.0f - t) * a.y + t * b.y; 500 | return result; 501 | } 502 | 503 | 504 | ZMATHDEF Vector3_t add_vec3(Vector3_t a, Vector3_t b) { 505 | return Vector3(a.x + b.x, a.y + b.y, a.z + b.z); 506 | } 507 | 508 | 509 | ZMATHDEF Vector3_t sub_vec3(Vector3_t a, Vector3_t b) { 510 | return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); 511 | } 512 | 513 | 514 | ZMATHDEF Vector3_t mul_vec3(Vector3_t v, float s) { 515 | return Vector3(v.x * s, v.y * s, v.z * s); 516 | } 517 | 518 | 519 | ZMATHDEF Vector3_t inv_vec3(Vector3_t v) { 520 | return Vector3(-v.x, -v.y, -v.z); 521 | } 522 | 523 | 524 | ZMATHDEF float dot_vec3(Vector3_t a, Vector3_t b) { 525 | return a.x * b.x + a.y * b.y + a.z * b.z; 526 | } 527 | 528 | 529 | ZMATHDEF float len_vec3(Vector3_t a) { 530 | return sqrt(a.x*a.x + a.y*a.y + a.z*a.z); 531 | } 532 | 533 | 534 | ZMATHDEF float len_sqr_vec3(Vector3_t a) { 535 | return a.x*a.x + a.y*a.y + a.z*a.z; 536 | } 537 | 538 | 539 | ZMATHDEF Vector3_t norm_vec3(Vector3_t a) { 540 | float len = sqrt(a.x*a.x + a.y*a.y + a.z*a.z); 541 | if (len == 0.0) return Vector3(0, 0, 0); 542 | return mul_vec3(a, 1.0f / len); 543 | } 544 | 545 | 546 | ZMATHDEF Vector3_t lerp_vec3(Vector3_t a, Vector3_t b, float t) { 547 | Vector3_t result; 548 | result.x = (1.0f - t) * a.x + t * b.x; 549 | result.y = (1.0f - t) * a.y + t * b.y; 550 | result.z = (1.0f - t) * a.z + t * b.z; 551 | return result; 552 | } 553 | 554 | 555 | ZMATHDEF Vector3_t cross_vec3(Vector3_t a, Vector3_t b) { 556 | return Vector3( 557 | a.y * b.z - a.z * b.y, 558 | a.z * b.x - a.x * b.z, 559 | a.x * b.y - a.y * b.x 560 | ); 561 | } 562 | 563 | 564 | ZMATHDEF Vector4_t add_vec4(Vector4_t a, Vector4_t b) { 565 | return Vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); 566 | } 567 | 568 | 569 | ZMATHDEF Vector4_t sub_vec4(Vector4_t a, Vector4_t b) { 570 | return Vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); 571 | } 572 | 573 | 574 | ZMATHDEF Vector4_t mul_vec4(Vector4_t v, float s) { 575 | return Vector4(v.x * s, v.y * s, v.z * s, v.w * s); 576 | } 577 | 578 | 579 | ZMATHDEF Vector4_t inv_vec4(Vector4_t v) { 580 | return Vector4(-v.x, -v.y, -v.z, -v.w); 581 | } 582 | 583 | 584 | ZMATHDEF float dot_vec4(Vector4_t a, Vector4_t b) { 585 | return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; 586 | } 587 | 588 | 589 | ZMATHDEF Matrix2x2_t mul_mat2x2(Matrix2x2_t a, Matrix2x2_t b) { 590 | Matrix2x2_t out; 591 | for (int32 i = 0; i < 2; ++i) { 592 | for (int32 j = 0; j < 2; ++j) { 593 | float f = 0.f; 594 | for (int32 k = 0; k < 2; ++k) { 595 | f += a.m[i*2+k] * b.m[k*2+j]; 596 | } 597 | out.m[i*2+j] = f; 598 | } 599 | } 600 | return out; 601 | } 602 | 603 | 604 | ZMATHDEF Matrix3x3_t mul_mat3x3(Matrix3x3_t a, Matrix3x3_t b) { 605 | Matrix3x3_t out; 606 | for (int32 i = 0; i < 3; ++i) { 607 | for (int32 j = 0; j < 3; ++j) { 608 | float f = 0.f; 609 | for (int32 k = 0; k < 3; ++k) { 610 | f += a.m[i*3+k] * b.m[k*3+j]; 611 | } 612 | out.m[i*3+j] = f; 613 | } 614 | } 615 | return out; 616 | } 617 | 618 | 619 | ZMATHDEF Matrix4x4_t mul_mat4x4(Matrix4x4_t a, Matrix4x4_t b) { 620 | Matrix4x4_t out; 621 | for (int32 i = 0; i < 4; ++i) { 622 | for (int32 j = 0; j < 4; ++j) { 623 | float f = 0.f; 624 | for (int32 k = 0; k < 4; ++k) { 625 | f += a.m[i*4+k] * b.m[k*4+j]; 626 | } 627 | out.m[i*4+j] = f; 628 | } 629 | } 630 | return out; 631 | } 632 | 633 | 634 | ZMATHDEF Vector3_t mul_mat3x3_vec3(Matrix3x3_t m, Vector3_t v) { 635 | Vector3_t out; 636 | for (int32 i = 0; i < 3; ++i) { 637 | float f = 0.f; 638 | for (int32 j = 0; j < 3; ++j) { 639 | f += m.m[j*3+i] * v.e[j]; 640 | } 641 | out.e[i] = f; 642 | } 643 | return out; 644 | } 645 | 646 | 647 | ZMATHDEF Vector4_t mul_mat4x4_vec4(Matrix4x4_t m, Vector4_t v) { 648 | Vector4_t out; 649 | for (int32 i = 0; i < 4; ++i) { 650 | float f = 0.f; 651 | for (int32 j = 0; j < 4; ++j) { 652 | f += m.m[j*4+i] * v.e[j]; 653 | } 654 | out.e[i] = f; 655 | } 656 | return out; 657 | } 658 | 659 | 660 | ZMATHDEF Matrix3x3_t trans_mat3x3(Matrix3x3_t m, Vector2_t v) { 661 | Matrix3x3_t trans = Matrix3x3(); 662 | trans.m[6] = v.x; 663 | trans.m[7] = v.y; 664 | return mul_mat3x3(m, trans); 665 | } 666 | 667 | 668 | ZMATHDEF Matrix3x3_t rot_mat3x3(Matrix3x3_t m, float rad) { 669 | Matrix3x3_t rot = Matrix3x3(); 670 | float c = cosf(rad); 671 | float s = sinf(rad); 672 | rot.m[0] = c; 673 | rot.m[1] = s; 674 | rot.m[3] = -s; 675 | rot.m[4] = c; 676 | return mul_mat3x3(m, rot); 677 | } 678 | 679 | 680 | ZMATHDEF Matrix3x3_t scale_mat3x3(Matrix3x3_t m, Vector2_t v) { 681 | Matrix3x3_t scale = Matrix3x3(); 682 | scale.m[0] = v.x; 683 | scale.m[4] = v.y; 684 | return mul_mat3x3(m, scale); 685 | } 686 | 687 | 688 | ZMATHDEF Matrix4x4_t trans_mat4x4(Matrix4x4_t m, Vector3_t v) { 689 | Matrix4x4_t trans = Matrix4x4(); 690 | trans.m[12] = v.x; 691 | trans.m[13] = v.y; 692 | trans.m[14] = v.z; 693 | return mul_mat4x4(m, trans); 694 | } 695 | 696 | 697 | ZMATHDEF Matrix4x4_t rotx_mat4x4(Matrix4x4_t m, float rad) { 698 | 699 | Matrix4x4_t rot = Matrix4x4(); 700 | float c = cosf(rad); 701 | float s = sinf(rad); 702 | 703 | rot.m[5] = c; 704 | rot.m[6] = s; 705 | rot.m[9] = -s; 706 | rot.m[10] = c; 707 | 708 | return mul_mat4x4(m, rot); 709 | } 710 | 711 | 712 | ZMATHDEF Matrix4x4_t roty_mat4x4(Matrix4x4_t m, float rad) { 713 | 714 | Matrix4x4_t rot = Matrix4x4(); 715 | float c = cosf(rad); 716 | float s = sinf(rad); 717 | 718 | rot.m[0] = c; 719 | rot.m[2] = -s; 720 | rot.m[8] = s; 721 | rot.m[10] = c; 722 | 723 | return mul_mat4x4(m, rot); 724 | } 725 | 726 | 727 | ZMATHDEF Matrix4x4_t rotz_mat4x4(Matrix4x4_t m, float rad) { 728 | 729 | Matrix4x4_t rot = Matrix4x4(); 730 | float c = cosf(rad); 731 | float s = sinf(rad); 732 | 733 | rot.m[0] = c; 734 | rot.m[1] = s; 735 | rot.m[4] = -s; 736 | rot.m[5] = c; 737 | 738 | return mul_mat4x4(m, rot); 739 | } 740 | 741 | 742 | ZMATHDEF Matrix4x4_t rotate_mat4x4(Matrix4x4_t m, Vector3_t rad) { 743 | m = rotx_mat4x4(m, rad.x); 744 | m = roty_mat4x4(m, rad.y); 745 | return rotz_mat4x4(m, rad.z); 746 | } 747 | 748 | 749 | ZMATHDEF Matrix4x4_t scale_mat4x4(Matrix4x4_t m, Vector3_t v) { 750 | Matrix4x4_t scale = Matrix4x4(); 751 | scale.m[0] = v.x; 752 | scale.m[5] = v.y; 753 | scale.m[10] = v.z; 754 | return mul_mat4x4(m, scale); 755 | } 756 | 757 | 758 | ZMATHDEF int inverse_mat4x4(Matrix4x4_t mat, Matrix4x4_t *out) { 759 | 760 | float *m = mat.m; 761 | Matrix4x4_t inv_mat; 762 | float *inv = inv_mat.m; 763 | float det; 764 | int32 i; 765 | 766 | inv[0] = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15] 767 | + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10]; 768 | inv[4] = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15] 769 | - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10]; 770 | inv[8] = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15] 771 | + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9]; 772 | inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14] 773 | - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9]; 774 | inv[1] = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15] 775 | - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10]; 776 | inv[5] = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15] 777 | + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10]; 778 | inv[9] = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15] 779 | - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9]; 780 | inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14] 781 | + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9]; 782 | inv[2] = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15] 783 | + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6]; 784 | inv[6] = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15] 785 | - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6]; 786 | inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15] 787 | + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5]; 788 | inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14] 789 | - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5]; 790 | inv[3] = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11] 791 | - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6]; 792 | inv[7] = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11] 793 | + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6]; 794 | inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11] 795 | - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5]; 796 | inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10] 797 | + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5]; 798 | 799 | det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12]; 800 | if (det == 0) 801 | return 0; 802 | 803 | det = 1.f / det; 804 | 805 | for (i = 0; i < 16; i++) 806 | out->m[i] = inv[i] * det; 807 | 808 | return 1; 809 | } 810 | 811 | 812 | ZMATHDEF Matrix4x4_t ortho_mat4x4(float b, float t, float l, float r, float n, float f) { 813 | 814 | Matrix4x4_t mat; 815 | 816 | mat.m[ 0] = 2.0f / (r - l); 817 | mat.m[ 1] = 0.0f; 818 | mat.m[ 2] = 0.0f; 819 | mat.m[ 3] = 0.0f; 820 | 821 | mat.m[ 4] = 0.0f; 822 | mat.m[ 5] = 2.0f / (t - b); 823 | mat.m[ 6] = 0.0f; 824 | mat.m[ 7] = 0.0f; 825 | 826 | mat.m[ 8] = 0.0f; 827 | mat.m[ 9] = 0.0f; 828 | mat.m[10] = -2.0f / (f - n); 829 | mat.m[11] = 0.0f; 830 | 831 | mat.m[12] = -(r + l) / (r - l); 832 | mat.m[13] = -(t + b) / (t - b); 833 | mat.m[14] = -(f + n) / (f - n); 834 | mat.m[15] = 1.0f; 835 | 836 | return mat; 837 | 838 | } 839 | 840 | 841 | ZMATHDEF Matrix4x4_t frustum_mat4x4(float b, float t, float l, float r, float n, float f) { 842 | 843 | Matrix4x4_t mat; 844 | 845 | mat.m[ 0] = 2.0f * n / (r - l); 846 | mat.m[ 1] = 0.0f; 847 | mat.m[ 2] = 0.0f; 848 | mat.m[ 3] = 0.0f; 849 | 850 | mat.m[ 4] = 0.0f; 851 | mat.m[ 5] = 2.0f * n / (t - b); 852 | mat.m[ 6] = 0.0f; 853 | mat.m[ 7] = 0.0f; 854 | 855 | mat.m[ 8] = (r + l) / (r - l); 856 | mat.m[ 9] = (t + b) / (t - b); 857 | mat.m[10] = -(f + n) / (f - n); 858 | mat.m[11] = -1.0f; 859 | 860 | mat.m[12] = 0.0f; 861 | mat.m[13] = 0.0f; 862 | mat.m[14] = -2.0f * f * n / (f - n); 863 | mat.m[15] = 0.0f; 864 | 865 | return mat; 866 | 867 | } 868 | 869 | 870 | ZMATHDEF Matrix4x4_t perspective_mat4x4(float fovy, float aspect, float n, float f) { 871 | 872 | float scale = tanf(fovy * 0.5f * ZM_DEG2RAD) * n; 873 | float r = aspect * scale; 874 | float l = -r; 875 | float t = scale; 876 | float b = -t; 877 | 878 | return frustum_mat4x4(b, t, l, r, n, f); 879 | 880 | } 881 | 882 | 883 | ZMATHDEF Matrix4x4_t look_at_mat4x4(Vector3_t eye, Vector3_t center, Vector3_t up) { 884 | 885 | Vector3_t forward = sub_vec3(center, eye); 886 | forward = norm_vec3(forward); 887 | 888 | Vector3_t side = cross_vec3(forward, up); 889 | side = norm_vec3(side); 890 | 891 | // recompute up = side x forward 892 | up = cross_vec3(side, forward); 893 | 894 | Matrix4x4_t m = Matrix4x4(); 895 | 896 | m.m[ 0] = side.x; 897 | m.m[ 1] = side.y; 898 | m.m[ 2] = side.z; 899 | 900 | m.m[ 4] = up.x; 901 | m.m[ 5] = up.y; 902 | m.m[ 6] = up.z; 903 | 904 | m.m[ 8] = -forward.x; 905 | m.m[ 9] = -forward.y; 906 | m.m[10] = -forward.z; 907 | 908 | return trans_mat4x4(m, inv_vec3(eye)); 909 | 910 | } 911 | 912 | 913 | ZMATHDEF void print_vec2(Vector2_t v) { 914 | zout("[%.4f, %.4f]\n", v.e[0], v.e[1]); 915 | } 916 | 917 | 918 | ZMATHDEF void print_vec3(Vector3_t v) { 919 | zout("[%.4f, %.4f, %.4f]\n", v.e[0], v.e[1], v.e[2]); 920 | } 921 | 922 | 923 | ZMATHDEF void print_vec4(Vector4_t v) { 924 | zout("[%.4f, %.4f, %.4f, %.4f]\n", v.e[0], v.e[1], v.e[2], v.e[2]); 925 | } 926 | 927 | 928 | ZMATHDEF void print_mat2x2(Matrix2x2_t m) { 929 | for (int32 i = 0; i < 2; ++i) { 930 | zout("[%.4f, %.4f]", m.m[i*2+0], m.m[i*2+1]); 931 | } 932 | zout(""); 933 | } 934 | 935 | 936 | ZMATHDEF void print_mat3x3(Matrix3x3_t m) { 937 | for (int32 i = 0; i < 3; ++i) { 938 | zout("[%.4f, %.4f, %.4f]", m.m[i*3+0], m.m[i*3+1], m.m[i*3+2]); 939 | } 940 | zout(""); 941 | } 942 | 943 | 944 | ZMATHDEF void print_mat4x4(Matrix4x4_t m) { 945 | for (int32 i = 0; i < 4; ++i) { 946 | zout("[%.4f, %.4f, %.4f, %.4f]", m.m[i*4+0], m.m[i*4+1], m.m[i*4+2], m.m[i*4+3]); 947 | } 948 | zout(""); 949 | } 950 | 951 | 952 | #endif // ZEN_MATH_IMPLEMENTATION 953 | 954 | 955 | /* 956 | zlib license: 957 | 958 | Copyright (c) 2017 Timothy Wright https://github.com/ZenToad 959 | 960 | This software is provided 'as-is', without any express or implied 961 | warranty. In no event will the authors be held liable for any damages 962 | arising from the use of this software. 963 | 964 | Permission is granted to anyone to use this software for any purpose, 965 | including commercial applications, and to alter it and redistribute it 966 | freely, subject to the following restrictions: 967 | 968 | 1. The origin of this software must not be misrepresented; you must not 969 | claim that you wrote the original software. If you use this software 970 | in a product, an acknowledgment in the product documentation would be 971 | appreciated but is not required. 972 | 2. Altered source versions must be plainly marked as such, and must not be 973 | misrepresented as being the original software. 974 | 3. This notice may not be removed or altered from any source distribution. 975 | */ 976 | -------------------------------------------------------------------------------- /zen_sdl.h: -------------------------------------------------------------------------------- 1 | /* zen_sdl.h - v0.42 - SDL wrapper -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_SDL_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_SDL_IMPLEMENTATION 11 | #include "zen_sdl.h" 12 | 13 | zlib license: 14 | Full license at bottom of file. 15 | 16 | */ 17 | 18 | #if !defined(__ZEN_SDL_H__) 19 | #define __ZEN_SDL_H__ 20 | 21 | 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | 27 | #if defined(ZEN_SDL_STATIC) 28 | #define ZSDL_DEF static 29 | #else 30 | #define ZSDL_DEF extern 31 | #endif 32 | 33 | 34 | #if defined(ZEN_LIB_DEV) 35 | #include "SDL.h" 36 | #include "glad/glad.h" 37 | #include "zen/zen_lib.h" 38 | #endif 39 | 40 | 41 | #define KEY_DOWN(SDL,KEY) SDL->keys[SDL_SCANCODE_##KEY] 42 | #define KEY_DOWN_ONCE(SDL,KEY) SDL->keys[SDL_SCANCODE_##KEY] == 1 43 | 44 | #define MOUSE_DOWN(SDL,B) SDL->mouse_button[(SDL_BUTTON_##B)-1] 45 | #define MOUSE_DOWN_ONCE(SDL,B) SDL->mouse_button[(SDL_BUTTON_##B)-1] == 1 46 | 47 | typedef struct zen_sdl { 48 | 49 | enum { 50 | ZEN_SDL_KEY_LAST = SDL_SCANCODE_APP2, 51 | SDL_MOUSE_COUNT = 3 52 | }; 53 | const char *window_title; 54 | 55 | int major_version; 56 | int minor_version; 57 | int window_cursor_mode; 58 | int window_background; 59 | int should_close; 60 | int got_quit_message; 61 | 62 | int window_width; 63 | int window_height; 64 | float window_widthf; 65 | float window_heightf; 66 | 67 | int display_width; 68 | int display_height; 69 | float display_widthf; 70 | float display_heightf; 71 | 72 | double current_time; 73 | double last_time; 74 | double delta_time; 75 | double total_time; 76 | int total_frames; 77 | 78 | float mouse_x; 79 | float mouse_y; 80 | float mouse_dx; 81 | float mouse_dy; 82 | float last_mouse_x; 83 | float last_mouse_y; 84 | float mouse_scroll; 85 | int mouse_button[SDL_MOUSE_COUNT]; 86 | 87 | SDL_Window* window; 88 | int keys[ZEN_SDL_KEY_LAST]; 89 | 90 | void (*window_event_callback)(zen_sdl *sdl, SDL_WindowEvent *e); 91 | void (*text_input_callback)(zen_sdl *sdl, SDL_TextInputEvent *e); 92 | void (*keyboard_callback)(zen_sdl *sdl, SDL_KeyboardEvent *e); 93 | void (*mouse_wheel_callback)(zen_sdl *sdl, SDL_MouseWheelEvent *e); 94 | void (*mouse_button_callback)(zen_sdl *sdl, SDL_MouseButtonEvent *e); 95 | void (*mouse_motion_callback)(zen_sdl *sdl, SDL_MouseMotionEvent *e); 96 | 97 | } zen_sdl; 98 | 99 | 100 | ZSDL_DEF zen_sdl *zen_sdl_create(const char *title, int width, int height, int major = 4, int minor = 5); 101 | ZSDL_DEF void zen_sdl_init(zen_sdl *sdl); 102 | ZSDL_DEF void zen_sdl_show_window(zen_sdl *sdl); 103 | ZSDL_DEF int zen_sdl_is_running(zen_sdl *sdl); 104 | ZSDL_DEF void zen_sdl_begin(zen_sdl *sdl); 105 | ZSDL_DEF void zen_sdl_end(zen_sdl *sdl); 106 | ZSDL_DEF void zen_sdl_quit(zen_sdl *sdl); 107 | ZSDL_DEF void zen_sdl_destroy(zen_sdl *sdl); 108 | 109 | ZSDL_DEF uint8 *zen_sdl_load_file(const char *path, isize *size = NULL); 110 | 111 | 112 | #if defined(__cplusplus) 113 | } 114 | #endif 115 | 116 | #endif // __ZEN_SDL_H__ 117 | 118 | 119 | //------------------------------------------ 120 | // 121 | // Implementation 122 | // 123 | //------------------------------------------ 124 | #if defined(ZEN_SDL_IMPLEMENTATION) 125 | 126 | 127 | void zen_sdl_default_window_event_callback(zen_sdl *sdl, SDL_WindowEvent* e) { 128 | //if () 129 | //glViewport(0, 0, e->data1, e->data2); 130 | } 131 | 132 | 133 | void zen_sdl_default_text_input_callback(zen_sdl *sdl, SDL_TextInputEvent *e) { 134 | // do nothing on default 135 | } 136 | 137 | void zen_sdl_default_keyboard_callback(zen_sdl *sdl, SDL_KeyboardEvent *e) { 138 | 139 | int key = e->keysym.scancode; 140 | if (e->type == SDL_KEYDOWN) { 141 | sdl->keys[key]++; 142 | } else if (e->type == SDL_KEYUP) { 143 | sdl->keys[key] = 0; 144 | } 145 | 146 | } 147 | 148 | void zen_sdl_default_mouse_wheel_callback(zen_sdl *sdl, SDL_MouseWheelEvent *e) { 149 | sdl->mouse_scroll += e->y; 150 | } 151 | 152 | void zen_sdl_default_mouse_button_callback(zen_sdl * sdl, SDL_MouseButtonEvent *e) { 153 | 154 | int button = (e->button - 1); 155 | if (button < 3) { 156 | if (e->type == SDL_MOUSEBUTTONDOWN) { 157 | sdl->mouse_button[button]++; 158 | } else if (e->type == SDL_MOUSEBUTTONUP) { 159 | sdl->mouse_button[button] = 0; 160 | } 161 | } 162 | 163 | } 164 | 165 | void zen_sdl_default_mouse_motion_callback(zen_sdl *sdl, SDL_MouseMotionEvent *e) { 166 | 167 | sdl->mouse_x = e->x; 168 | sdl->mouse_y = e->y; 169 | sdl->mouse_dx = e->xrel; 170 | sdl->mouse_dy = e->yrel; 171 | 172 | } 173 | 174 | static void zen_sdl_die(const char * message) { 175 | zout("%s: %s\n", message, SDL_GetError()); 176 | exit(2); 177 | } 178 | 179 | 180 | ZSDL_DEF zen_sdl *zen_sdl_create(const char *title, int width, int height, int major, int minor) { 181 | 182 | zen_sdl *sdl = ZEN_CALLOC(zen_sdl, 1); 183 | GB_ASSERT_NOT_NULL(sdl); 184 | 185 | sdl->window_title = title; 186 | sdl->major_version = major; 187 | sdl->minor_version = minor; 188 | sdl->window_width = width; 189 | sdl->window_height = height; 190 | sdl->window_background = 0xFF333333; 191 | 192 | return sdl; 193 | } 194 | 195 | 196 | ZSDL_DEF void zen_sdl_destroy(zen_sdl *sdl) { 197 | free(sdl); 198 | } 199 | 200 | 201 | void zen_sdl_init(zen_sdl *sdl) { 202 | 203 | // Initialize SDL 204 | if (SDL_Init(SDL_INIT_EVERYTHING) < 0) 205 | zen_sdl_die("Couldn't initialize SDL"); 206 | 207 | atexit (SDL_Quit); 208 | SDL_GL_LoadLibrary(NULL); // Default OpenGL is fine. 209 | 210 | SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); 211 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, sdl->major_version); 212 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, sdl->minor_version); 213 | 214 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 215 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 216 | 217 | // Create the window 218 | sdl->window = SDL_CreateWindow( sdl->window_title, 219 | SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 220 | sdl->window_width, sdl->window_height, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL 221 | ); 222 | if (sdl->window == NULL) 223 | zen_sdl_die("Couldn't set video mode"); 224 | 225 | SDL_GLContext maincontext = SDL_GL_CreateContext(sdl->window); 226 | if (maincontext == NULL) 227 | zen_sdl_die("Failed to create OpenGL context"); 228 | 229 | // Check OpenGL properties 230 | printf("OpenGL loaded\n"); 231 | gladLoadGLLoader(SDL_GL_GetProcAddress); 232 | printf("Vendor: %s\n", glGetString(GL_VENDOR)); 233 | printf("Renderer: %s\n", glGetString(GL_RENDERER)); 234 | printf("Version: %s\n", glGetString(GL_VERSION)); 235 | 236 | GB_ASSERT(GLVersion.major >= sdl->major_version); 237 | GB_ASSERT(GLVersion.minor >= sdl->minor_version); 238 | 239 | // Use v-sync 240 | SDL_GL_SetSwapInterval(1); 241 | 242 | sdl->should_close = 0; 243 | 244 | 245 | // callbacks 246 | if (sdl->window_event_callback == NULL) { 247 | sdl->window_event_callback = zen_sdl_default_window_event_callback; 248 | } 249 | 250 | if (sdl->text_input_callback == NULL) { 251 | sdl->text_input_callback = zen_sdl_default_text_input_callback; 252 | } 253 | 254 | if (sdl->keyboard_callback == NULL) { 255 | sdl->keyboard_callback = zen_sdl_default_keyboard_callback; 256 | } 257 | 258 | if (sdl->mouse_wheel_callback == NULL) { 259 | sdl->mouse_wheel_callback = zen_sdl_default_mouse_wheel_callback; 260 | } 261 | 262 | if (sdl->mouse_button_callback == NULL) { 263 | sdl->mouse_button_callback = zen_sdl_default_mouse_button_callback; 264 | } 265 | 266 | if (sdl->mouse_motion_callback == NULL) { 267 | sdl->mouse_motion_callback = zen_sdl_default_mouse_motion_callback; 268 | } 269 | 270 | for (int i = 0; i < sdl->ZEN_SDL_KEY_LAST; ++i) { 271 | sdl->keys[i] = 0; 272 | } 273 | 274 | sdl->current_time = cast(double)SDL_GetPerformanceCounter() / cast(double)SDL_GetPerformanceFrequency(); 275 | sdl->last_time = sdl->current_time; 276 | sdl->delta_time = 0.0; 277 | sdl->total_time = 0; 278 | sdl->total_frames = 0; 279 | 280 | SDL_StartTextInput(); 281 | 282 | } 283 | 284 | 285 | ZSDL_DEF void zen_sdl_show_window(zen_sdl *sdl) { 286 | SDL_ShowWindow(sdl->window); 287 | } 288 | 289 | 290 | ZSDL_DEF int zen_sdl_is_running(zen_sdl *sdl) { 291 | return !(sdl->should_close || sdl->got_quit_message); 292 | } 293 | 294 | 295 | ZSDL_DEF void zen_sdl_begin(zen_sdl *sdl) { 296 | 297 | // do time here 298 | sdl->last_time = sdl->current_time; 299 | sdl->current_time = cast(double)SDL_GetPerformanceCounter() / cast(double)SDL_GetPerformanceFrequency(); 300 | sdl->delta_time = sdl->current_time - sdl->last_time; 301 | sdl->total_time += sdl->delta_time; 302 | sdl->total_frames++; 303 | 304 | 305 | sdl->last_mouse_x = sdl->mouse_x; 306 | sdl->last_mouse_y = sdl->mouse_y; 307 | 308 | SDL_Event event; 309 | while (SDL_PollEvent(&event)) { 310 | switch(event.type) { 311 | case SDL_QUIT: { 312 | sdl->got_quit_message = 1; 313 | } break; 314 | case SDL_KEYDOWN: 315 | case SDL_KEYUP: { 316 | sdl->keyboard_callback(sdl, &event.key); 317 | } break; 318 | case SDL_TEXTINPUT: { 319 | sdl->text_input_callback(sdl, &event.text); 320 | } break; 321 | case SDL_MOUSEWHEEL: { 322 | sdl->mouse_wheel_callback(sdl, &event.wheel); 323 | } break; 324 | case SDL_MOUSEBUTTONDOWN: 325 | case SDL_MOUSEBUTTONUP: { 326 | sdl->mouse_button_callback(sdl, &event.button); 327 | } break; 328 | case SDL_MOUSEMOTION: { 329 | sdl->mouse_motion_callback(sdl, &event.motion); 330 | } break; 331 | case SDL_WINDOWEVENT: { 332 | sdl->window_event_callback(sdl, &event.window); 333 | } break; 334 | } 335 | } 336 | 337 | 338 | int r = sdl->window_background & 0xFF; 339 | int g = (sdl->window_background >> 8) & 0xFF; 340 | int b = (sdl->window_background >> 16) & 0xFF; 341 | int a = (sdl->window_background >> 24) & 0xFF; 342 | glClearColor(r / 255.99f, g / 255.99f, b / 255.99f, a / 255.99f); 343 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 344 | 345 | 346 | } 347 | 348 | 349 | ZSDL_DEF void zen_sdl_end(zen_sdl *sdl) { 350 | 351 | for (int i = 0; i < sdl->ZEN_SDL_KEY_LAST; ++i) { 352 | if (sdl->keys[i]) { 353 | sdl->keys[i]++; 354 | } 355 | } 356 | 357 | for (int i = 0; i < sdl->SDL_MOUSE_COUNT; ++i) { 358 | if (sdl->mouse_button[i]) 359 | sdl->mouse_button[i]++; 360 | } 361 | 362 | sdl->mouse_scroll = 0; 363 | SDL_GL_SwapWindow(sdl->window); 364 | 365 | } 366 | 367 | 368 | ZSDL_DEF void zen_sdl_quit(zen_sdl *sdl) { 369 | int ms = (int)(1.0e3 * sdl->total_time / sdl->total_frames); 370 | zout("\n%d (ms)\n", ms); 371 | SDL_Quit(); 372 | } 373 | 374 | 375 | ZSDL_DEF uint8 *zen_sdl_load_file(const char *path, isize *size) { 376 | 377 | SDL_RWops *rw = SDL_RWFromFile(path, "rb"); 378 | if (rw == NULL) { 379 | zout("%s: %s", path, SDL_GetError()); 380 | return NULL; 381 | } 382 | 383 | int64 res_size = SDL_RWsize(rw); 384 | uint8 *mem = ZEN_CALLOC(uint8, res_size + 1); 385 | GB_ASSERT_NOT_NULL(mem); 386 | 387 | int64 nb_read_total = 0; 388 | int64 nb_read = 1; 389 | uint8 *buf = mem; 390 | 391 | while (nb_read_total < res_size && nb_read != 0) { 392 | nb_read = SDL_RWread(rw, buf, 1, (res_size - nb_read_total)); 393 | nb_read_total += nb_read; 394 | buf += nb_read; 395 | } 396 | 397 | SDL_RWclose(rw); 398 | if (nb_read_total != res_size) { 399 | free(mem); 400 | return NULL; 401 | } 402 | 403 | mem[nb_read_total] = '\0'; 404 | if (size) *size = res_size; 405 | return mem; 406 | 407 | } 408 | 409 | #endif 410 | /* 411 | zlib license: 412 | 413 | Copyright (c) 2017 Timothy Wright https://github.com/ZenToad 414 | 415 | This software is provided 'as-is', without any express or implied 416 | warranty. In no event will the authors be held liable for any damages 417 | arising from the use of this software. 418 | 419 | Permission is granted to anyone to use this software for any purpose, 420 | including commercial applications, and to alter it and redistribute it 421 | freely, subject to the following restrictions: 422 | 423 | 1. The origin of this software must not be misrepresented; you must not 424 | claim that you wrote the original software. If you use this software 425 | in a product, an acknowledgment in the product documentation would be 426 | appreciated but is not required. 427 | 2. Altered source versions must be plainly marked as such, and must not be 428 | misrepresented as being the original software. 429 | 3. This notice may not be removed or altered from any source distribution. 430 | */ 431 | -------------------------------------------------------------------------------- /zen_sdl_audio.h: -------------------------------------------------------------------------------- 1 | /* zen_sdl_audio.h - v0.42 - SDL Audio wrapper -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_SDL_AUDIO_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_SDL_AUDIO_IMPLEMENTATION 11 | #include "zen_sdl_audio.h" 12 | 13 | zlib license: 14 | Full license at bottom of file. 15 | 16 | */ 17 | 18 | 19 | #if !defined(__ZEN_SDL_AUDIO_H__) 20 | #define __ZEN_SDL_AUDIO_H__ 21 | 22 | 23 | #if defined(ZEN_LIB_DEV) 24 | #include "zen/zen_lib.h" 25 | #endif 26 | 27 | 28 | #define ZEN_AUDIO_MAX_CHANNELS 16 29 | #define ZEN_AUDIO_MAX_SOUNDS 16 30 | #define ZEN_AUDIO_SYSTEM_CHANNELS 2 31 | #define ZEN_AUDIO_SYSTEM_FREQ 44100 32 | #define ZEN_AUDIO_SYSTEM_SAMPLES 1024 33 | 34 | 35 | #if defined(__cplusplus) 36 | extern "C" { 37 | #endif 38 | 39 | 40 | #if defined(ZEN_AUDIO_STATIC) 41 | #define ZAUDIODEF static 42 | #else 43 | #define ZAUDIODEF extern 44 | #endif 45 | 46 | 47 | struct ZenAudioSystem; 48 | 49 | 50 | ZAUDIODEF ZenAudioSystem *zen_audio_create(); 51 | ZAUDIODEF void zen_audio_init(ZenAudioSystem *audio); 52 | ZAUDIODEF void zen_audio_turn_on(ZenAudioSystem *audio); 53 | ZAUDIODEF void zen_audio_turn_off(ZenAudioSystem *audio); 54 | ZAUDIODEF void zen_audio_shutdown(ZenAudioSystem *audio); 55 | ZAUDIODEF void zen_audio_destroy(ZenAudioSystem *audio); 56 | 57 | 58 | ZAUDIODEF float dB_to_volume(float dB); 59 | ZAUDIODEF float volume_to_dB(float volume); 60 | 61 | 62 | ZAUDIODEF void zen_audio_load_sound(ZenAudioSystem *audio, const char *sound_name, bool looping = false); 63 | ZAUDIODEF void zen_audio_unload_sound(ZenAudioSystem *audio, const char *sound_name); 64 | ZAUDIODEF uint32 zen_audio_play_sound(ZenAudioSystem *audio, const char *sound_name, float volumedB = 0.0f); 65 | ZAUDIODEF void zen_audio_stop_channel(ZenAudioSystem *audio, uint32 channel_id); 66 | ZAUDIODEF void zen_audio_stop_all_channels(ZenAudioSystem *audio); 67 | ZAUDIODEF void zen_audio_set_channel_volume(ZenAudioSystem *engine, uint32 channel_id, float volumedB); 68 | ZAUDIODEF bool zen_audio_is_playing(ZenAudioSystem *engine, uint32 channel_id); 69 | 70 | 71 | #if defined(__cplusplus) 72 | } 73 | #endif 74 | 75 | 76 | #endif // __ZEN_SDL_AUDIO_H__ 77 | 78 | 79 | //------------------------------------------ 80 | // 81 | // 82 | // Implementation 83 | // 84 | //------------------------------------------ 85 | #if defined(ZEN_SDL_AUDIO_IMPLEMENTATION) || defined(ZEN_LIB_DEV) 86 | 87 | 88 | #if defined(ZEN_LIB_DEV) 89 | #include 90 | #include "SDL.h" 91 | 92 | #include 93 | #endif 94 | 95 | typedef struct zen_sound { 96 | 97 | int is_loaded; 98 | const char *name; 99 | float *audio_data; 100 | int sample_count; 101 | bool looping; 102 | 103 | } zen_sound; 104 | 105 | 106 | enum FADE_TYPE { 107 | NOT_FADING = 0, 108 | FADE_IN, 109 | FADE_OUT 110 | }; 111 | 112 | 113 | typedef struct zen_channel { 114 | 115 | uint32 id; 116 | zen_sound *sound; 117 | 118 | float position; 119 | float advance; 120 | 121 | int is_playing; 122 | uint32 expire; 123 | int loop_count; 124 | 125 | 126 | FADE_TYPE fade_type; 127 | uint32 ticks_fade; 128 | uint32 fade_length; 129 | float fade_volume_reset; 130 | float fade_volume; 131 | 132 | 133 | float left_pan; 134 | float right_pan; 135 | 136 | float gain; 137 | 138 | } zen_channel; 139 | 140 | 141 | typedef struct ZenAudioSystem { 142 | 143 | SDL_AudioSpec mixer; 144 | SDL_AudioDeviceID id; 145 | 146 | uint32 next_channel_id; 147 | float gain; 148 | 149 | zen_sound sounds[ZEN_AUDIO_MAX_SOUNDS]; 150 | zen_channel channels[ZEN_AUDIO_MAX_CHANNELS]; 151 | 152 | 153 | } ZenAudioSystem; 154 | 155 | 156 | static void zen_audio_reset_channel(zen_channel *channel) { 157 | 158 | memset(channel, 0, zen_sizeof(zen_channel)); 159 | 160 | channel->fade_type = NOT_FADING; 161 | channel->right_pan = 1.0f; 162 | channel->left_pan = 1.0f; 163 | channel->gain = 1.0f; 164 | channel->advance = 1.0f; 165 | 166 | } 167 | 168 | 169 | static void mix_audio_stream(ZenAudioSystem *audio, zen_channel *c, float **out_buffer, int output_sample_count) { 170 | 171 | 172 | float *out = *out_buffer; 173 | float *in = c->sound->audio_data; 174 | int output_sample = 0; // buffer pos 175 | int channels = 2; 176 | 177 | 178 | // calc gain here just once 179 | float left_gain = audio->gain * c->gain * c->left_pan; 180 | float right_gain = audio->gain * c->gain * c->right_pan; 181 | 182 | while (output_sample < output_sample_count) { 183 | 184 | int index = c->position * channels; 185 | float left = in[index] * left_gain; 186 | float right = in[index + 1] * right_gain; 187 | 188 | *out++ += left; 189 | *out++ += right; 190 | 191 | output_sample += 1; 192 | c->position += c->advance; // allows for pitch change 193 | 194 | 195 | if (c->position >= c->sound->sample_count) { 196 | if (c->loop_count < 0) { 197 | //infinite loop 198 | c->position = 0; 199 | } else if (c->loop_count > 0) { 200 | c->loop_count--; 201 | c->position = 0; 202 | } else { 203 | c->is_playing = 0; 204 | return; 205 | } 206 | } 207 | } 208 | 209 | } 210 | 211 | 212 | static void mix_channel(ZenAudioSystem *audio, zen_channel *c, uint32 sdl_ticks, float **out_buffer, int out_sample_count) { 213 | 214 | 215 | if (c->expire > 0 && c->expire < sdl_ticks) { 216 | c->is_playing = 0; 217 | return; 218 | } 219 | 220 | 221 | if (c->fade_type != NOT_FADING) { 222 | uint32 ticks = sdl_ticks - c->ticks_fade; 223 | if (ticks < c->fade_length) { 224 | c->gain = c->fade_volume_reset; 225 | if (c->fade_type == FADE_OUT) { 226 | c->is_playing = 0; 227 | return; 228 | } 229 | c->fade_type = NOT_FADING; 230 | } else if (c->fade_type == FADE_OUT) { 231 | c->gain = c->fade_volume * (c->fade_length - ticks); 232 | } else { // FADE_IN 233 | c->gain = (c->fade_volume * ticks) / c->fade_length; 234 | } 235 | } 236 | 237 | 238 | mix_audio_stream(audio, c, out_buffer, out_sample_count); 239 | 240 | 241 | } 242 | 243 | 244 | static void zen_audio_callback(void *userdata, uint8 *output, int len) { 245 | 246 | 247 | GB_ASSERT_NOT_NULL(userdata); 248 | ZenAudioSystem *audio = (ZenAudioSystem *)userdata; 249 | SDL_memset(output, audio->mixer.silence, len); 250 | 251 | 252 | float *output_buffer = (float *)output; 253 | uint32 ticks = SDL_GetTicks(); 254 | int sample_count = len / (zen_sizeof(float) * audio->mixer.channels); 255 | 256 | 257 | for (int i = 0; i < ZEN_AUDIO_MAX_CHANNELS; ++i) { 258 | if (audio->channels[i].is_playing) { 259 | mix_channel(audio, &audio->channels[i], ticks, &output_buffer, sample_count); 260 | } 261 | } 262 | 263 | 264 | } 265 | 266 | 267 | ZAUDIODEF ZenAudioSystem *zen_audio_create() { 268 | 269 | ZenAudioSystem *audio = (ZenAudioSystem *)SDL_malloc(zen_sizeof(ZenAudioSystem)); 270 | GB_ASSERT_NOT_NULL(audio); 271 | return audio; 272 | 273 | } 274 | 275 | 276 | ZAUDIODEF void zen_audio_init(ZenAudioSystem *audio) { 277 | 278 | audio->gain = 1.0f; 279 | for (int i = 0; i < ZEN_AUDIO_MAX_CHANNELS; ++i) { 280 | SDL_zero(audio->channels[i]); 281 | zen_audio_reset_channel(&audio->channels[i]); 282 | } 283 | 284 | 285 | SDL_AudioSpec want; 286 | want.channels = ZEN_AUDIO_SYSTEM_CHANNELS; 287 | want.freq = ZEN_AUDIO_SYSTEM_FREQ; 288 | want.format = AUDIO_F32; 289 | want.callback = zen_audio_callback; 290 | want.userdata = audio; 291 | want.samples = ZEN_AUDIO_SYSTEM_SAMPLES; 292 | 293 | audio->id = SDL_OpenAudioDevice(NULL, 0, &want, &audio->mixer, 0); 294 | 295 | GB_ASSERT_MSG(audio->id, "Couldn't open audio device"); 296 | GB_ASSERT_MSG(want.format == audio->mixer.format, "Couldn't get correct format"); 297 | 298 | } 299 | 300 | 301 | ZAUDIODEF void zen_audio_turn_on(ZenAudioSystem *audio) { 302 | SDL_PauseAudioDevice(audio->id, 0); 303 | } 304 | 305 | 306 | ZAUDIODEF void zen_audio_turn_off(ZenAudioSystem *audio) { 307 | SDL_PauseAudioDevice(audio->id, 1); 308 | } 309 | 310 | 311 | static zen_sound *zen_audio_get_sound(ZenAudioSystem *audio, const char *name) { 312 | 313 | for (int i = 0; i < ZEN_AUDIO_MAX_SOUNDS; ++i) { 314 | zen_sound *sound = &audio->sounds[i]; 315 | if (sound->is_loaded && (strcmp(sound->name, name) == 0)) { 316 | return sound; 317 | } 318 | } 319 | 320 | return NULL; 321 | 322 | } 323 | 324 | 325 | ZAUDIODEF void zen_audio_unload_sound(ZenAudioSystem *audio, const char *sound_name) { 326 | 327 | zen_sound *sound = zen_audio_get_sound(audio, sound_name); 328 | if (sound == NULL) 329 | return; // not loaded 330 | 331 | 332 | // stop any channels playing the sound 333 | for (int i = 0; i < ZEN_AUDIO_MAX_CHANNELS; ++i) { 334 | zen_channel *channel = &audio->channels[i]; 335 | if (channel->is_playing && channel->sound == sound) { 336 | SDL_LockAudioDevice(audio->id); 337 | channel->is_playing = 0; 338 | SDL_UnlockAudioDevice(audio->id); 339 | } 340 | } 341 | 342 | sound->is_loaded = 0; 343 | SDL_free(sound->audio_data); 344 | sound->audio_data = NULL; 345 | 346 | } 347 | 348 | 349 | ZAUDIODEF void zen_audio_shutdown(ZenAudioSystem *audio) { 350 | 351 | if (audio == NULL) 352 | return; 353 | 354 | SDL_PauseAudioDevice(audio->id, 1); 355 | 356 | for (int i = 0; i < ZEN_AUDIO_MAX_SOUNDS; ++i) { 357 | audio->sounds[i].is_loaded = 0; 358 | SDL_free(audio->sounds[0].audio_data); 359 | audio->sounds[i].audio_data = NULL; 360 | } 361 | 362 | SDL_CloseAudioDevice(audio->id); 363 | 364 | } 365 | 366 | 367 | ZAUDIODEF void zen_audio_destroy(ZenAudioSystem *audio) { 368 | SDL_free(audio); 369 | } 370 | 371 | 372 | ZAUDIODEF float dB_to_volume(float dB) { 373 | return powf(10.0f, 0.05f * dB); 374 | } 375 | 376 | 377 | ZAUDIODEF float volume_to_dB(float volume) { 378 | return 20.0f * log10f(volume); 379 | } 380 | 381 | 382 | 383 | static void zen_audio_add_sound(ZenAudioSystem *audio, const char *name, float *audio_buf, int sample_count, bool looping) { 384 | 385 | for (int i = 0; i < ZEN_AUDIO_MAX_SOUNDS; ++i) { 386 | if (!audio->sounds[i].is_loaded) { 387 | audio->sounds[i].is_loaded = 1; 388 | audio->sounds[i].name = name; 389 | audio->sounds[i].audio_data = audio_buf; 390 | audio->sounds[i].sample_count = sample_count; 391 | audio->sounds[i].looping = looping; 392 | return; 393 | } 394 | } 395 | 396 | } 397 | 398 | 399 | static void zen_audio_add_channel(ZenAudioSystem *audio, int channel_id, zen_sound *sound, float volumedB) { 400 | 401 | for (int i = 0; i < ZEN_AUDIO_MAX_CHANNELS; ++i) { 402 | zen_channel *channel = &audio->channels[i]; 403 | if (!channel->is_playing) { 404 | SDL_LockAudioDevice(audio->id); 405 | 406 | zen_audio_reset_channel(channel); 407 | channel->sound = sound; 408 | channel->id = channel_id; 409 | channel->loop_count = sound->looping ? -1 : 0; 410 | channel->is_playing = 1; 411 | channel->gain = dB_to_volume(volumedB); 412 | SDL_UnlockAudioDevice(audio->id); 413 | return; 414 | } 415 | } 416 | 417 | } 418 | 419 | 420 | ZAUDIODEF uint32 zen_audio_play_sound(ZenAudioSystem *audio, const char *sound_name, float volumedB) { 421 | 422 | uint32 channel_id = audio->next_channel_id++; 423 | zen_sound *sound = zen_audio_get_sound(audio, sound_name); 424 | if (sound == NULL) { 425 | zen_audio_load_sound(audio, sound_name); 426 | sound = zen_audio_get_sound(audio, sound_name); 427 | if (sound == NULL) { 428 | return channel_id; 429 | } 430 | } 431 | 432 | zen_audio_add_channel(audio, channel_id, sound, volumedB); 433 | 434 | return channel_id; 435 | 436 | } 437 | 438 | 439 | static zen_channel *zen_audio_find_channel(ZenAudioSystem *audio, uint32 channel_id) { 440 | 441 | for (int i = 0; i < ZEN_AUDIO_MAX_CHANNELS; ++i) { 442 | zen_channel *channel = &audio->channels[i]; 443 | if (channel->id == channel_id) { 444 | return channel; 445 | } 446 | } 447 | 448 | return NULL; 449 | 450 | } 451 | 452 | 453 | ZAUDIODEF void zen_audio_stop_channel(ZenAudioSystem *audio, uint32 channel_id) { 454 | 455 | zen_channel *channel = zen_audio_find_channel(audio, channel_id); 456 | if (channel) { 457 | SDL_LockAudioDevice(audio->id); 458 | channel->is_playing = 0; 459 | SDL_UnlockAudioDevice(audio->id); 460 | } 461 | 462 | } 463 | 464 | 465 | ZAUDIODEF void zen_audio_stop_all_channels(ZenAudioSystem *audio) { 466 | 467 | SDL_LockAudioDevice(audio->id); 468 | for (int i = 0; i < ZEN_AUDIO_MAX_CHANNELS; ++i) { 469 | audio->channels[i].is_playing = 0; 470 | } 471 | SDL_UnlockAudioDevice(audio->id); 472 | 473 | } 474 | 475 | 476 | ZAUDIODEF void zen_audio_set_channel_volume(ZenAudioSystem *audio, uint32 channel_id, float volumedB) { 477 | 478 | zen_channel *channel = zen_audio_find_channel(audio, channel_id); 479 | if (channel) { 480 | SDL_LockAudioDevice(audio->id); 481 | channel->gain = dB_to_volume(volumedB); 482 | SDL_UnlockAudioDevice(audio->id); 483 | } 484 | 485 | } 486 | 487 | 488 | ZAUDIODEF bool zen_audio_is_playing(ZenAudioSystem *audio, uint32 channel_id) { 489 | 490 | bool is_playing = false; 491 | zen_channel *channel = zen_audio_find_channel(audio, channel_id); 492 | if (channel) { 493 | SDL_LockAudioDevice(audio->id); 494 | is_playing = channel->is_playing; 495 | SDL_UnlockAudioDevice(audio->id); 496 | } 497 | return is_playing; 498 | 499 | } 500 | 501 | 502 | ZAUDIODEF void zen_audio_load_sound(ZenAudioSystem *audio, const char *sound_name, bool looping) { 503 | 504 | zen_sound *sound = zen_audio_get_sound(audio, sound_name); 505 | if (sound) { 506 | return; // already loaded 507 | } 508 | 509 | 510 | SDL_AudioSpec wav_spec; 511 | uint8 *audio_buf = 0; 512 | uint32 audio_len = 0; 513 | GB_ASSERT_MSG(SDL_LoadWAV(sound_name, &wav_spec, &audio_buf, &audio_len), 514 | "Error loading %s: %s", sound_name, SDL_GetError()); 515 | 516 | 517 | SDL_AudioCVT cvt; 518 | SDL_zero(cvt); 519 | 520 | SDL_AudioSpec *mix = &audio->mixer; 521 | int result = SDL_BuildAudioCVT(&cvt, 522 | wav_spec.format, wav_spec.channels, wav_spec.freq, 523 | mix->format, mix->channels, mix->freq); 524 | 525 | GB_ASSERT_MSG(result >= 0, "Problem building wav file conversion"); 526 | 527 | cvt.len = audio_len; 528 | cvt.buf = (uint8 *)SDL_malloc(cvt.len * cvt.len_mult); 529 | SDL_memcpy(cvt.buf, audio_buf, audio_len); 530 | 531 | if (SDL_ConvertAudio(&cvt) < 0) { 532 | GB_PANIC("Audio conversion error: %s", SDL_GetError()); 533 | } 534 | 535 | float *audio_data = (float *)cvt.buf; 536 | int sample_count = cvt.len_cvt / (zen_sizeof(float) * mix->channels); 537 | zen_audio_add_sound(audio, sound_name, audio_data, sample_count, looping); 538 | 539 | 540 | SDL_FreeWAV(audio_buf); 541 | 542 | 543 | } 544 | 545 | 546 | 547 | #endif // ZEN_SDL_AUDIO_IMPLEMENTATION 548 | 549 | /* 550 | zlib license: 551 | 552 | Copyright (c) 2017 Timothy Wright https://github.com/ZenToad 553 | 554 | This software is provided 'as-is', without any express or implied 555 | warranty. In no event will the authors be held liable for any damages 556 | arising from the use of this software. 557 | 558 | Permission is granted to anyone to use this software for any purpose, 559 | including commercial applications, and to alter it and redistribute it 560 | freely, subject to the following restrictions: 561 | 562 | 1. The origin of this software must not be misrepresented; you must not 563 | claim that you wrote the original software. If you use this software 564 | in a product, an acknowledgment in the product documentation would be 565 | appreciated but is not required. 566 | 2. Altered source versions must be plainly marked as such, and must not be 567 | misrepresented as being the original software. 568 | 3. This notice may not be removed or altered from any source distribution. 569 | */ 570 | -------------------------------------------------------------------------------- /zen_sdl_imgui.h: -------------------------------------------------------------------------------- 1 | /* zen_sdl_imgui.h - v0.42 - SDL imgui implementation -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define ZEN_IMGUI_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define ZEN_SDL_IMGUI_IMPLEMENTATION 11 | #include "zen_sdl_imgui.h" 12 | 13 | Full license at bottom of file. 14 | 15 | */ 16 | 17 | #ifndef _ZEN_SDL_IMGUI_H__ 18 | #define _ZEN_SDL_IMGUI_H__ 19 | 20 | #ifdef ZEN_SDL_IMGUI_STATIC 21 | #define ZSDLGUIDEF static 22 | #else 23 | #define ZSDLGUIDEF extern 24 | #endif 25 | 26 | #if defined(ZEN_LIB_DEV) 27 | #include "zen_sdl.h" 28 | #endif 29 | 30 | ZSDLGUIDEF void zen_imgui_init(zen_sdl *sdl); 31 | ZSDLGUIDEF void zen_imgui_set_default_callbacks(zen_sdl *sdl); 32 | ZSDLGUIDEF void zen_imgui_begin(zen_sdl *sdl); 33 | ZSDLGUIDEF void zen_imgui_end(); 34 | ZSDLGUIDEF void zen_imgui_quit(); 35 | 36 | 37 | ZSDLGUIDEF void sdl_imgui_mouse_button_callback(zen_sdl * sdl, SDL_MouseButtonEvent *e); 38 | ZSDLGUIDEF void sdl_imgui_mouse_wheel_callback(zen_sdl *sdl, SDL_MouseWheelEvent *e); 39 | ZSDLGUIDEF void sdl_imgui_keyboard_callback(zen_sdl *sdl, SDL_KeyboardEvent *e); 40 | ZSDLGUIDEF void sdl_imgui_text_input_callback(zen_sdl *sdl, SDL_TextInputEvent *e); 41 | 42 | #endif //_ZEN_SDL_IMGUI_H__ 43 | 44 | 45 | 46 | 47 | #if defined(ZEN_SDL_IMGUI_IMPLEMENTATION) || defined(ZEN_LIB_DEV) 48 | 49 | #if defined(ZEN_LIB_DEV) 50 | #include "zen_gl.h" 51 | #include "zen_sdl.h" 52 | #include "imgui.h" 53 | #endif 54 | 55 | #include "SDL_syswm.h" 56 | 57 | typedef struct ZenSdlImguiState_t { 58 | 59 | GLuint vbo; 60 | GLuint ebo; 61 | GLuint vao; 62 | 63 | ZGLShader zen_imgui_shader; 64 | 65 | } ZenSdlImguiState_t; 66 | 67 | static ZenSdlImguiState_t __zen_imgui_state = {0}; 68 | 69 | static ImFont* __zen_imgui_default_font; 70 | static ImFont* __zen_imgui_custion_font; 71 | 72 | 73 | ZSDLGUIDEF void zen_imgui_begin(zen_sdl *sdl) { 74 | 75 | ImGuiIO& io = ImGui::GetIO(); 76 | 77 | // Setup display size (every frame to accommodate for window resizing) 78 | int w = sdl->window_width; 79 | int h = sdl->window_height; 80 | int display_w = sdl->window_width; 81 | int display_h = sdl->window_height; 82 | 83 | io.DisplaySize = ImVec2((float)w, (float)h); 84 | io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); 85 | 86 | io.DeltaTime = sdl->delta_time; 87 | 88 | if (SDL_GetWindowFlags(sdl->window) & SDL_WINDOW_MOUSE_FOCUS) { 89 | io.MousePos = ImVec2(sdl->mouse_x, sdl->mouse_y); 90 | } else { 91 | io.MousePos = ImVec2(-1,-1); 92 | } 93 | 94 | // Hide OS mouse cursor if ImGui is drawing it 95 | SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1); 96 | 97 | // Start the frame 98 | ImGui::NewFrame(); 99 | 100 | } 101 | 102 | ZSDLGUIDEF void zen_imgui_end() { 103 | ImGui::Render(); 104 | } 105 | 106 | static const char* zen_imgui_default_get_clipboard_callback(void* user_data) { 107 | return SDL_GetClipboardText(); 108 | } 109 | 110 | static void zen_imgui_default_set_clipboard_callback(void* user_data, const char* text) { 111 | SDL_SetClipboardText(text); 112 | } 113 | 114 | ZSDLGUIDEF void zen_imgui_quit() { 115 | ImGui::Shutdown(); 116 | } 117 | 118 | static void zen_imgui_create_font() { 119 | // Build texture atlas 120 | ImGuiIO& io = ImGui::GetIO(); 121 | unsigned char* pixels; 122 | int width, height; 123 | // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely 124 | // to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept 125 | // than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. 126 | __zen_imgui_default_font = io.Fonts->AddFontDefault(); 127 | //@TODO: this shouldn't be hard-coded here 128 | //__zen_imgui_custion_font = io.Fonts->AddFontFromFileTTF("res/PressStart2P/PressStart2P.ttf", 16); 129 | 130 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 131 | 132 | // Upload texture to graphics system 133 | GLint last_texture; 134 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 135 | glActiveTexture(GL_TEXTURE0 + 1); 136 | GLuint font_texture; 137 | glGenTextures(1, &font_texture); 138 | glBindTexture(GL_TEXTURE_2D, font_texture); 139 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 140 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 141 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 142 | 143 | // Store our identifier 144 | io.Fonts->TexID = (void *)(intptr_t)font_texture; 145 | 146 | // Restore state 147 | glBindTexture(GL_TEXTURE_2D, last_texture); 148 | 149 | } 150 | 151 | // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) 152 | // If text or lines are blurry when integrating ImGui in your engine: 153 | // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) 154 | ZSDLGUIDEF void zen_imgui_render(ImDrawData* draw_data) { 155 | 156 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) 157 | ImGuiIO& io = ImGui::GetIO(); 158 | int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); 159 | int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); 160 | if (fb_width == 0 || fb_height == 0) 161 | return; 162 | draw_data->ScaleClipRects(io.DisplayFramebufferScale); 163 | 164 | // Backup GL state 165 | GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); 166 | GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 167 | GLint last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, &last_active_texture); 168 | GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 169 | GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer); 170 | GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 171 | GLint last_blend_src; glGetIntegerv(GL_BLEND_SRC, &last_blend_src); 172 | GLint last_blend_dst; glGetIntegerv(GL_BLEND_DST, &last_blend_dst); 173 | GLint last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); 174 | GLint last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); 175 | GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); 176 | GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); 177 | GLboolean last_enable_blend = glIsEnabled(GL_BLEND); 178 | GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); 179 | GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); 180 | GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); 181 | 182 | // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled 183 | glEnable(GL_BLEND); 184 | glBlendEquation(GL_FUNC_ADD); 185 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 186 | glDisable(GL_CULL_FACE); 187 | glDisable(GL_DEPTH_TEST); 188 | glEnable(GL_SCISSOR_TEST); 189 | glActiveTexture(GL_TEXTURE0 + 1); 190 | 191 | // Setup viewport, orthographic projection matrix 192 | glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); 193 | const float ortho_projection[4][4] = 194 | { 195 | { 2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f }, 196 | { 0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f }, 197 | { 0.0f, 0.0f, -1.0f, 0.0f }, 198 | {-1.0f, 1.0f, 0.0f, 1.0f }, 199 | }; 200 | 201 | ZGLShader *shader = &__zen_imgui_state.zen_imgui_shader; 202 | ZenSdlImguiState_t *state = &__zen_imgui_state; 203 | glUseProgram(shader->program); 204 | zgl_set_uniform_int(shader, "Texture", 1); 205 | zgl_set_uniform_mat4(shader, "ProjMtx", &ortho_projection[0][0]); 206 | 207 | glBindVertexArray(state->vao); 208 | 209 | for (int n = 0; n < draw_data->CmdListsCount; n++) 210 | { 211 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 212 | const ImDrawIdx* idx_buffer_offset = 0; 213 | 214 | glBindBuffer(GL_ARRAY_BUFFER, state->vbo); 215 | glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); 216 | 217 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state->ebo); 218 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); 219 | 220 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 221 | { 222 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 223 | if (pcmd->UserCallback) 224 | { 225 | pcmd->UserCallback(cmd_list, pcmd); 226 | } 227 | else 228 | { 229 | glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); 230 | glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); 231 | glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); 232 | } 233 | idx_buffer_offset += pcmd->ElemCount; 234 | } 235 | } 236 | 237 | // Restore modified GL state 238 | glUseProgram(last_program); 239 | glActiveTexture(last_active_texture); 240 | glBindTexture(GL_TEXTURE_2D, last_texture); 241 | glBindVertexArray(last_vertex_array); 242 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 243 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer); 244 | glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); 245 | glBlendFunc(last_blend_src, last_blend_dst); 246 | if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); 247 | if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); 248 | if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); 249 | if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); 250 | glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); 251 | glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); 252 | } 253 | 254 | static void zen_imgui_setup_shaders() { 255 | 256 | GLint last_texture, last_array_buffer, last_vertex_array; 257 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 258 | glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 259 | glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 260 | 261 | const GLchar *vertex_shader = 262 | "#version 420 core\n" 263 | "uniform mat4 ProjMtx;\n" 264 | "in vec2 Position;\n" 265 | "in vec2 UV;\n" 266 | "in vec4 Color;\n" 267 | "out vec2 Frag_UV;\n" 268 | "out vec4 Frag_Color;\n" 269 | "void main()\n" 270 | "{\n" 271 | " Frag_UV = UV;\n" 272 | " Frag_Color = Color;\n" 273 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" 274 | "}\n"; 275 | 276 | const GLchar* fragment_shader = 277 | "#version 420 core\n" 278 | "uniform sampler2D Texture;\n" 279 | "in vec2 Frag_UV;\n" 280 | "in vec4 Frag_Color;\n" 281 | "out vec4 Out_Color;\n" 282 | "void main()\n" 283 | "{\n" 284 | " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" 285 | "}\n"; 286 | 287 | b32 result = zgl_create_shader(&__zen_imgui_state.zen_imgui_shader, vertex_shader, fragment_shader); 288 | 289 | if (!result) { 290 | exit(EXIT_FAILURE); 291 | } 292 | 293 | ZGLShader *shader = &__zen_imgui_state.zen_imgui_shader; 294 | glUseProgram(shader->program); 295 | 296 | glGenVertexArrays(1, &__zen_imgui_state.vao); 297 | glBindVertexArray(__zen_imgui_state.vao); 298 | __zen_imgui_state.vbo = zgl_make_vbo(NULL, 0, GL_STREAM_DRAW); 299 | __zen_imgui_state.ebo = zgl_make_ebo(NULL, 0, GL_STREAM_DRAW); 300 | zgl_bind_vbo(__zen_imgui_state.vbo); 301 | 302 | int32 loc = glGetAttribLocation(shader->program, "Position"); 303 | assert(loc != -1 && "Position"); 304 | zgl_vert_ptr_aa(loc, 2, ImDrawVert, pos); 305 | loc = glGetAttribLocation(shader->program, "UV"); 306 | assert(loc != -1 && "UV"); 307 | zgl_vert_ptr_aa(loc, 2, ImDrawVert, uv); 308 | loc = glGetAttribLocation(shader->program, "Color"); 309 | assert(loc != -1 && "Color"); 310 | zgl_vert_ptr_aa_u8n(loc, 4, ImDrawVert, col); 311 | 312 | zen_imgui_create_font(); 313 | 314 | // Restore modified GL state 315 | glBindTexture(GL_TEXTURE_2D, last_texture); 316 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 317 | glBindVertexArray(last_vertex_array); 318 | 319 | } 320 | 321 | ZSDLGUIDEF void zen_imgui_init(zen_sdl *sdl) { 322 | 323 | ImGuiIO& io = ImGui::GetIO(); 324 | io.KeyMap[ImGuiKey_Tab] = SDLK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. 325 | io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; 326 | io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; 327 | io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP; 328 | io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN; 329 | io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP; 330 | io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN; 331 | io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME; 332 | io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END; 333 | io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE; 334 | io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE; 335 | io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN; 336 | io.KeyMap[ImGuiKey_Escape] = SDLK_ESCAPE; 337 | io.KeyMap[ImGuiKey_A] = SDLK_a; 338 | io.KeyMap[ImGuiKey_C] = SDLK_c; 339 | io.KeyMap[ImGuiKey_V] = SDLK_v; 340 | io.KeyMap[ImGuiKey_X] = SDLK_x; 341 | io.KeyMap[ImGuiKey_Y] = SDLK_y; 342 | io.KeyMap[ImGuiKey_Z] = SDLK_z; 343 | 344 | io.RenderDrawListsFn = zen_imgui_render; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. 345 | io.SetClipboardTextFn = zen_imgui_default_set_clipboard_callback; 346 | io.GetClipboardTextFn = zen_imgui_default_get_clipboard_callback; 347 | io.ClipboardUserData = NULL; 348 | 349 | #ifdef _WIN32 350 | SDL_SysWMinfo wmInfo; 351 | SDL_VERSION(&wmInfo.version); 352 | SDL_GetWindowWMInfo(sdl->window, &wmInfo); 353 | io.ImeWindowHandle = wmInfo.info.win.window; 354 | #endif 355 | 356 | zen_imgui_setup_shaders(); 357 | } 358 | 359 | 360 | ZSDLGUIDEF void sdl_imgui_text_input_callback(zen_sdl *sdl, SDL_TextInputEvent *e) { 361 | 362 | ImGuiIO& io = ImGui::GetIO(); 363 | if (io.WantTextInput) { 364 | io.AddInputCharactersUTF8(e->text); 365 | } 366 | 367 | } 368 | 369 | 370 | ZSDLGUIDEF void sdl_imgui_keyboard_callback(zen_sdl *sdl, SDL_KeyboardEvent *e) { 371 | 372 | int key = e->keysym.sym & ~SDLK_SCANCODE_MASK; 373 | ImGuiIO& io = ImGui::GetIO(); 374 | if (io.WantCaptureKeyboard) { 375 | io.KeysDown[key] = (e->type == SDL_KEYDOWN); 376 | io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); 377 | io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); 378 | io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); 379 | io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); 380 | } else { 381 | io.KeysDown[key] = false; 382 | io.KeyShift = false; 383 | io.KeyCtrl = false; 384 | io.KeyAlt = false; 385 | io.KeySuper = false; 386 | if (e->type == SDL_KEYDOWN) { 387 | sdl->keys[e->keysym.scancode]++; 388 | } else if (e->type == SDL_KEYUP) { 389 | sdl->keys[e->keysym.scancode] = 0; 390 | } 391 | } 392 | 393 | } 394 | 395 | 396 | ZSDLGUIDEF void sdl_imgui_mouse_wheel_callback(zen_sdl *sdl, SDL_MouseWheelEvent *e) { 397 | ImGuiIO& io = ImGui::GetIO(); 398 | if (io.WantCaptureMouse) { 399 | io.MouseWheel = e->y; 400 | sdl->mouse_scroll = 0; 401 | } else { 402 | io.MouseWheel = 0; 403 | sdl->mouse_scroll += e->y; 404 | } 405 | } 406 | 407 | 408 | ZSDLGUIDEF void sdl_imgui_mouse_button_callback(zen_sdl * sdl, SDL_MouseButtonEvent *e) { 409 | 410 | int button = (e->button - 1); 411 | if (button < 3) { 412 | ImGuiIO& io = ImGui::GetIO(); 413 | if (io.WantCaptureMouse) { 414 | io.MouseDown[button] = e->type == SDL_MOUSEBUTTONDOWN ? true : false; 415 | } else { 416 | io.MouseDown[button] = false; 417 | if (e->type == SDL_MOUSEBUTTONDOWN) { 418 | sdl->mouse_button[button]++; 419 | } else if (e->type == SDL_MOUSEBUTTONUP) { 420 | sdl->mouse_button[button] = 0; 421 | } 422 | } 423 | } 424 | 425 | } 426 | 427 | 428 | ZSDLGUIDEF void zen_imgui_set_default_callbacks(zen_sdl *sdl) { 429 | 430 | sdl->text_input_callback = sdl_imgui_text_input_callback; 431 | sdl->keyboard_callback = sdl_imgui_keyboard_callback; 432 | sdl->mouse_wheel_callback = sdl_imgui_mouse_wheel_callback; 433 | sdl->mouse_button_callback = sdl_imgui_mouse_button_callback; 434 | 435 | } 436 | 437 | 438 | #endif //ZEN_IMGUI_IMPLEMENTATION 439 | 440 | // Public Domain (www.unlicense.org) 441 | // This is free and unencumbered software released into the public domain. 442 | // Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 443 | // software, either in source code form or as a compiled binary, for any purpose, 444 | // commercial or non-commercial, and by any means. 445 | // In jurisdictions that recognize copyright laws, the author or authors of this 446 | // software dedicate any and all copyright interest in the software to the public 447 | // domain. We make this dedication for the benefit of the public at large and to 448 | // the detriment of our heirs and successors. We intend this dedication to be an 449 | // overt act of relinquishment in perpetuity of all present and future rights to 450 | // this software under copyright law. 451 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 452 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 453 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 454 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 455 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 456 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 457 | -------------------------------------------------------------------------------- /zen_squtil.h: -------------------------------------------------------------------------------- 1 | /* zen_squtil.h - v0.42 - Squirrel Lang wrapper -https://github.com/ZenToad/zen 2 | 3 | Do this: 4 | #define SQUTIL_IMPLEMENTATION 5 | before you include this file in *one* C or C++ file to create the implementation. 6 | // i.e. it should look like this: 7 | #include ... 8 | #include ... 9 | #include ... 10 | #define SQUTIL_IMPLEMENTATION 11 | #include "zen_squtil.h" 12 | 13 | zlib license: 14 | Full license at bottom of file. 15 | 16 | */ 17 | 18 | #ifndef SQUTIL_H 19 | #define SQUTIL_H 20 | 21 | #ifdef SQUTIL_STATIC 22 | #define SQUTIL_DEF static 23 | #else 24 | #define SQUTIL_DEF extern 25 | #endif 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | 33 | // definitions go here... 34 | SQUTIL_DEF SQRESULT set_table_int(HSQUIRRELVM v, const char* table, const char* key, SQInteger value); 35 | SQUTIL_DEF SQRESULT get_string(HSQUIRRELVM v, const char* name, const SQChar** string); 36 | SQUTIL_DEF SQRESULT get_int( HSQUIRRELVM v, const char* name, SQInteger* integer ); 37 | SQUTIL_DEF SQRESULT get_var( HSQUIRRELVM v, const char* name ); 38 | SQUTIL_DEF void printfunc( HSQUIRRELVM v, const SQChar *s, ... ); 39 | SQUTIL_DEF void errorfunc( HSQUIRRELVM v, const SQChar *s, ... ); 40 | SQUTIL_DEF void print_stack( HSQUIRRELVM v ); 41 | SQUTIL_DEF void register_global_func( HSQUIRRELVM v, SQFUNCTION f, const char *fname ); 42 | SQUTIL_DEF SQRESULT register_global_variable( HSQUIRRELVM v, const char *fname, SQInteger value ); 43 | SQUTIL_DEF void call_func( HSQUIRRELVM v, const char* func ); 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | #endif // end SQUTIL_H 50 | 51 | #ifdef SQUTIL_IMPLEMENTATION 52 | 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | SQUTIL_DEF SQRESULT register_global_variable( HSQUIRRELVM v, const char *name, SQInteger value ) { 59 | sq_pushstring( v, _SC( name ), -1 ); 60 | sq_pushinteger( v, value ); 61 | return sq_newslot( v, -3, SQFalse ); 62 | } 63 | 64 | SQUTIL_DEF SQRESULT set_table_int(HSQUIRRELVM v, const char* table, const char* key, SQInteger value) { 65 | SQInteger top = sq_gettop(v); //saves the stack size before the call 66 | sq_pushroottable(v); 67 | SQRESULT result = get_var(v, table); 68 | if( SQ_SUCCEEDED(result)) { 69 | sq_pushstring(v, _SC(key), -1); 70 | sq_pushinteger(v, value); 71 | result = sq_newslot(v, -3, SQFalse); 72 | } 73 | sq_settop(v, top); 74 | return result; 75 | } 76 | 77 | SQUTIL_DEF SQRESULT get_string( HSQUIRRELVM v, const char* name, const SQChar** string ) { 78 | SQInteger top = sq_gettop(v); //saves the stack size before the call 79 | sq_pushstring( v, _SC( name ), -1 ); 80 | SQRESULT result = sq_get( v, -2 ); 81 | if( SQ_SUCCEEDED( result ) ) { 82 | sq_getstring( v, -1, string ); 83 | } 84 | sq_settop( v, top ); 85 | return result; 86 | } 87 | 88 | SQUTIL_DEF SQRESULT get_int( HSQUIRRELVM v, const char* name, SQInteger* integer ) { 89 | SQInteger top = sq_gettop(v); //saves the stack size before the call 90 | sq_pushstring( v, _SC( name ), -1 ); 91 | SQRESULT result = sq_get( v, -2 ); 92 | if( SQ_SUCCEEDED( result ) ) { 93 | sq_getinteger( v, -1, integer ); 94 | } 95 | sq_settop( v, top ); 96 | return result; 97 | } 98 | 99 | SQUTIL_DEF void register_global_func( HSQUIRRELVM v, SQFUNCTION f, const char *fname ) { 100 | sq_pushstring(v,fname,-1); 101 | sq_newclosure(v,f,0); //create a new function 102 | sq_newslot(v,-3,SQFalse); 103 | } 104 | 105 | SQUTIL_DEF SQRESULT get_var( HSQUIRRELVM v, const char* name ) { 106 | sq_pushstring( v, _SC(name), -1 ); 107 | return sq_get( v, -2 ); 108 | } 109 | 110 | SQUTIL_DEF void printfunc( HSQUIRRELVM v, const SQChar *s, ... ) { 111 | va_list vl; 112 | va_start(vl, s); 113 | vfprintf(stdout, s, vl); 114 | va_end(vl); 115 | } 116 | 117 | SQUTIL_DEF void errorfunc( HSQUIRRELVM v, const SQChar *s, ... ) { 118 | va_list vl; 119 | va_start(vl, s); 120 | vfprintf(stderr, s, vl); 121 | va_end(vl); 122 | } 123 | 124 | SQUTIL_DEF void call_func( HSQUIRRELVM v, const char* func ) { 125 | if (SQ_SUCCEEDED(get_var(v, func))) { 126 | sq_pushroottable(v); 127 | sq_call(v, 1, SQFalse, SQTrue);// leave closure on stack 128 | sq_pop(v, 1); // pop Coroutine and process 129 | } 130 | } 131 | 132 | static void print_integer( HSQUIRRELVM v, SQInteger top, SQInteger index ) { 133 | SQInteger value; 134 | sq_getinteger( v, index, &value ); 135 | printf("[%lld,%lld] %lld\n", top, index, value); 136 | } 137 | 138 | static void print_float( HSQUIRRELVM v, SQInteger top, SQInteger index ) { 139 | SQFloat value; 140 | sq_getfloat( v, index, &value ); 141 | printf("[%lld,%lld] %f\n", top, index, value); 142 | } 143 | 144 | static void print_string( HSQUIRRELVM v, SQInteger top, SQInteger index ) { 145 | const SQChar* value; 146 | sq_getstring( v, index, &value ); 147 | printf("[%lld,%lld] %s\n", top, index, value); 148 | } 149 | 150 | static void print_bool( HSQUIRRELVM v, SQInteger top, SQInteger index ) { 151 | SQBool value; 152 | sq_getbool( v, index, &value ); 153 | printf("[%lld,%lld] %lld\n", top, index, value); 154 | } 155 | 156 | static void print_stack_value( HSQUIRRELVM v, SQObjectType type, SQInteger top, SQInteger index ) { 157 | switch( type ) { 158 | case OT_NULL: printf("[%lld,%lld] NULL\n", (index - top - 1), index); break; 159 | case OT_INTEGER: print_integer( v, (index - top - 1), index ); break; 160 | case OT_FLOAT: print_float( v, (index - top - 1), index ); break; 161 | case OT_STRING: print_string( v, (index - top - 1), index ); break; 162 | case OT_TABLE: printf("[%lld,%lld] TABLE\n", (index - top - 1), index); break; 163 | case OT_ARRAY: printf("[%lld,%lld] ARRAY\n", (index - top - 1), index); break; 164 | case OT_USERDATA: printf("[%lld,%lld] USERDATA\n", (index - top - 1), index); break; 165 | case OT_CLOSURE: printf("[%lld,%lld] CLOSURE\n", (index - top - 1), index); break; 166 | case OT_NATIVECLOSURE: printf("[%lld,%lld] NATIVECLOSURE\n", (index - top - 1), index); break; 167 | case OT_GENERATOR: printf("[%lld,%lld] GENERATOR\n", (index - top - 1), index); break; 168 | case OT_USERPOINTER: printf("[%lld,%lld] USERPOINTER\n", (index - top - 1), index); break; 169 | case OT_BOOL: print_bool( v, top, (index - top - 1) ); break; 170 | case OT_INSTANCE: printf("[%lld,%lld] INSTANCE\n", (index - top - 1), index); break; 171 | case OT_CLASS: printf("[%lld,%lld] CLASS\n", (index - top - 1), index); break; 172 | case OT_WEAKREF: printf("[%lld,%lld] WEAKREF\n", (index - top - 1), index); break; 173 | default: printf("[%lld,%lld] UNKNOWN\n", (index - top - 1), index); break; 174 | } 175 | } 176 | 177 | SQUTIL_DEF void print_stack(HSQUIRRELVM v) { 178 | 179 | SQInteger top = sq_gettop( v ); 180 | printf("TOP: %lld\n", top); 181 | for( int i = top; i > 0; --i ) { 182 | SQObjectType type = sq_gettype( v, i ); 183 | print_stack_value( v, type, top, i ); 184 | } 185 | printf("\n"); 186 | } 187 | 188 | #endif // end SQUTIL_IMPLEMENTATION 189 | 190 | /* 191 | zlib license: 192 | 193 | Copyright (c) 2017 Timothy Wright https://github.com/ZenToad 194 | 195 | This software is provided 'as-is', without any express or implied 196 | warranty. In no event will the authors be held liable for any damages 197 | arising from the use of this software. 198 | 199 | Permission is granted to anyone to use this software for any purpose, 200 | including commercial applications, and to alter it and redistribute it 201 | freely, subject to the following restrictions: 202 | 203 | 1. The origin of this software must not be misrepresented; you must not 204 | claim that you wrote the original software. If you use this software 205 | in a product, an acknowledgment in the product documentation would be 206 | appreciated but is not required. 207 | 2. Altered source versions must be plainly marked as such, and must not be 208 | misrepresented as being the original software. 209 | 3. This notice may not be removed or altered from any source distribution. 210 | */ 211 | --------------------------------------------------------------------------------