Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up| /* Goxel 3D voxels editor | |
| * | |
| * copyright (c) 2015 Guillaume Chereau <guillaume@noctua-software.com> | |
| * | |
| * Goxel is free software: you can redistribute it and/or modify it under the | |
| * terms of the GNU General Public License as published by the Free Software | |
| * Foundation, either version 3 of the License, or (at your option) any later | |
| * version. | |
| * Goxel is distributed in the hope that it will be useful, but WITHOUT ANY | |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
| * details. | |
| * You should have received a copy of the GNU General Public License along with | |
| * goxel. If not, see <http://www.gnu.org/licenses/>. | |
| */ | |
| // File: goxel.h | |
| #ifndef GOXEL_H | |
| #define GOXEL_H | |
| #ifndef _GNU_SOURCE | |
| # define _GNU_SOURCE | |
| #endif | |
| #ifndef NOMINMAX | |
| # define NOMINMAX | |
| #endif | |
| #include "action.h" | |
| #include "assets.h" | |
| #include "block_def.h" | |
| #include "camera.h" | |
| #include "gesture.h" | |
| #include "gesture3d.h" | |
| #include "gui.h" | |
| #include "image.h" | |
| #include "inputs.h" | |
| #include "layer.h" | |
| #include "log.h" | |
| #include "luagoxel.h" | |
| #include "material.h" | |
| #include "mesh.h" | |
| #include "mesh_utils.h" | |
| #include "meta.h" | |
| #include "model3d.h" | |
| #include "noc_file_dialog.h" | |
| #include "palette.h" | |
| #include "pathtracer.h" | |
| #include "render.h" | |
| #include "shape.h" | |
| #include "system.h" | |
| #include "theme.h" | |
| #include "tools.h" | |
| #include "utarray.h" | |
| #include "uthash.h" | |
| #include "utlist.h" | |
| #include "utils/box.h" | |
| #include "utils/cache.h" | |
| #include "utils/gl.h" | |
| #include "utils/img.h" | |
| #include "utils/plane.h" | |
| #include "utils/sound.h" | |
| #include "utils/texture.h" | |
| #include "utils/vec.h" | |
| #include <float.h> | |
| #include <stdarg.h> | |
| #include <stdbool.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #define GOXEL_VERSION_STR "0.10.6" | |
| #ifndef GOXEL_DEFAULT_THEME | |
| # define GOXEL_DEFAULT_THEME "original" | |
| #endif | |
| // #### Set the DEBUG macro #### | |
| #ifndef DEBUG | |
| # if !defined(NDEBUG) | |
| # define DEBUG 1 | |
| # else | |
| # define DEBUG 0 | |
| # endif | |
| #endif | |
| #if !DEBUG && !defined(NDEBUG) | |
| # define NDEBUG | |
| #endif | |
| #include <assert.h> | |
| // ############################# | |
| // #### DEFINED macro ########## | |
| // DEFINE(NAME) returns 1 if NAME is defined to 1, 0 otherwise. | |
| #define DEFINED(macro) DEFINED_(macro) | |
| #define macrotest_1 , | |
| #define DEFINED_(value) DEFINED__(macrotest_##value) | |
| #define DEFINED__(comma) DEFINED___(comma 1, 0) | |
| #define DEFINED___(_, v, ...) v | |
| // ############################# | |
| // CHECK is similar to an assert, but the condition is tested even in release | |
| // mode. | |
| #if DEBUG | |
| #define CHECK(c) assert(c) | |
| #else | |
| #define CHECK(c) do { \ | |
| if (!(c)) { \ | |
| LOG_E("Error %s %s %d", __func__, __FILE__, __LINE__); \ | |
| exit(-1); \ | |
| } \ | |
| } while (0) | |
| #endif | |
| // I redefine asprintf so that if the function fails, we just crash the | |
| // application. I don't see how we can recover from an asprintf fails | |
| // anyway. | |
| #define asprintf(...) CHECK(asprintf(__VA_ARGS__) != -1) | |
| #define vasprintf(...) CHECK(vasprintf(__VA_ARGS__) != -1) | |
| // ############################# | |
| #ifdef __EMSCRIPTEN__ | |
| # include <emscripten.h> | |
| # define KEEPALIVE EMSCRIPTEN_KEEPALIVE | |
| #else | |
| # define KEEPALIVE | |
| #endif | |
| // ####### Section: Utils ################################################ | |
| // Some useful inline functions / macros | |
| /* | |
| * Macro: ARRAY_SIZE | |
| * Return the number of elements in an array | |
| */ | |
| #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | |
| /* | |
| * Macro: SWAP | |
| * Swap two variables | |
| */ | |
| #define SWAP(x0, x) do {typeof(x0) tmp = x0; x0 = x; x = tmp;} while (0) | |
| /* | |
| * Macro: USER_PASS | |
| * Used to pass values to callback 'void *user' arguments. | |
| * | |
| * For a function with the following declaration: f(void *user), we can pass | |
| * several arguments packed in an array like that: | |
| * | |
| * int x, y; | |
| * f(USER_PASS(&x, &y)); | |
| */ | |
| #define USER_PASS(...) ((const void*[]){__VA_ARGS__}) | |
| /* | |
| * Macro: USER_GET | |
| * Used to unpack values passed to a callback with USER_PASS: | |
| * | |
| * void f(void *user) | |
| * { | |
| * char *arg1 = USER_GET(user, 0); | |
| * int arg2 = *((int*)USER_GET(user, 1)); | |
| * } | |
| */ | |
| #define USER_GET(var, n) (((void**)var)[n]) | |
| /* Define: DR2D | |
| * Convertion ratio from radian to degree. */ | |
| #define DR2D (180 / M_PI) | |
| /* Define: DR2D | |
| * Convertion ratio from degree to radian. */ | |
| #define DD2R (M_PI / 180) | |
| /* Define: KB | |
| * 1024 */ | |
| #define KB 1024 | |
| /* Define: MB | |
| * 1024^2 */ | |
| #define MB (1024 * KB) | |
| /* Define: GB | |
| * 1024^3 */ | |
| #define GB (1024 * MB) | |
| /* | |
| * Macro: min | |
| * Safe min function. | |
| */ | |
| #define min(a, b) ({ \ | |
| __typeof__ (a) _a = (a); \ | |
| __typeof__ (b) _b = (b); \ | |
| _a < _b ? _a : _b; \ | |
| }) | |
| /* | |
| * Macro: max | |
| * Safe max function. | |
| */ | |
| #define max(a, b) ({ \ | |
| __typeof__ (a) _a = (a); \ | |
| __typeof__ (b) _b = (b); \ | |
| _a > _b ? _a : _b; \ | |
| }) | |
| /* | |
| * Macro: max3 | |
| * Safe max function, return the max of three values. | |
| */ | |
| #define max3(x, y, z) (max((x), max((y), (z)))) | |
| /* | |
| * Macro: min3 | |
| * Safe max function, return the max of three values. | |
| */ | |
| #define min3(x, y, z) (min((x), min((y), (z)))) | |
| /* | |
| * Macro: clamp | |
| * Clamp a value. | |
| */ | |
| #define clamp(x, a, b) (min(max(x, a), b)) | |
| /* | |
| * Macro: cmp | |
| * Compare two values. | |
| * | |
| * Return: | |
| * +1 if a > b, -1 if a < b, 0 if a == b. | |
| */ | |
| #define cmp(a, b) ({ \ | |
| __typeof__ (a) _a = (a); \ | |
| __typeof__ (b) _b = (b); \ | |
| (_a > _b) ? +1 : (_a < _b) ? -1 : 0; \ | |
| }) | |
| /* Function: smoothstep | |
| * Perform Hermite interpolation between two values. | |
| * | |
| * This is similar to the smoothstep function in OpenGL shader language. | |
| * | |
| * Parameters: | |
| * edge0 - Lower edge of the Hermite function. | |
| * edge1 - Upper edge of the Hermite function. | |
| * x - Source value for interpolation. | |
| */ | |
| static inline float smoothstep(float edge0, float edge1, float x) | |
| { | |
| x = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); | |
| return x * x * (3.0f - 2.0f * x); | |
| } | |
| /* | |
| * Function: mix | |
| * Linear blend of x and y. | |
| * | |
| * Similar to GLES mix function. | |
| */ | |
| static inline float mix(float x, float y, float t) | |
| { | |
| return (1.0 - t) * x + t * y; | |
| } | |
| /* Function: set_flag | |
| * Set some int bits to 0 or 1. | |
| * | |
| * Parameters: | |
| * x - The int value to change. | |
| * flag - Bitmask of the bits we want to set. | |
| * v - Value to set. | |
| */ | |
| static inline void set_flag(int *x, int flag, bool v) | |
| { | |
| v ? (*x |= flag) : (*x &= ~flag); | |
| } | |
| /* | |
| * Extra texture creation function from a path, that can also be an asset. | |
| */ | |
| texture_t *texture_new_image(const char *path, int flags); | |
| /* | |
| * Function: read_file | |
| * Read a file from disk. | |
| * | |
| * Return: | |
| * A newly allocated buffer containing the file data. | |
| */ | |
| char *read_file(const char *path, int *size); | |
| /* | |
| * Function: unix_to_dtf | |
| * Get gregorian date from unix time. | |
| * | |
| * Parameters: | |
| * t - Unix time. | |
| * iy - Output year. | |
| * im - Output month (1 - 12). | |
| * id - Output day (1 - 31). | |
| * h - Output hour. | |
| * m - Output minute. | |
| * s - Output seconds. | |
| */ | |
| int unix_to_dtf(double t, int *iy, int *im, int *id, int *h, int *m, int *s); | |
| /* | |
| * Function: utf_16_to_8 | |
| * Convert a string encoded in utf_16 to utf_8. | |
| * | |
| * Parameters: | |
| * in16 - Input string in utf 16 encoding. | |
| * out8 - Output buffer that receive the utf8 string. | |
| * size8 - Size of the output buffer. | |
| */ | |
| int utf_16_to_8(const wchar_t *in16, char *out8, size_t size8); | |
| /* | |
| * Function: str_endswith | |
| * Return whether a string ends with an other one. | |
| */ | |
| bool str_endswith(const char *str, const char *end); | |
| /* | |
| * Function: str_startswith | |
| * Return whether a string starts with an other one. | |
| */ | |
| bool str_startswith(const char *s1, const char *s2); | |
| /* | |
| * Function: unproject | |
| * Convert from screen coordinate to world coordinates. | |
| * | |
| * Similar to gluUnproject. | |
| * | |
| * Parameters: | |
| * win - Windows coordinates to be mapped. | |
| * model - Modelview matrix. | |
| * proj - Projection matrix. | |
| * viewport - Viewport rect (x, y, w, h). | |
| * out - Output of the computed object coordinates. | |
| */ | |
| void unproject(const float win[3], const float model[4][4], | |
| const float proj[4][4], const float viewport[4], | |
| float out[3]); | |
| // #### Dialogs ################ | |
| enum { | |
| DIALOG_FLAG_SAVE = 1 << 0, | |
| DIALOG_FLAG_OPEN = 1 << 1, | |
| DIALOG_FLAG_DIR = 1 << 2, | |
| }; | |
| // All the icons positions inside icon.png (as Y*8 + X + 1). | |
| enum { | |
| ICON_NULL = 0, | |
| ICON_TOOL_BRUSH = 1, | |
| ICON_TOOL_PICK = 2, | |
| ICON_TOOL_SHAPE = 3, | |
| ICON_TOOL_PLANE = 4, | |
| ICON_TOOL_LASER = 5, | |
| ICON_TOOL_MOVE = 6, | |
| ICON_TOOL_EXTRUDE = 7, | |
| ICON_TOOL_FUZZY_SELECT = 8, | |
| ICON_MODE_ADD = 9, | |
| ICON_MODE_SUB = 10, | |
| ICON_MODE_PAINT = 11, | |
| ICON_SHAPE_CUBE = 12, | |
| ICON_SHAPE_SPHERE = 13, | |
| ICON_SHAPE_CYLINDER = 14, | |
| ICON_TOOL_SELECTION = 15, | |
| ICON_TOOL_LINE = 16, | |
| ICON_ADD = 17, | |
| ICON_REMOVE = 18, | |
| ICON_ARROW_BACK = 19, | |
| ICON_ARROW_FORWARD = 20, | |
| ICON_LINK = 21, | |
| ICON_MENU = 22, | |
| ICON_DELETE = 23, | |
| ICON_TOOL_PROCEDURAL = 24, | |
| ICON_VISIBILITY = 25, | |
| ICON_VISIBILITY_OFF = 26, | |
| ICON_ARROW_DOWNWARD = 27, | |
| ICON_ARROW_UPWARD = 28, | |
| ICON_EDIT = 29, | |
| ICON_COPY = 30, | |
| ICON_GALLERY = 31, | |
| ICON_INFO = 32, | |
| ICON_SETTINGS = 33, | |
| ICON_CLOUD = 34, | |
| ICON_SHAPE = 35, | |
| ICON_CLOSE = 36, | |
| ICON_TOOLS = 41, | |
| ICON_PALETTE = 42, | |
| ICON_LAYERS = 43, | |
| ICON_RENDER = 44, | |
| ICON_CAMERA = 45, | |
| ICON_IMAGE = 46, | |
| ICON_EXPORT = 47, | |
| ICON_DEBUG = 48, | |
| ICON_VIEW = 49, | |
| ICON_MATERIAL = 50, | |
| ICON_LIGHT = 51, | |
| }; | |
| /* | |
| * Some icons have their color blended depending on the style. We define | |
| * them with a range in the icons atlas: | |
| */ | |
| #define ICON_COLORIZABLE_START 17 | |
| #define ICON_COLORIZABLE_END 41 | |
| // #### Block ################## | |
| // The block size can only be 16. | |
| #define BLOCK_SIZE 16 | |
| #define VOXEL_TEXTURE_SIZE 8 | |
| // Generate an optimal palette whith a fixed number of colors from a mesh. | |
| void quantization_gen_palette(const mesh_t *mesh, int nb, | |
| uint8_t (*palette)[4]); | |
| // #### Goxel : core object #### | |
| // Flags to set where the mouse snap. In order of priority. | |
| enum { | |
| SNAP_IMAGE_BOX = 1 << 0, | |
| SNAP_SELECTION_IN = 1 << 1, | |
| SNAP_SELECTION_OUT = 1 << 2, | |
| SNAP_MESH = 1 << 3, | |
| SNAP_PLANE = 1 << 4, | |
| SNAP_CAMERA = 1 << 5, // Used for laser tool. | |
| SNAP_LAYER_OUT = 1 << 6, // Snap the layer box. | |
| SNAP_ROUNDED = 1 << 8, // Round the result. | |
| }; | |
| typedef struct goxel | |
| { | |
| obj_t obj; | |
| int screen_size[2]; | |
| float screen_scale; | |
| image_t *image; | |
| // Flag so that we reinit OpenGL after the context has been killed. | |
| bool graphics_initialized; | |
| // We can't reset the graphics in the middle of the gui, so use this. | |
| // for testing. | |
| bool request_test_graphic_release; | |
| // Tools can set this mesh and it will replace the current layer mesh | |
| // during render. | |
| mesh_t *tool_mesh; | |
| mesh_t *layers_mesh_; | |
| uint32_t layers_mesh_hash; | |
| mesh_t *render_mesh_; // All the layers + tool mesh. | |
| uint32_t render_mesh_hash; | |
| layer_t *render_layers; | |
| uint32_t render_layers_hash; | |
| struct { | |
| mesh_t *mesh; | |
| float box[4][4]; | |
| } clipboard; | |
| int snap_mask; // Global snap mask (can edit in the GUI). | |
| float snap_offset; // Only for brush tool, remove that? | |
| float plane[4][4]; // The snapping plane. | |
| bool show_export_viewport; | |
| uint8_t back_color[4]; | |
| uint8_t grid_color[4]; | |
| uint8_t image_box_color[4]; | |
| bool hide_box; | |
| texture_t *pick_fbo; | |
| painter_t painter; | |
| renderer_t rend; | |
| cursor_t cursor; | |
| tool_t *tool; | |
| float tool_radius; | |
| bool no_edit; // Disable editing. | |
| // Some state for the tool iter functions. | |
| float tool_plane[4][4]; | |
| int tool_drag_mode; // 0: move, 1: resize. | |
| float selection[4][4]; // The selection box. | |
| struct { | |
| float rotation[4]; | |
| float pos[2]; | |
| float camera_ofs[3]; | |
| float camera_mat[4][4]; | |
| } move_origin; | |
| palette_t *palettes; // The list of all the palettes | |
| palette_t *palette; // The current color palette | |
| char *help_text; // Seen in the bottom of the screen. | |
| char *hint_text; // Seen in the bottom of the screen. | |
| int frame_count; // Global frames counter. | |
| double frame_time; // Clock time at beginning of the frame (sec) | |
| double fps; // Average fps. | |
| bool quit; // Set to true to quit the application. | |
| int view_effects; // EFFECT_WIREFRAME | EFFECT_GRID | EFFECT_EDGES | |
| struct { | |
| gesture_t drag; | |
| gesture_t pan; | |
| gesture_t rotate; | |
| gesture_t hover; | |
| gesture_t pinch; | |
| } gestures; | |
| pathtracer_t pathtracer; | |
| // Used to check if the active mesh changed to play tick sound. | |
| uint64_t last_mesh_key; | |
| double last_click_time; | |
| // Some stats for the UI. | |
| struct { | |
| void (*current_panel)(void); | |
| float panel_width; | |
| float viewport[4]; | |
| } gui; | |
| } goxel_t; | |
| // the global goxel instance. | |
| extern goxel_t goxel; | |
| // XXX: add some doc. | |
| void goxel_init(void); | |
| void goxel_release(void); | |
| void goxel_reset(void); | |
| int goxel_iter(inputs_t *inputs); | |
| void goxel_render(void); | |
| /* | |
| * Function: goxel_create_graphics | |
| * Called after the graphics context has been created. | |
| */ | |
| void goxel_create_graphics(void); | |
| /* | |
| * Function: goxel_release_graphics | |
| * Called before the graphics context gets destroyed. | |
| */ | |
| void goxel_release_graphics(void); | |
| /* | |
| * Function: goxel_on_low_memory | |
| * Attempt to release cached memory | |
| */ | |
| void goxel_on_low_memory(void); | |
| int goxel_unproject(const float viewport[4], | |
| const float pos[2], int snap_mask, float offset, | |
| float out[3], float normal[3]); | |
| void goxel_render_view(const float viewport[4], bool render_mode); | |
| void goxel_render_export_view(const float viewport[4]); | |
| // Called by the gui when the mouse hover a 3D view. | |
| // XXX: change the name since we also call it when the mouse get out of | |
| // the view. | |
| void goxel_mouse_in_view(const float viewport[4], const inputs_t *inputs, | |
| bool capture_keys); | |
| const mesh_t *goxel_get_layers_mesh(void); | |
| const mesh_t *goxel_get_render_mesh(void); | |
| /* | |
| * Function: goxel_get_render_layers | |
| * Compute merged current image layer list | |
| * | |
| * This returns a simplified list of layers from the current image where | |
| * we merged as many layers as possible into a single one. | |
| * | |
| * It also can replace the current layer mesh with the tool preview. | |
| * | |
| * This is the function that should be used the get the actual list of layers | |
| * to be rendered. | |
| */ | |
| const layer_t *goxel_get_render_layers(bool with_tool_preview); | |
| void goxel_set_help_text(const char *msg, ...); | |
| void goxel_set_hint_text(const char *msg, ...); | |
| void goxel_import_image_plane(const char *path); | |
| // Render the view into an RGB[A] buffer. | |
| void goxel_render_to_buf(uint8_t *buf, int w, int h, int bpp); | |
| void save_to_file(const image_t *img, const char *path); | |
| int load_from_file(const char *path); | |
| // Iter info of a gox file, without actually reading it. | |
| // For the moment only returns the image preview if available. | |
| int gox_iter_infos(const char *path, | |
| int (*callback)(const char *attr, int size, | |
| void *value, void *user), | |
| void *user); | |
| void wavefront_export(const mesh_t *mesh, const char *path); | |
| void ply_export(const mesh_t *mesh, const char *path); | |
| // Section: box_edit | |
| /* | |
| * Function: gox_edit | |
| * Render a box that can be edited with the mouse. | |
| * | |
| * This is used for the move and selection tools. | |
| * Still a bit experimental. In theory we should be able to edit any box, | |
| * but because of the snap mechanism, we can only edit the layer or selection | |
| * for the moment. | |
| * | |
| * Parameters: | |
| * snap - SNAP_LAYER_OUT for layer edit, SNAP_SELECTION_OUT for selection | |
| * edit. | |
| * mode - 0: move, 1: resize. | |
| * transf - Receive the output transformation. | |
| * first - Set to true if the edit is the first one. | |
| */ | |
| int box_edit(int snap, int mode, float transf[4][4], bool *first); | |
| // Section: tests | |
| /* Function: tests_run | |
| * Run all the unit tests */ | |
| void tests_run(void); | |
| // Section: script | |
| /* | |
| * Function: script_run | |
| * Run a lua script from a file. | |
| */ | |
| int script_run(const char *filename, int argc, const char **argv); | |
| #endif // GOXEL_H |