/* GraphicTool2.cpp - Copyright 2008 Evan Wallace This code can be freely modified and distributed as long as this copyright notice is included in its entirety at the top of the modified or distributed code. */ #include #include #include #include #include #include #include #define DOMAIN_FILE "Domain_Definition.dat" using namespace std; struct vector_t { float x, y, z; }; enum { TYPE_INT, TYPE_UINT, TYPE_FLOAT }; enum { FACE_XNEG, FACE_YNEG, FACE_ZNEG, FACE_XPOS, FACE_YPOS, FACE_ZPOS }; enum { POSITION_LEFT = 0, POSITION_CENTER_HORIZONTAL = 1, POSITION_RIGHT = 2, POSITION_BOTTOM = 0, POSITION_CENTER_VERTICAL = 4, POSITION_TOP = 8, POSITION_CENTER = 5 }; enum { STATE_NORMAL = 0, STATE_PRESS = 1, STATE_TOGGLE = 2 }; enum { ARROW_X = 1, ARROW_Y = 2, ARROW_Z = 4, ARROW_DIAGONAL_1 = 8, ARROW_DIAGONAL_2 = 16 }; struct domain_t { float min_x, min_y, min_z; float max_x, max_y, max_z; // just for display purposes float w, h, d; // w, h, and d are redundant to eliminate floating point errors float temp_x, temp_y, temp_z; // for snapping to nearest domain unsigned int grid_x, grid_y, grid_z; // number of grid points in that dimension // interfaces (>0 means the index of the domain to link to (starting with 1), <=0 means boundary conditions) int inter_xneg, inter_yneg, inter_zneg; int inter_xpos, inter_ypos, inter_zpos; // mapping (no visual representation for mapping, just the numbers) int map_x, map_y, map_z; float alpha_x, alpha_y, alpha_z; float beta_x, beta_y, beta_z; }; struct property_t { const char *name; unsigned int type; unsigned int offset; bool is_2d; }; struct button_t { float min_x, min_y, max_x, max_y; unsigned int state; const char *text; bool is_2d, is_3d, is_selection; }; // to add a new property just fill out an entry below and add code in open() and save() for that property property_t properties[] = { { "x", TYPE_FLOAT, offsetof(domain_t, min_x), true }, { "y", TYPE_FLOAT, offsetof(domain_t, min_y), true }, { "z", TYPE_FLOAT, offsetof(domain_t, min_z), false }, { "width", TYPE_FLOAT, offsetof(domain_t, w), true }, { "height", TYPE_FLOAT, offsetof(domain_t, h), true }, { "depth", TYPE_FLOAT, offsetof(domain_t, d), false }, { "grid_x", TYPE_UINT, offsetof(domain_t, grid_x), true }, { "grid_y", TYPE_UINT, offsetof(domain_t, grid_y), true }, { "grid_z", TYPE_UINT, offsetof(domain_t, grid_z), false }, { "interface in -x", TYPE_INT, offsetof(domain_t, inter_xneg), true }, { "interface in -y", TYPE_INT, offsetof(domain_t, inter_yneg), true }, { "interface in -z", TYPE_INT, offsetof(domain_t, inter_zneg), false }, { "interface in +x", TYPE_INT, offsetof(domain_t, inter_xpos), true }, { "interface in +y", TYPE_INT, offsetof(domain_t, inter_ypos), true }, { "interface in +z", TYPE_INT, offsetof(domain_t, inter_zpos), false }, { "map_x", TYPE_INT, offsetof(domain_t, map_x), true }, { "map_y", TYPE_INT, offsetof(domain_t, map_y), true }, { "map_z", TYPE_INT, offsetof(domain_t, map_z), false }, { "alpha_x", TYPE_FLOAT, offsetof(domain_t, alpha_x), true }, { "alpha_y", TYPE_FLOAT, offsetof(domain_t, alpha_y), true }, { "alpha_z", TYPE_FLOAT, offsetof(domain_t, alpha_z), false }, { "beta_x", TYPE_FLOAT, offsetof(domain_t, beta_x), true }, { "beta_y", TYPE_FLOAT, offsetof(domain_t, beta_y), true }, { "beta_z", TYPE_FLOAT, offsetof(domain_t, beta_z), false } }; const char *convert[] = { "Convert to 2D", "Convert to 3D" }; // these need to be in the same order as the buttons below enum { BUTTON_CONVERT = 0, BUTTON_INTERFACES, BUTTON_SAVE, BUTTON_SUBDIVIDE, BUTTON_XNEG, BUTTON_XPOS, BUTTON_YNEG, BUTTON_YPOS, BUTTON_ZNEG, BUTTON_ZPOS, BUTTON_OUTSIDE, BUTTON_GRID, BUTTON_SELECTION }; // a negative coordinate means the opposite side (for example, "-5" means "width - 5") button_t buttons[] = { { 5.0f, 5.0f, 105.0f, 30.0f, STATE_NORMAL, convert[0], true, true, false }, { 110.0f, 5.0f, 225.0f, 30.0f, STATE_NORMAL, "Show interfaces", true, true, false }, { 230.0f, 5.0f, 270.0f, 30.0f, STATE_NORMAL, "Save", true, true, false }, { 275.0f, 5.0f, 415.0f, 30.0f, STATE_NORMAL, "Subdivide selection", true, true, true }, { -385.0f, -30.0f, -360.0f, -5.0f, STATE_NORMAL, "-X", false, true, false }, { -355.0f, -30.0f, -330.0f, -5.0f, STATE_NORMAL, "+X", false, true, false }, { -325.0f, -30.0f, -300.0f, -5.0f, STATE_NORMAL, "-Y", false, true, false }, { -295.0f, -30.0f, -270.0f, -5.0f, STATE_NORMAL, "+Y", false, true, false }, { -265.0f, -30.0f, -240.0f, -5.0f, STATE_NORMAL, "-Z", false, true, false }, { -235.0f, -30.0f, -210.0f, -5.0f, STATE_NORMAL, "+Z", false, true, false }, { -205.0f, -30.0f, -115.0f, -5.0f, STATE_NORMAL, "Outside only", false, true, false }, { -190.0f, -30.0f, -115.0f, -5.0f, STATE_NORMAL, "Show grid", true, false, false }, { -110.0f, -30.0f, -5.0f, -5.0f, STATE_NORMAL, "Selection only", true, true, false } }; // status is displayed in the lower-right corner enum { STATUS_OPEN = 0, STATUS_OPEN_ERROR, STATUS_SAVE, STATUS_SAVE_ERROR, STATUS_NONE }; const char *status[] = { "Opened " DOMAIN_FILE, "Could not open " DOMAIN_FILE, "Saved " DOMAIN_FILE, "Could not save " DOMAIN_FILE }; unsigned int current_status = STATUS_NONE; // for the "Subdivide selection" button bool get_subdivide = false; unsigned int subdivide_x, subdivide_y, subdivide_z, subdivide_index; bool entering_subdivide; char subdivide_string[32]; int subdivide_length = 0; vector domains; int selection = -1; XFontStruct *info; Display *display; Window window; unsigned int width = 600; unsigned int height = 500; // for the properties in the upper-left corner unsigned int property = 0; bool entering_property = false; char property_string[32] = ""; int property_length = 0; float spin_x_axis = 0.0f, spin_y_axis = 0.0f, zoom_z = 0.0f; float center_x = 0.0f, center_y = 0.0f, center_z = 0.0f, move_dist = 0.0f; bool spinning = false, moving = false, resizing = false, is_2d = false; int font_width; int font_height; unsigned int font = 0; // for the yellow arrow under the cursor unsigned int arrow_type = 0, arrow_corner = 0; float arrow_x, arrow_y, arrow_z; float off_x, off_y, off_z; void add_domain(float x1, float y1, float z1, float x2, float y2, float z2, int grid_x, int grid_y, int grid_z, int xneg, int yneg, int zneg, int xpos, int ypos, int zpos, int map_x, int map_y, int map_z, float alpha_x, float alpha_y, float alpha_z, float beta_x, float beta_y, float beta_z) { domain_t domain = { min(x1, x2), min(y1, y2), min(z1, z2), // minimum coordinates max(x1, x2), max(y1, y2), max(z1, z2), // maximum coordinates fabsf(x1 - x2), fabsf(y1 - y2), fabsf(z1 - z2), // changes in coordinates 0.0f, 0.0f, 0.0f, // temporary variables initialized to 0 grid_x, grid_y, grid_z, // number of grid points xneg, yneg, zneg, // interfaces xpos, ypos, zpos, // interfaces map_x, map_y, map_z, // mapping alpha_x, alpha_y, alpha_z, // alpha beta_x, beta_y, beta_z // beta }; domains.push_back(domain); } void draw_text(float x, float y, float z, const char *s, unsigned int position) { if(info) { float dx, dy; int i = 0, direction, ascent, descent; XCharStruct overall; const char *c = s; if(c) while(*c++) i++; XTextExtents(info, s, i, &direction, &ascent, &descent, &overall); font_width = overall.rbearing - overall.lbearing; font_height = info->descent + info->ascent; if(position & POSITION_CENTER_HORIZONTAL) dx = -(float)font_width * 0.5f; else if(position & POSITION_RIGHT) dx = -(float)font_width; else dx = 0.0f; if(position & POSITION_CENTER_VERTICAL) dy = (float)font_height * 0.5f; else if(position & POSITION_TOP) dy = 0.0f; else dy = (float)font_height; glRasterPos3f(x, y, z); glBitmap(0, 0, 0.0f, 0.0f, dx, dy - (float)info->ascent, NULL); glCallLists(i, GL_UNSIGNED_BYTE, (unsigned char *)s); } } void error(const char *text) { printf("error : %s\n", text); } void fill_domain(domain_t dom) { glVertex3f(dom.min_x, dom.min_y, dom.min_z); glVertex3f(dom.min_x, dom.min_y, dom.max_z); glVertex3f(dom.min_x, dom.max_y, dom.max_z); glVertex3f(dom.min_x, dom.max_y, dom.min_z); glVertex3f(dom.max_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.min_y, dom.max_z); glVertex3f(dom.max_x, dom.max_y, dom.max_z); glVertex3f(dom.max_x, dom.max_y, dom.min_z); glVertex3f(dom.min_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.max_y, dom.min_z); glVertex3f(dom.min_x, dom.max_y, dom.min_z); glVertex3f(dom.min_x, dom.min_y, dom.max_z); glVertex3f(dom.max_x, dom.min_y, dom.max_z); glVertex3f(dom.max_x, dom.max_y, dom.max_z); glVertex3f(dom.min_x, dom.max_y, dom.max_z); glVertex3f(dom.min_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.min_y, dom.max_z); glVertex3f(dom.min_x, dom.min_y, dom.max_z); glVertex3f(dom.min_x, dom.max_y, dom.min_z); glVertex3f(dom.max_x, dom.max_y, dom.min_z); glVertex3f(dom.max_x, dom.max_y, dom.max_z); glVertex3f(dom.min_x, dom.max_y, dom.max_z); } void line_domain(domain_t dom) { glVertex3f(dom.min_x, dom.min_y, dom.min_z); glVertex3f(dom.min_x, dom.min_y, dom.max_z); glVertex3f(dom.max_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.min_y, dom.max_z); glVertex3f(dom.min_x, dom.max_y, dom.min_z); glVertex3f(dom.min_x, dom.max_y, dom.max_z); glVertex3f(dom.max_x, dom.max_y, dom.min_z); glVertex3f(dom.max_x, dom.max_y, dom.max_z); glVertex3f(dom.min_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.min_y, dom.min_z); glVertex3f(dom.max_x, dom.max_y, dom.min_z); glVertex3f(dom.max_x, dom.max_y, dom.min_z); glVertex3f(dom.min_x, dom.max_y, dom.min_z); glVertex3f(dom.min_x, dom.max_y, dom.min_z); glVertex3f(dom.min_x, dom.min_y, dom.min_z); glVertex3f(dom.min_x, dom.min_y, dom.max_z); glVertex3f(dom.max_x, dom.min_y, dom.max_z); glVertex3f(dom.max_x, dom.min_y, dom.max_z); glVertex3f(dom.max_x, dom.max_y, dom.max_z); glVertex3f(dom.max_x, dom.max_y, dom.max_z); glVertex3f(dom.min_x, dom.max_y, dom.max_z); glVertex3f(dom.min_x, dom.max_y, dom.max_z); glVertex3f(dom.min_x, dom.min_y, dom.max_z); } void grid_domain(domain_t dom) { bool outside = (buttons[BUTTON_OUTSIDE].state & STATE_TOGGLE) ? true : false; bool xneg, yneg, zneg, xpos, ypos, zpos; unsigned int i; float f; xneg = (!is_2d && (buttons[BUTTON_XNEG].state & STATE_TOGGLE) && (!outside || dom.inter_xneg <= 0)); yneg = (!is_2d && (buttons[BUTTON_YNEG].state & STATE_TOGGLE) && (!outside || dom.inter_yneg <= 0)); zneg = (!is_2d && (buttons[BUTTON_ZNEG].state & STATE_TOGGLE) && (!outside || dom.inter_zneg <= 0)); xpos = (!is_2d && (buttons[BUTTON_XPOS].state & STATE_TOGGLE) && (!outside || dom.inter_xpos <= 0)); ypos = (!is_2d && (buttons[BUTTON_YPOS].state & STATE_TOGGLE) && (!outside || dom.inter_ypos <= 0)); zpos = ((!is_2d && (buttons[BUTTON_ZPOS].state & STATE_TOGGLE) && (!outside || dom.inter_zpos <= 0)) || (is_2d && (buttons[BUTTON_GRID].state & STATE_TOGGLE))); for(i = 0; i < dom.grid_x; i++) { f = dom.min_x + (dom.max_x - dom.min_x) * (0.5f - cosf((float)i / (float)(dom.grid_x - 1) * 3.141592654f) * 0.5f); if(zneg) { glVertex3f(f, dom.min_y, dom.min_z); glVertex3f(f, dom.max_y, dom.min_z); } if(zpos) { glVertex3f(f, dom.min_y, dom.max_z); glVertex3f(f, dom.max_y, dom.max_z); } if(yneg) { glVertex3f(f, dom.min_y, dom.min_z); glVertex3f(f, dom.min_y, dom.max_z); } if(ypos) { glVertex3f(f, dom.max_y, dom.min_z); glVertex3f(f, dom.max_y, dom.max_z); } } for(i = 0; i < dom.grid_y; i++) { f = dom.min_y + (dom.max_y - dom.min_y) * (0.5f - cosf((float)i / (float)(dom.grid_y - 1) * 3.141592654f) * 0.5f); if(zneg) { glVertex3f(dom.min_x, f, dom.min_z); glVertex3f(dom.max_x, f, dom.min_z); } if(zpos) { glVertex3f(dom.min_x, f, dom.max_z); glVertex3f(dom.max_x, f, dom.max_z); } if(xneg) { glVertex3f(dom.min_x, f, dom.min_z); glVertex3f(dom.min_x, f, dom.max_z); } if(xpos) { glVertex3f(dom.max_x, f, dom.min_z); glVertex3f(dom.max_x, f, dom.max_z); } } for(i = 0; i < dom.grid_z; i++) { f = dom.min_z + (dom.max_z - dom.min_z) * (0.5f - cosf((float)i / (float)(dom.grid_z - 1) * 3.141592654f) * 0.5f); if(yneg) { glVertex3f(dom.min_x, dom.min_y, f); glVertex3f(dom.max_x, dom.min_y, f); } if(ypos) { glVertex3f(dom.min_x, dom.max_y, f); glVertex3f(dom.max_x, dom.max_y, f); } if(xneg) { glVertex3f(dom.min_x, dom.min_y, f); glVertex3f(dom.min_x, dom.max_y, f); } if(xpos) { glVertex3f(dom.max_x, dom.min_y, f); glVertex3f(dom.max_x, dom.max_y, f); } } } void render() { // pre-blending colors is faster than full-screen blending unsigned char c31 = get_subdivide ? 15 : 31; unsigned char c63 = get_subdivide ? 31 : 63; unsigned char c95 = get_subdivide ? 47 : 95; unsigned char c127 = get_subdivide ? 63 : 127; unsigned char c191 = get_subdivide ? 95 : 191; unsigned char c255 = get_subdivide ? 127 : 255; std::vector::iterator i; float space = -zoom_z * 0.02f, offset; char buffer[100], buffer2[100]; domain_t dom; int n; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f, 0.0f, zoom_z); glRotatef(spin_x_axis, 1.0f, 0.0f, 0.0f); glRotatef(spin_y_axis, 0.0f, 1.0f, 0.0f); glTranslatef(center_x, center_y, center_z); glEnable(GL_DEPTH_TEST); glBegin(GL_QUADS); glColor3ub(c63, c63, c63); for(i = domains.begin(); i != domains.end(); i++) fill_domain(*i); glEnd(); glDisable(GL_DEPTH_TEST); if(selection != -1) { glBegin(GL_QUADS); glColor3ub(c95, c95, c95); fill_domain(domains.at(selection)); glEnd(); } glBegin(GL_LINES); glColor3ub(c31, c31, c31); if(!is_2d) for(i = domains.begin(); i != domains.end(); i++) line_domain(*i); if(!(buttons[BUTTON_SELECTION].state & STATE_TOGGLE)) for(i = domains.begin(); i != domains.end(); i++) grid_domain(*i); else if(selection != -1) grid_domain(domains.at(selection)); glEnd(); glBegin(GL_LINES); glColor3ub(c127, c127, c127); for(i = domains.begin(), n = 1; i != domains.end(); i++, n++) { if(i->inter_xneg > 0 && i->inter_xneg <= domains.size()) { dom = domains.at(i->inter_xneg - 1); glVertex3f(i->min_x + 0.001f, (i->min_y + i->max_y) * 0.5f - 0.001f, (i->min_z + i->max_z) * 0.5f); glVertex3f(dom.max_x - 0.001f, (dom.min_y + dom.max_y) * 0.5f - 0.001f, (dom.min_z + dom.max_z) * 0.5f); } if(i->inter_yneg > 0 && i->inter_yneg <= domains.size()) { dom = domains.at(i->inter_yneg - 1); glVertex3f((i->min_x + i->max_x) * 0.5f - 0.001f, i->min_y + 0.001f, (i->min_z + i->max_z) * 0.5f); glVertex3f((dom.min_x + dom.max_x) * 0.5f - 0.001f, dom.max_y - 0.001f, (dom.min_z + dom.max_z) * 0.5f); } if(i->inter_zneg > 0 && i->inter_zneg <= domains.size()) { dom = domains.at(i->inter_zneg - 1); glVertex3f((i->min_x + i->max_x) * 0.5f, (i->min_y + i->max_y) * 0.5f - 0.001f, i->min_z + 0.001f); glVertex3f((dom.min_x + dom.max_x) * 0.5f, (dom.min_y + dom.max_y) * 0.5f - 0.001f, dom.max_z - 0.001f); } if(i->inter_xpos > 0 && i->inter_xpos <= domains.size()) { dom = domains.at(i->inter_xpos - 1); glVertex3f(i->max_x - 0.001f, (i->min_y + i->max_y) * 0.5f + 0.001f, (i->min_z + i->max_z) * 0.5f); glVertex3f(dom.min_x + 0.001f, (dom.min_y + dom.max_y) * 0.5f + 0.001f, (dom.min_z + dom.max_z) * 0.5f); } if(i->inter_ypos > 0 && i->inter_ypos <= domains.size()) { dom = domains.at(i->inter_ypos - 1); glVertex3f((i->min_x + i->max_x) * 0.5f + 0.001f, i->max_y - 0.001f, (i->min_z + i->max_z) * 0.5f); glVertex3f((dom.min_x + dom.max_x) * 0.5f + 0.001f, dom.min_y + 0.001f, (dom.min_z + dom.max_z) * 0.5f); } if(i->inter_zpos > 0 && i->inter_zpos <= domains.size()) { dom = domains.at(i->inter_zpos - 1); glVertex3f((i->min_x + i->max_x) * 0.5f, (i->min_y + i->max_y) * 0.5f + 0.001f, i->max_z - 0.001f); glVertex3f((dom.min_x + dom.max_x) * 0.5f, (dom.min_y + dom.max_y) * 0.5f + 0.001f, dom.min_z + 0.001f); } } glEnd(); // bring the lines toward the camera a small amount to reduce z-fighting in 3D view if(!is_2d) { glPushMatrix(); offset = -zoom_z * 0.001f * cosf(spin_x_axis * 0.017453293f); glTranslatef(-sinf(spin_y_axis * 0.017453293f) * offset, -zoom_z * 0.001f * sinf(spin_x_axis * 0.017453293f), cosf(spin_y_axis * 0.017453293f) * offset); glEnable(GL_DEPTH_TEST); } glBegin(GL_LINES); glColor3ub(c191, c191, c191); for(i = domains.begin(); i != domains.end(); i++) line_domain(*i); glEnd(); if(!is_2d) { glDisable(GL_DEPTH_TEST); glPopMatrix(); } if(buttons[BUTTON_INTERFACES].state & STATE_TOGGLE) { glColor3ub(c255, c191, 0); for(i = domains.begin(), n = 1; i != domains.end(); i++, n++) { if(i->inter_xneg <= 0 || i->inter_xneg > domains.size()) { sprintf(buffer, "%d", i->inter_xneg); draw_text(i->min_x - space, (i->min_y + i->max_y) * 0.5f, (i->min_z + i->max_z) * 0.5f, buffer, POSITION_CENTER); } if(i->inter_yneg <= 0 || i->inter_yneg > domains.size()) { sprintf(buffer, "%d", i->inter_yneg); draw_text((i->min_x + i->max_x) * 0.5f, i->min_y - space, (i->min_z + i->max_z) * 0.5f, buffer, POSITION_CENTER); } if(!is_2d && (i->inter_zneg <= 0 || i->inter_zneg > domains.size())) { sprintf(buffer, "%d", i->inter_zneg); draw_text((i->min_x + i->max_x) * 0.5f, (i->min_y + i->max_y) * 0.5f, i->min_z - space, buffer, POSITION_CENTER); } if(i->inter_xpos <= 0 || i->inter_xpos > domains.size()) { sprintf(buffer, "%d", i->inter_xpos); draw_text(i->max_x + space, (i->min_y + i->max_y) * 0.5f, (i->min_z + i->max_z) * 0.5f, buffer, POSITION_CENTER); } if(i->inter_ypos <= 0 || i->inter_ypos > domains.size()) { sprintf(buffer, "%d", i->inter_ypos); draw_text((i->min_x + i->max_x) * 0.5f, i->max_y + space, (i->min_z + i->max_z) * 0.5f, buffer, POSITION_CENTER); } if(!is_2d && (i->inter_zpos <= 0 || i->inter_zpos > domains.size())) { sprintf(buffer, "%d", i->inter_zpos); draw_text((i->min_x + i->max_x) * 0.5f, (i->min_y + i->max_y) * 0.5f, i->max_z + space, buffer, POSITION_CENTER); } } } for(i = domains.begin(), n = 1; i != domains.end(); i++, n++) { glColor3ub(c255, c255, c255); sprintf(buffer, "%u", n); draw_text((i->min_x + i->max_x) * 0.5f, (i->min_y + i->max_y) * 0.5f, (i->min_z + i->max_z) * 0.5f, buffer, POSITION_CENTER); } if(arrow_type) { float z = zoom_z * -0.02f; glPointSize(7.0f); glColor3ub(c255, c255, 0); glPushMatrix(); glTranslatef(arrow_x, arrow_y, arrow_z); if(arrow_type & ARROW_X) glRotatef(90.0f, 0.0f, 1.0f, 0.0f); else if(arrow_type & ARROW_Y) glRotatef(90.0f, 1.0f, 0.0f, 0.0f); if(arrow_type & ARROW_DIAGONAL_1) glRotatef(45.0f, 0.0f, 0.0f, 1.0f); else if(arrow_type & ARROW_DIAGONAL_2) glRotatef(135.0f, 0.0f, 0.0f, 1.0f); glBegin(GL_TRIANGLE_FAN); glVertex3f(-z, 0.0f, 0.0f); glVertex3f(-z * 0.6f, -z * 0.5f, 0.0f); glVertex3f(-z * 0.6f, -z * 0.2f, 0.0f); glVertex3f(-z * 0.6f, z * 0.2f, 0.0f); glVertex3f(-z * 0.6f, z * 0.5f, 0.0f); glEnd(); glBegin(GL_TRIANGLE_FAN); glVertex3f(z, 0.0f, 0.0f); glVertex3f(z * 0.6f, -z * 0.5f, 0.0f); glVertex3f(z * 0.6f, -z * 0.2f, 0.0f); glVertex3f(z * 0.6f, z * 0.2f, 0.0f); glVertex3f(z * 0.6f, z * 0.5f, 0.0f); glEnd(); if(!(arrow_type & (ARROW_DIAGONAL_1 | ARROW_DIAGONAL_2))) { glBegin(GL_TRIANGLE_FAN); glVertex3f(0.0f, -z, 0.0f); glVertex3f(-z * 0.5f, -z * 0.6f, 0.0f); glVertex3f(-z * 0.2f, -z * 0.6f, 0.0f); glVertex3f(z * 0.2f, -z * 0.6f, 0.0f); glVertex3f(z * 0.5f, -z * 0.6f, 0.0f); glEnd(); glBegin(GL_TRIANGLE_FAN); glVertex3f(0.0f, z, 0.0f); glVertex3f(-z * 0.5f, z * 0.6f, 0.0f); glVertex3f(-z * 0.2f, z * 0.6f, 0.0f); glVertex3f(z * 0.2f, z * 0.6f, 0.0f); glVertex3f(z * 0.5f, z * 0.6f, 0.0f); glEnd(); } glBegin(GL_TRIANGLE_FAN); glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(-z * 0.2f, -z * 0.2f, 0.0f); glVertex3f(-z * 0.6f, -z * 0.2f, 0.0f); glVertex3f(-z * 0.6f, z * 0.2f, 0.0f); glVertex3f(-z * 0.2f, z * 0.2f, 0.0f); if(!(arrow_type & (ARROW_DIAGONAL_1 | ARROW_DIAGONAL_2))) { glVertex3f(-z * 0.2f, z * 0.6f, 0.0f); glVertex3f(z * 0.2f, z * 0.6f, 0.0f); } glVertex3f(z * 0.2f, z * 0.2f, 0.0f); glVertex3f(z * 0.6f, z * 0.2f, 0.0f); glVertex3f(z * 0.6f, -z * 0.2f, 0.0f); glVertex3f(z * 0.2f, -z * 0.2f, 0.0f); if(!(arrow_type & (ARROW_DIAGONAL_1 | ARROW_DIAGONAL_2))) { glVertex3f(z * 0.2f, -z * 0.6f, 0.0f); glVertex3f(-z * 0.2f, -z * 0.6f, 0.0f); } glVertex3f(-z * 0.2f, -z * 0.2f, 0.0f); glEnd(); glPopMatrix(); } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0.0, (double)width, 0.0, (double)height); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3ub(c255, c255, c255); draw_text((float)(width - (is_2d ? 195 : 390)), (float)height - 17.5f, 0.0f, "Grid:", POSITION_RIGHT | POSITION_CENTER_VERTICAL); if(current_status < sizeof(status) / sizeof(const char *)) { if(current_status & 1) glColor3ub(c255, 0, 0); else glColor3ub(0, c255, 0); draw_text((float)(width - 5), 5.0f, 0.0f, status[current_status], POSITION_RIGHT | POSITION_BOTTOM); } unsigned char normal[] = { c191, c191, c191, c127, c127, c127 }; unsigned char toggle[] = { c255, c191, c127, c255, c127, 0 }; unsigned char *colors; unsigned int color; float min_x, min_y, max_x, max_y; for(n = 0; n < sizeof(buttons) / sizeof(button_t); n++) { if(is_2d && !buttons[n].is_2d) continue; else if(!is_2d && !buttons[n].is_3d) continue; else if(selection == -1 && buttons[n].is_selection) continue; colors = (buttons[n].state & STATE_TOGGLE) ? toggle : normal; color = (buttons[n].state & STATE_PRESS) ? 3 : 0; min_x = buttons[n].min_x; if(min_x < 0.0f) min_x += (float)width; max_x = buttons[n].max_x; if(max_x < 0.0f) max_x += (float)width; min_y = buttons[n].min_y; if(min_y < 0.0f) min_y += (float)height; max_y = buttons[n].max_y; if(max_y < 0.0f) max_y += (float)height; glBegin(GL_QUADS); glColor3ubv(&colors[color]); glVertex2f(min_x, max_y); glVertex2f(max_x, max_y); glColor3ubv(&colors[3 - color]); glVertex2f(max_x, min_y); glVertex2f(min_x, min_y); glEnd(); glColor3ub(0, 0, 0); draw_text((min_x + max_x) * 0.5f, (min_y + max_y) * 0.5f, 0.0f, buttons[n].text, POSITION_CENTER); } if(selection != -1) { unsigned int i, j; float y = (float)height - 5.0f; domain_t dom = domains.at(selection); for(i = 0; i < sizeof(properties) / sizeof(property_t); i++) { if(is_2d && !properties[i].is_2d) continue; if(properties[i].type == TYPE_INT) sprintf(buffer, "%d", *(int *)(((unsigned char *)&dom) + properties[i].offset)); else if(properties[i].type == TYPE_UINT) sprintf(buffer, "%u", *(unsigned int *)(((unsigned char *)&dom) + properties[i].offset)); else if(properties[i].type == TYPE_FLOAT) { sprintf(buffer, "%f", *(float *)(((unsigned char *)&dom) + properties[i].offset)); // pretty printing for(j = 0; buffer[j]; j++) ; while(buffer[j - 1] == '0') j--; if(buffer[j - 1] == '.') { // fix -0 if(buffer[j - 2] == '0' && buffer[j - 3] == '-') { buffer[j - 3] = '0'; buffer[j - 2] = '.'; buffer[j - 1] = '0'; } else j++; } buffer[j] = '\0'; } if(property == i) { if(entering_property) { if(!property_length) { sprintf(buffer2, "%s = %s", properties[i].name, buffer); glColor3ub(c127, c127, c127); draw_text(5.0f, y, 0.0f, buffer2, POSITION_LEFT | POSITION_TOP); } sprintf(buffer2, "%s = %s_", properties[i].name, property_string); } else sprintf(buffer2, "%s = %s", properties[i].name, buffer); glColor3ub(c255, c255, 0); } else { sprintf(buffer2, "%s = %s", properties[i].name, buffer); glColor3ub(c255, c255, c255); } draw_text(5.0f, y, 0.0f, buffer2, POSITION_LEFT | POSITION_TOP); y -= (float)font_height; } } if(get_subdivide) { if(entering_subdivide && subdivide_index == 1) { if(subdivide_length == 0) { glColor3ub(127, 127, 127); sprintf(buffer, "Subdivisions in y = %u", subdivide_y); draw_text((float)(width / 2 - 65), (float)(height / 2), 0.0f, buffer, POSITION_LEFT | POSITION_BOTTOM); } glColor3ub(255, 255, 0); sprintf(buffer, "Subdivisions in y = %s_", subdivide_string); } else { glColor3ub(255, 255, (subdivide_index == 1) ? 0 : 255); sprintf(buffer, "Subdivisions in y = %u", subdivide_y); } draw_text((float)(width / 2 - 65), (float)(height / 2), 0.0f, buffer, POSITION_LEFT | POSITION_BOTTOM); if(entering_subdivide && subdivide_index == 0) { if(subdivide_length == 0) { glColor3ub(127, 127, 127); sprintf(buffer, "Subdivisions in x = %u", subdivide_x); draw_text((float)(width / 2 - 65), (float)(height / 2 + font_height), 0.0f, buffer, POSITION_LEFT | POSITION_BOTTOM); } glColor3ub(255, 255, 0); sprintf(buffer, "Subdivisions in x = %s_", subdivide_string); } else { glColor3ub(255, 255, (subdivide_index == 0) ? 0 : 255); sprintf(buffer, "Subdivisions in x = %u", subdivide_x); } draw_text((float)(width / 2 - 65), (float)(height / 2 + font_height), 0.0f, buffer, POSITION_LEFT | POSITION_BOTTOM); if(entering_subdivide && subdivide_index == 2) { if(subdivide_length == 0) { glColor3ub(127, 127, 127); sprintf(buffer, "Subdivisions in z = %u", subdivide_z); draw_text((float)(width / 2 - 65), (float)(height / 2), 0.0f, buffer, POSITION_LEFT | POSITION_TOP); } glColor3ub(255, 255, 0); sprintf(buffer, "Subdivisions in z = %s_", subdivide_string); } else { glColor3ub(255, 255, (subdivide_index == 2) ? 0 : 255); sprintf(buffer, "Subdivisions in z = %u", subdivide_z); } draw_text((float)(width / 2 - 65), (float)(height / 2), 0.0f, buffer, POSITION_LEFT | POSITION_TOP); glColor3ub(255, 255, (subdivide_index == 3) ? 0 : 255); draw_text((float)(width / 2), (float)(height / 2 - font_height), 0.0f, "Subdivide", POSITION_CENTER_HORIZONTAL | POSITION_TOP); } glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glXSwapBuffers(display, window); } void resize() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (float)width / (float)height, 0.001f, 100000.0f); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, width, height); } bool equals(float a, float b) { return (fabsf(a - b) < 0.00001f); } void calculate_interfaces() { vector::iterator i, j; int I, J; for(i = domains.begin(); i != domains.end(); i++) { if(i->inter_xneg > 0) i->inter_xneg = 0; if(i->inter_yneg > 0) i->inter_yneg = 0; if(i->inter_zneg > 0) i->inter_zneg = 0; if(i->inter_xpos > 0) i->inter_xpos = 0; if(i->inter_ypos > 0) i->inter_ypos = 0; if(i->inter_zpos > 0) i->inter_zpos = 0; } for(i = domains.begin(), I = 0; i != domains.end(); i++, I++) { for(j = i + 1, J = I + 1; j != domains.end(); j++, J++) { // check for interfaces in x if(equals(i->min_y, j->min_y) && equals(i->max_y, j->max_y) && equals(i->min_z, j->min_z) && equals(i->max_z, j->max_z)) { if(equals(i->min_x, j->max_x)) { i->inter_xneg = J + 1; j->inter_xpos = I + 1; } if(equals(i->max_x, j->min_x)) { i->inter_xpos = J + 1; j->inter_xneg = I + 1; } } // check for interfaces in y if(equals(i->min_x, j->min_x) && equals(i->max_x, j->max_x) && equals(i->min_z, j->min_z) && equals(i->max_z, j->max_z)) { if(equals(i->min_y, j->max_y)) { i->inter_yneg = J + 1; j->inter_ypos = I + 1; } if(equals(i->max_y, j->min_y)) { i->inter_ypos = J + 1; j->inter_yneg = I + 1; } } // check for interfaces in z if(equals(i->min_x, j->min_x) && equals(i->max_x, j->max_x) && equals(i->min_y, j->min_y) && equals(i->max_y, j->max_y)) { if(equals(i->min_z, j->max_z)) { i->inter_zneg = J + 1; j->inter_zpos = I + 1; } if(equals(i->max_z, j->min_z)) { i->inter_zpos = J + 1; j->inter_zneg = I + 1; } } } } } void skip_lines(FILE *f, unsigned int lines) { int c; while(lines--) { do c = fgetc(f); while(c >= 0 && c != '\n'); if(!c) break; } } bool open(const char *file) { FILE *f; if(f = fopen(file, "r")) { domain_t dom; float dummy; int n; if(fscanf(f, "Number of Dimension = %d\n", &n) == 1 && (n == 2 || n == 3)) { is_2d = (n == 2) ? true : false; buttons[BUTTON_CONVERT].text = convert[is_2d]; skip_lines(f, 21); for(;;) { memset(&dom, 0, sizeof(dom)); if(is_2d) { if(fscanf(f, " 1 Linear %*f %*f %*f %*f %*f %d %*d\n", &dom.inter_xneg) != 1) break; if(fscanf(f, " 2 Linear %f %f %*f %*f %*f %d %*d\n", &dom.min_x, &dom.min_y, &dom.inter_yneg) != 3) break; if(fscanf(f, " 3 Linear %*f %*f %*f %*f %*f %d %*d\n", &dom.inter_xpos) != 1) break; if(fscanf(f, " 4 Linear %f %f %*f %*f %*f %d %*d\n", &dom.max_x, &dom.max_y, &dom.inter_ypos) != 3) break; } else { if(fscanf(f, " 1 %d %*d\n", &dom.inter_xneg) != 1) break; if(fscanf(f, " 2 %d %*d\n", &dom.inter_yneg) != 1) break; if(fscanf(f, " 3 %d %*d\n", &dom.inter_zneg) != 1) break; if(fscanf(f, " 4 %d %*d\n", &dom.inter_xpos) != 1) break; if(fscanf(f, " 5 %d %*d\n", &dom.inter_ypos) != 1) break; if(fscanf(f, " 6 %d %*d\n", &dom.inter_zpos) != 1) break; skip_lines(f, 1); if(fscanf(f, " Minimum %f %f %f\n", &dom.min_x, &dom.min_y, &dom.min_z) != 3) break; if(fscanf(f, " Maximum %f %f %f\n", &dom.max_x, &dom.max_y, &dom.max_z) != 3) break; } skip_lines(f, 1); if(fscanf(f, "%u %*d %*d in x\n", &dom.grid_x) != 1) break; if(fscanf(f, "%u %*d %*d in y\n", &dom.grid_y) != 1) break; if(!is_2d) if(fscanf(f, "%u %*d %*d in z\n", &dom.grid_z) != 1) break; skip_lines(f, is_2d ? 5 : 6); if(fscanf(f, "%d %*d %f %f %*d in x\n", &dom.map_x, &dom.alpha_x, &dom.beta_x) != 3) break; if(fscanf(f, "%d %*d %f %f %*d in y\n", &dom.map_y, &dom.alpha_y, &dom.beta_y) != 3) break; if(!is_2d) if(fscanf(f, "%d %*d %f %f %*d in z\n", &dom.map_z, &dom.alpha_z, &dom.beta_z) != 3) break; skip_lines(f, is_2d ? 25 : 29); if(dom.min_x > dom.max_x) { dummy = dom.min_x; dom.min_x = dom.max_x; dom.max_x = dummy; } if(dom.min_y > dom.max_y) { dummy = dom.min_y; dom.min_y = dom.max_y; dom.max_y = dummy; } if(!is_2d && dom.min_z > dom.max_z) { dummy = dom.min_z; dom.min_z = dom.max_z; dom.max_z = dummy; } dom.w = dom.max_x - dom.min_x; dom.h = dom.max_y - dom.min_y; if(!is_2d) dom.d = dom.max_z - dom.min_z; domains.push_back(dom); } fclose(f); return true; } fclose(f); } return false; } bool save(const char *file) { FILE *f; if(f = fopen(file, "w")) { vector::iterator i; int n; calculate_interfaces(); fprintf(f, "Number of Dimension = %u\n", is_2d ? 2 : 3); fprintf(f, "\n"); fprintf(f, "Wall Temperature = -1 ( 0 : Freestream T for all Wall)\n"); fprintf(f, " (-1 : Only for those T with -1)\n"); fprintf(f, "Conforming Domain = T\n"); fprintf(f, "\n"); fprintf(f, "Data Duplication = F (See Override for more control)\n"); fprintf(f, "Anchor Domain = 1 (Anchor domain number)\n"); fprintf(f, "\n"); fprintf(f, "Use External File = F (if T, use interface file instead)\n"); fprintf(f, "Interface Filename = Domain_Interface\n"); fprintf(f, "\n"); fprintf(f, "Use External File = F (if T, use interface file instead)\n"); fprintf(f, "Coordinate Filename = Domain_Coordinate\n"); fprintf(f, "\n"); fprintf(f, "Number of Domain = %u\n", domains.size()); for(i = domains.begin(), n = 1; i != domains.end(); i++, n++) { fprintf(f, "\n"); fprintf(f, "=========================================================================\n"); fprintf(f, "Domain Number : %-6u Active : T Type : 0\n", n); fprintf(f, " Override : T Angle_0 : 0 Angle_1 : 0\n"); fprintf(f, "----------------------------------------------------------------\n"); if(is_2d) { fprintf(f, " Center Wall\n"); fprintf(f, "Side Type x y x y Radius Link Temperature\n"); fprintf(f, " 1 Linear %9f %9f 0 0 1 %4i %2i\n", i->min_x, i->max_y, i->inter_xneg, (i->inter_xneg == -4) ? -1 : 0); fprintf(f, " 2 Linear %9f %9f 0 0 1 %4i %2i\n", i->min_x, i->min_y, i->inter_yneg, (i->inter_yneg == -4) ? -1 : 0); fprintf(f, " 3 Linear %9f %9f 0 0 1 %4i %2i\n", i->max_x, i->min_y, i->inter_xpos, (i->inter_xpos == -4) ? -1 : 0); fprintf(f, " 4 Linear %9f %9f 0 0 1 %4i %2i\n", i->max_x, i->max_y, i->inter_ypos, (i->inter_ypos == -4) ? -1 : 0); } else { fprintf(f, " Wall\n"); fprintf(f, "Face Link Temperature\n"); fprintf(f, " 1 %4i %2i\n", i->inter_xneg, (i->inter_xneg == -4) ? -1 : 0); fprintf(f, " 2 %4i %2i\n", i->inter_yneg, (i->inter_yneg == -4) ? -1 : 0); fprintf(f, " 3 %4i %2i\n", i->inter_zneg, (i->inter_zneg == -4) ? -1 : 0); fprintf(f, " 4 %4i %2i\n", i->inter_xpos, (i->inter_xpos == -4) ? -1 : 0); fprintf(f, " 5 %4i %2i\n", i->inter_ypos, (i->inter_ypos == -4) ? -1 : 0); fprintf(f, " 6 %4i %2i\n", i->inter_zpos, (i->inter_zpos == -4) ? -1 : 0); fprintf(f, "\n"); fprintf(f, "Coordinates x y z\n"); fprintf(f, " Minimum %f %f %f\n", i->min_x, i->min_y, i->min_z); fprintf(f, " Maximum %f %f %f\n", i->max_x, i->max_y, i->max_z); } fprintf(f, "\n"); fprintf(f, " N BlockSize Update\n"); fprintf(f, "%6u 0 0 in x\n", i->grid_x); fprintf(f, "%6u 0 0 in y\n", i->grid_y); if(!is_2d) fprintf(f, "%6u 0 0 in z\n", i->grid_z); fprintf(f, "\n"); fprintf(f, "Coordinate Method Point_Type Algorithm Symmetry Transpose_Algorithm\n"); fprintf(f, " 1 1 1 2 0 T in x\n"); fprintf(f, " 2 1 1 2 0 T in y\n"); if(!is_2d) fprintf(f, " 3 1 1 2 0 T in z\n"); fprintf(f, "\n"); fprintf(f, " Map Manual alpha beta Map_F\n"); fprintf(f, "%6d 0 %9f %9f 0 in x\n", i->map_x, i->alpha_x, i->beta_x); fprintf(f, "%6d 0 %9f %9f 0 in y\n", i->map_y, i->alpha_y, i->beta_y); if(!is_2d) fprintf(f, "%6d 0 %9f %9f 0 in z\n", i->map_z, i->alpha_z, i->beta_z); fprintf(f, "\n"); fprintf(f, " Filter Fequency CutOff Omega Order Smooth_1/2 (Derivative)\n"); fprintf(f, " 1 1 0 0 10 1 1 in x\n"); fprintf(f, " 1 1 0 0 10 1 1 in y\n"); if(!is_2d) fprintf(f, " 1 1 0 0 10 1 1 in z\n"); fprintf(f, "\n"); fprintf(f, " Filter Frequency CutOff Omega Order Smooth_1/2 (Smoothing Q)\n"); fprintf(f, " 1 1 0 0 6 1 1 in x\n"); fprintf(f, " 1 1 0 0 6 1 1 in y\n"); if(!is_2d) fprintf(f, " 1 1 0 0 6 1 1 in z\n"); fprintf(f, "\n"); fprintf(f, " Filter Frequency CutOff Omega Order Smooth_1/2 (Smoothing T)\n"); fprintf(f, " 1 1 0 0 6 1 1 in x\n"); fprintf(f, " 1 1 0 0 6 1 1 in y\n"); if(!is_2d) fprintf(f, " 1 1 0 0 6 1 1 in z\n"); fprintf(f, "\n"); fprintf(f, " Filter Frequency CutOff Omega Order Smooth_1/2 (Smoothing R)\n"); fprintf(f, " 1 1 0 0 3 1 1 in x\n"); fprintf(f, " 1 1 0 0 3 1 1 in y\n"); if(!is_2d) fprintf(f, " 1 1 0 0 3 1 1 in z\n"); fprintf(f, "\n"); fprintf(f, " Reactive? (Chemical Model)\n"); fprintf(f, " F\n"); } fprintf(f, "\n"); fprintf(f, "=========================================================================\n"); fprintf(f, "Domain Number : -1 Active : T Type : 0\n"); fprintf(f, " Override : T Angle_0 : 0 Angle_1 : 0\n"); fprintf(f, "----------------------------------------------------------------\n"); fclose(f); return true; } return false; } void reset_camera() { std::vector::iterator i; i = domains.begin(); if(i != domains.end()) { float min_x = i->min_x, min_y = i->min_y, min_z = i->min_z; float max_x = i->max_x, max_y = i->max_y, max_z = i->max_z; i++; while(i != domains.end()) { if(i->min_x < min_x) min_x = i->min_x; if(i->min_y < min_y) min_y = i->min_y; if(i->min_z < min_z) min_z = i->min_z; if(i->max_x > max_x) max_x = i->max_x; if(i->max_y > max_y) max_y = i->max_y; if(i->max_z > max_z) max_z = i->max_z; i++; } center_x = (min_x + max_x) * -0.5f; center_y = (min_y + max_y) * -0.5f; center_z = (min_z + max_z) * -0.5f; zoom_z = sqrtf((max_x - min_x) * (max_x - min_x) + (max_y - min_y) * (max_y - min_y) + (max_z - min_z) * (max_z - min_z)) * -2.0f; } } void load() { std::vector::iterator i; if(info = XLoadQueryFont(display, "-*-times-medium-r-*--17-120-100-100-p-88-iso8859-1")) { unsigned int first, last; first = info->min_char_or_byte2; last = info->max_char_or_byte2; font = glGenLists(last + 1); glListBase(font); glXUseXFont(info->fid, first, last - first + 1, font + first); } else error("could not find font"); glDepthFunc(GL_LEQUAL); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); resize(); current_status = open(DOMAIN_FILE) ? STATUS_OPEN : STATUS_OPEN_ERROR; reset_camera(); } float distance_to(const vector_t &pos, const vector_t &vel, const domain_t &dom, unsigned int &face) { float dist_min_x = (dom.min_x - pos.x) / vel.x; float dist_max_x = (dom.max_x - pos.x) / vel.x; float dist_min_y = (dom.min_y - pos.y) / vel.y; float dist_max_y = (dom.max_y - pos.y) / vel.y; float dist_min_z = (dom.min_z - pos.z) / vel.z; float dist_max_z = (dom.max_z - pos.z) / vel.z; float x, y, z, dist = 1.0e9f; // -x if(dist_min_x > 0.0f && dist_min_x < dist) { y = pos.y + vel.y * dist_min_x; if(y > dom.min_y && y < dom.max_y) { z = pos.z + vel.z * dist_min_x; if(z > dom.min_z && z < dom.max_z) { dist = dist_min_x; face = FACE_XNEG; } } } // -y if(dist_min_y > 0.0f && dist_min_y < dist) { x = pos.x + vel.x * dist_min_y; if(x > dom.min_x && x < dom.max_x) { z = pos.z + vel.z * dist_min_y; if(z > dom.min_z && z < dom.max_z) { dist = dist_min_y; face = FACE_YNEG; } } } // -z if(dist_min_z > 0.0f && dist_min_z < dist) { x = pos.x + vel.x * dist_min_z; if(x > dom.min_x && x < dom.max_x) { y = pos.y + vel.y * dist_min_z; if(y > dom.min_y && y < dom.max_y) { dist = dist_min_z; face = FACE_ZNEG; } } } // +x if(dist_max_x > 0.0f && dist_max_x < dist) { y = pos.y + vel.y * dist_max_x; if(y > dom.min_y && y < dom.max_y) { z = pos.z + vel.z * dist_max_x; if(z > dom.min_z && z < dom.max_z) { dist = dist_max_x; face = FACE_XPOS; } } } // +y if(dist_max_y > 0.0f && dist_max_y < dist) { x = pos.x + vel.x * dist_max_y; if(x > dom.min_x && x < dom.max_x) { z = pos.z + vel.z * dist_max_y; if(z > dom.min_z && z < dom.max_z) { dist = dist_max_y; face = FACE_YPOS; } } } // +z if(dist_max_z > 0.0f && dist_max_z < dist) { x = pos.x + vel.x * dist_max_z; if(x > dom.min_x && x < dom.max_x) { y = pos.y + vel.y * dist_max_z; if(y > dom.min_y && y < dom.max_y) { dist = dist_max_z; face = FACE_ZPOS; } } } return dist; } void get_mouse_vector(int wx, int wy, vector_t &pos, vector_t &vel) { float d; int v[4]; double m[16], p[16], x, y, z; glLoadIdentity(); glTranslatef(0.0f, 0.0f, zoom_z); glRotatef(spin_x_axis, 1.0f, 0.0f, 0.0f); glRotatef(spin_y_axis, 0.0f, 1.0f, 0.0f); glTranslatef(center_x, center_y, center_z); glFinish(); glGetIntegerv(GL_VIEWPORT, v); glGetDoublev(GL_MODELVIEW_MATRIX, m); glGetDoublev(GL_PROJECTION_MATRIX, p); wy = height - wy; gluUnProject((double)wx + 0.5, (double)wy + 0.5, 0.1, m, p, v, &x, &y, &z); pos.x = x; pos.y = y; pos.z = z; gluUnProject((double)wx + 0.5, (double)wy + 0.5, 0.2, m, p, v, &x, &y, &z); vel.x = x - pos.x; vel.y = y - pos.y; vel.z = z - pos.z; d = vel.x * vel.x + vel.y * vel.y + vel.z * vel.z; if(d != 0.0f) { d = 1.0f / sqrtf(d); vel.x *= d; vel.y *= d; vel.z *= d; } } float closest_point(vector_t &point, vector_t &closest, int ignore) { std::vector::iterator i; float dist = 1.0e9f, d; float tx, ty, tz; float x, y, z; int j, corner; for(i = domains.begin(), j = 0; i != domains.end(); i++, j++) { if(j == ignore) continue; // test all 8 corners for(corner = 0; corner < 8; corner++) { tx = (corner & 1) ? i->max_x : i->min_x; ty = (corner & 2) ? i->max_y : i->min_y; tz = (corner & 4) ? i->max_z : i->min_z; x = point.x - tx; y = point.y - ty; z = point.z - tz; d = x * x + y * y + z * z; if(d < dist) { closest.x = tx; closest.y = ty; closest.z = tz; dist = d; } } } return sqrtf(dist); } bool setup_arrows(int x, int y) { vector_t pos, vel; unsigned int face, old_arrow_type = arrow_type, corner, arrow_or; float dist = 1.0e9f, temp_dist, corner_dist, tx, ty, tz; std::vector::iterator i; get_mouse_vector(x, y, pos, vel); if((moving || resizing) && selection != -1) { dist = distance_to(pos, vel, domains.at(selection), face); arrow_x = pos.x + vel.x * dist; arrow_y = pos.y + vel.y * dist; arrow_z = pos.z + vel.z * dist; } else { arrow_type = arrow_or = 0; for(i = domains.begin(); i != domains.end(); i++) { temp_dist = distance_to(pos, vel, *i, face); if(temp_dist < dist) { dist = temp_dist; arrow_type = 0; if(face == FACE_XNEG || face == FACE_XPOS) arrow_type = ARROW_X; else if(face == FACE_YNEG || face == FACE_YPOS) arrow_type = ARROW_Y; else if(face == FACE_ZNEG || face == FACE_ZPOS) arrow_type = ARROW_Z; arrow_x = pos.x + vel.x * dist; arrow_y = pos.y + vel.y * dist; arrow_z = pos.z + vel.z * dist; corner_dist = -zoom_z * 0.0003f; if(!(arrow_type & ARROW_X) && i->w * 0.5f < corner_dist) corner_dist = i->w * 0.5f; if(!(arrow_type & ARROW_Y) && i->h * 0.5f < corner_dist) corner_dist = i->h * 0.5f; if(!(arrow_type & ARROW_Z) && i->d * 0.5f < corner_dist) corner_dist = i->d * 0.5f; for(corner = 0; corner < 8; corner++) { tx = arrow_x - ((corner & 1) ? i->max_x : i->min_x); ty = arrow_y - ((corner & 2) ? i->max_y : i->min_y); tz = arrow_z - ((corner & 4) ? i->max_z : i->min_z); temp_dist = tx * tx + ty * ty + tz * tz; if(temp_dist < corner_dist) { i->temp_x = ((corner & 1) ? i->max_x : i->min_x); i->temp_y = ((corner & 2) ? i->max_y : i->min_y); i->temp_z = ((corner & 4) ? i->max_z : i->min_z); off_x = tx; off_y = ty; off_z = tz; arrow_corner = corner; if(arrow_type & ARROW_X) { if(((corner & 2) >> 1) ^ ((corner & 4) >> 2)) arrow_or = ARROW_DIAGONAL_1; else arrow_or = ARROW_DIAGONAL_2; } else if(arrow_type & ARROW_Y) { if((corner & 1) ^ ((corner & 4) >> 2)) arrow_or = ARROW_DIAGONAL_2; else arrow_or = ARROW_DIAGONAL_1; } else if(arrow_type & ARROW_Z) { if((corner & 1) ^ ((corner & 2) >> 1)) arrow_or = ARROW_DIAGONAL_2; else arrow_or = ARROW_DIAGONAL_1; } corner_dist = temp_dist; } } } } arrow_type |= arrow_or; } return (!old_arrow_type || arrow_type); } int main(int argc, char *argv[]) { if(display = XOpenDisplay(NULL)) { if(glXQueryExtension(display, NULL, NULL)) { int visual[] = { GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None}; XVisualInfo *info; if(info = glXChooseVisual(display, DefaultScreen(display), visual)) { GLXContext context; if(context = glXCreateContext(display, info, NULL, GL_TRUE)) { bool changed; int old_x, old_y; float nx, ny, nz; unsigned int old_button; float old_X, old_Y, old_Z; XSetWindowAttributes attributes; vector_t pos, vel; Time old_time = 0; XEvent event; attributes.colormap = XCreateColormap(display, RootWindow(display, info->screen), info->visual, AllocNone); attributes.border_pixel = 0; attributes.event_mask = ExposureMask | FocusChangeMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask; buttons[BUTTON_CONVERT].text = convert[is_2d]; window = XCreateWindow(display, RootWindow(display, info->screen), 0, 0, width, height, 0, info->depth, InputOutput, info->visual, CWBorderPixel | CWColormap | CWEventMask, &attributes); XSetStandardProperties(display, window, "Mesh Generation", "Mesh Generation", None, argv, argc, NULL); glXMakeCurrent(display, window, context); XMapWindow(display, window); load(); for(;;) { render(); // I needed to call render twice here when compiling on Mac OS X (the window would only refresh every other call) changed = false; do { XNextEvent(display, &event); switch(event.type) { case ButtonPress: { unsigned int button = ~0; current_status = STATUS_NONE; if(get_subdivide) break; if(event.xbutton.button == 1 || event.xbutton.button == 3) { float min_x, min_y, max_x, max_y, x = event.xbutton.x, y = (float)height - event.xbutton.y; for(button = 0; button < sizeof(buttons) / sizeof(button_t); button++) { if(is_2d && !buttons[button].is_2d) continue; else if(!is_2d && !buttons[button].is_3d) continue; else if(selection == -1 && buttons[button].is_selection) continue; min_x = buttons[button].min_x; if(min_x < 0.0f) min_x += (float)width; max_x = buttons[button].max_x; if(max_x < 0.0f) max_x += (float)width; min_y = buttons[button].min_y; if(min_y < 0.0f) min_y += (float)height; max_y = buttons[button].max_y; if(max_y < 0.0f) max_y += (float)height; if(min_x < x && x < max_x && min_y < y && y < max_y) break; } } if(button < sizeof(buttons) / sizeof(button_t)) { buttons[button].state |= STATE_PRESS; changed = true; } else if(event.xbutton.button == 1) { int n; unsigned int face, temp_face; float dist = 1.0e9f, temp_dist; std::vector::iterator i; get_mouse_vector(event.xbutton.x, event.xbutton.y, pos, vel); selection = -1; for(i = domains.begin(), n = 0; i != domains.end(); i++, n++) { temp_dist = distance_to(pos, vel, *i, temp_face); if(temp_dist < dist) { dist = temp_dist; face = temp_face; selection = n; } } if(setup_arrows(event.xmotion.x, event.xmotion.y)) changed = true; if(selection != -1) { domain_t &dom = domains.at(selection); old_X = pos.x + vel.x * dist; old_Y = pos.y + vel.y * dist; old_Z = pos.z + vel.z * dist; nx = ny = nz = 0.0f; if(face == FACE_XNEG || face == FACE_XPOS) { nx = 1.0f; move_dist = pos.x + vel.x * dist; } else if(face == FACE_YNEG || face == FACE_YPOS) { ny = 1.0f; move_dist = pos.y + vel.y * dist; } else { nz = 1.0f; move_dist = pos.z + vel.z * dist; } // insert a new domain on left double click if(old_button == 1 && old_x == event.xbutton.x && old_y == event.xbutton.y && event.xbutton.time - old_time < 500) { domain_t dom = domains.at(selection); if(is_2d) { float t = -pos.z / vel.z; float x = pos.x + vel.x * t; float y = pos.y + vel.y * t; dom.min_x = x - dom.w * 0.5f; dom.min_y = y - dom.h * 0.5f; dom.max_x = dom.min_x + dom.w; dom.max_y = dom.min_y + dom.h; } else if(face == FACE_XNEG) { dom.min_x -= dom.w; dom.max_x = dom.min_x + dom.w; } else if(face == FACE_YNEG) { dom.min_y -= dom.h; dom.max_y = dom.min_y + dom.h; } else if(face == FACE_ZNEG) { dom.min_z -= dom.d; dom.max_z = dom.min_z + dom.d; } else if(face == FACE_XPOS) { dom.min_x += dom.w; dom.max_x = dom.min_x + dom.w; } else if(face == FACE_YPOS) { dom.min_y += dom.h; dom.max_y = dom.min_y + dom.h; } else { dom.min_z += dom.d; dom.max_z = dom.min_z + dom.d; } selection = domains.size(); domains.push_back(dom); calculate_interfaces(); old_time = 0; } else if(arrow_type & (ARROW_DIAGONAL_1 | ARROW_DIAGONAL_2)) resizing = true; else { dom.temp_x = dom.temp_y = dom.temp_z = 0.0f; moving = true; } } // insert a new domain on left double click else if(old_button == 1 && old_x == event.xbutton.x && old_y == event.xbutton.y && event.xbutton.time - old_time < 500) { if(!domains.empty()) { // get the most-used values for the new domain and hopefully some of them will be right std::vector::iterator i; float t = (-center_z - pos.z) / vel.z; float x = pos.x + vel.x * t; float y = pos.y + vel.y * t; float w, h, d; unsigned int grid_x, grid_y, grid_z; vector count; vector::iterator i_count; vector float_values; vector::iterator i_float; vector uint_values; vector::iterator i_uint; unsigned int c; bool found; // grid_x for(i = domains.begin(); i != domains.end(); i++) { found = false; for(i_uint = uint_values.begin(), i_count = count.begin(); i_uint != uint_values.end(); i_uint++, i_count++) { if(*i_uint == i->grid_x) { (*i_count)++; found = true; break; } } if(!found) { uint_values.push_back(i->grid_x); count.push_back(1); } } c = 0; for(i_uint = uint_values.begin(), i_count = count.begin(); i_uint != uint_values.end(); i_uint++, i_count++) { if(*i_count > c) { c = *i_count; grid_x = *i_uint; } } uint_values.clear(); count.clear(); // grid_y for(i = domains.begin(); i != domains.end(); i++) { found = false; for(i_uint = uint_values.begin(), i_count = count.begin(); i_uint != uint_values.end(); i_uint++, i_count++) { if(*i_uint == i->grid_y) { (*i_count)++; found = true; break; } } if(!found) { uint_values.push_back(i->grid_y); count.push_back(1); } } c = 0; for(i_uint = uint_values.begin(), i_count = count.begin(); i_uint != uint_values.end(); i_uint++, i_count++) { if(*i_count > c) { c = *i_count; grid_y = *i_uint; } } uint_values.clear(); count.clear(); // grid_z for(i = domains.begin(); i != domains.end(); i++) { found = false; for(i_uint = uint_values.begin(), i_count = count.begin(); i_uint != uint_values.end(); i_uint++, i_count++) { if(*i_uint == i->grid_z) { (*i_count)++; found = true; break; } } if(!found) { uint_values.push_back(i->grid_z); count.push_back(1); } } c = 0; for(i_uint = uint_values.begin(), i_count = count.begin(); i_uint != uint_values.end(); i_uint++, i_count++) { if(*i_count > c) { c = *i_count; grid_z = *i_uint; } } uint_values.clear(); count.clear(); // w for(i = domains.begin(); i != domains.end(); i++) { found = false; for(i_float = float_values.begin(), i_count = count.begin(); i_float != float_values.end(); i_float++, i_count++) { if(equals(*i_float, i->w)) { (*i_count)++; found = true; break; } } if(!found) { float_values.push_back(i->w); count.push_back(1); } } c = 0; for(i_float = float_values.begin(), i_count = count.begin(); i_float != float_values.end(); i_float++, i_count++) { if(*i_count > c) { c = *i_count; w = *i_float; } } float_values.clear(); count.clear(); // h for(i = domains.begin(); i != domains.end(); i++) { found = false; for(i_float = float_values.begin(), i_count = count.begin(); i_float != float_values.end(); i_float++, i_count++) { if(equals(*i_float, i->h)) { (*i_count)++; found = true; break; } } if(!found) { float_values.push_back(i->h); count.push_back(1); } } c = 0; for(i_float = float_values.begin(), i_count = count.begin(); i_float != float_values.end(); i_float++, i_count++) { if(*i_count > c) { c = *i_count; h = *i_float; } } float_values.clear(); count.clear(); // d for(i = domains.begin(); i != domains.end(); i++) { found = false; for(i_float = float_values.begin(), i_count = count.begin(); i_float != float_values.end(); i_float++, i_count++) { if(equals(*i_float, i->d)) { (*i_count)++; found = true; break; } } if(!found) { float_values.push_back(i->d); count.push_back(1); } } c = 0; for(i_float = float_values.begin(), i_count = count.begin(); i_float != float_values.end(); i_float++, i_count++) { if(*i_count > c) { c = *i_count; d = *i_float; } } float_values.clear(); count.clear(); selection = domains.size(); add_domain(x - w * 0.5f, y - h * 0.5f, -center_z - d * 0.5f, x + w * 0.5f, y + h * 0.5f, -center_z + d * 0.5f, grid_x, grid_y, grid_z, -1, -1, -1, -1, -1, -1, 1, 1, 1, 0.999f, 0.999f, 0.999f, 0.0f, 0.0f, 0.0f); } else { selection = 0; add_domain(-0.01f, -0.01f, -0.01f, 0.01f, 0.01f, 0.01f, 49, 49, 49, -1, -1, -1, -1, -1, -1, 1, 1, 1, 0.999f, 0.999f, 0.999f, 0.0f, 0.0f, 0.0f); reset_camera(); } } old_button = 1; old_time = event.xbutton.time; old_x = event.xbutton.x; old_y = event.xbutton.y; changed = true; } else if(event.xbutton.button == 3) { old_x = event.xbutton.x; old_y = event.xbutton.y; spinning = true; // re-center the camera on right double click if(old_button == 3 && old_x == event.xbutton.x && old_y == event.xbutton.y && event.xbutton.time - old_time < 500) { int n; unsigned int face, temp_face; float dist = 1.0e9f, temp_dist; std::vector::iterator i; get_mouse_vector(event.xbutton.x, event.xbutton.y, pos, vel); selection = -1; for(i = domains.begin(), n = 0; i != domains.end(); i++, n++) { temp_dist = distance_to(pos, vel, *i, temp_face); if(temp_dist < dist) { dist = temp_dist; face = temp_face; selection = n; center_x = -(i->min_x + i->max_x) * 0.5f; center_y = -(i->min_y + i->max_y) * 0.5f; center_z = -(i->min_z + i->max_z) * 0.5f; } } if(selection == -1) reset_camera(); setup_arrows(event.xmotion.x, event.xmotion.y); } else { arrow_type = 0; old_button = 3; old_time = event.xbutton.time; old_x = event.xbutton.x; old_y = event.xbutton.y; } changed = true; } else if(event.xbutton.button == 4) { zoom_z *= 0.9f; changed = true; setup_arrows(event.xmotion.x, event.xmotion.y); } else if(event.xbutton.button == 5) { zoom_z /= 0.9f; changed = true; setup_arrows(event.xmotion.x, event.xmotion.y); } break; } case ButtonRelease: { unsigned int button = ~0; if(get_subdivide) break; for(button = 0; button < sizeof(buttons) / sizeof(button_t); button++) { if(buttons[button].state & STATE_PRESS) break; } if(button < sizeof(buttons) / sizeof(button_t)) { if(event.xbutton.button == 1 || event.xbutton.button == 3) { float min_x, min_y, max_x, max_y, x = event.xbutton.x, y = (float)height - event.xbutton.y; for(button = 0; button < sizeof(buttons) / sizeof(button_t); button++) { if(is_2d && !buttons[button].is_2d) continue; else if(!is_2d && !buttons[button].is_3d) continue; else if(selection == -1 && buttons[button].is_selection) continue; min_x = buttons[button].min_x; if(min_x < 0.0f) min_x += (float)width; max_x = buttons[button].max_x; if(max_x < 0.0f) max_x += (float)width; min_y = buttons[button].min_y; if(min_y < 0.0f) min_y += (float)height; max_y = buttons[button].max_y; if(max_y < 0.0f) max_y += (float)height; if(min_x < x && x < max_x && min_y < y && y < max_y) { buttons[button].state ^= STATE_TOGGLE; break; } } } for(button = 0; button < sizeof(buttons) / sizeof(button_t); button++) buttons[button].state &= ~STATE_PRESS; changed = true; } else if(event.xbutton.button == 1) { if(selection != -1) { calculate_interfaces(); changed = true; } moving = resizing = false; } else if(event.xbutton.button == 3) { if(setup_arrows(event.xmotion.x, event.xmotion.y)) changed = true; spinning = false; } break; } case MotionNotify: { if(get_subdivide) break; if(spinning) { spin_y_axis += (float)(event.xmotion.x - old_x); spin_x_axis += (float)(event.xmotion.y - old_y); if(spin_x_axis < -90.0f) spin_x_axis = -90.0f; if(spin_x_axis > 90.0f) spin_x_axis = 90.0f; spin_y_axis -= floorf(spin_y_axis / 360.0f) * 360.0f; old_x = event.xmotion.x; old_y = event.xmotion.y; changed = true; } else if(moving && selection != -1) { int corner; float dist = -zoom_z * 0.01f, d; float new_X, new_Y, new_Z; vector_t point, closest; domain_t &dom = domains.at(selection); get_mouse_vector(event.xmotion.x, event.xmotion.y, pos, vel); d = (move_dist - nx * pos.x - ny * pos.y - nz * pos.z) / (nx * vel.x + ny * vel.y + nz * vel.z); new_X = pos.x + vel.x * d; new_Y = pos.y + vel.y * d; new_Z = pos.z + vel.z * d; dom.temp_x = new_X - old_X - dom.temp_x; dom.temp_y = new_Y - old_Y - dom.temp_y; dom.temp_z = new_Z - old_Z - dom.temp_z; dom.min_x += dom.temp_x; dom.min_y += dom.temp_y; dom.min_z += dom.temp_z; dom.max_x = dom.min_x + dom.w; dom.max_y = dom.min_y + dom.h; dom.max_z = dom.min_z + dom.d; old_X = new_X; old_Y = new_Y; old_Z = new_Z; dom.temp_x = dom.temp_y = dom.temp_z = 0.0f; for(corner = 0; corner < 8; corner++) { point.x = (corner & 1) ? dom.max_x : dom.min_x; point.y = (corner & 2) ? dom.max_y : dom.min_y; point.z = (corner & 4) ? dom.max_z : dom.min_z; d = closest_point(point, closest, selection); if(d < dist) { dom.temp_x = closest.x - point.x; dom.temp_y = closest.y - point.y; dom.temp_z = closest.z - point.z; dist = d; } } dom.min_x += dom.temp_x; dom.min_y += dom.temp_y; dom.min_z += dom.temp_z; dom.max_x = dom.min_x + dom.w; dom.max_y = dom.min_y + dom.h; dom.max_z = dom.min_z + dom.d; setup_arrows(event.xmotion.x, event.xmotion.y); changed = true; } else if(resizing && selection != -1) { float d; float new_X, new_Y, new_Z; vector_t point, closest; domain_t &dom = domains.at(selection); get_mouse_vector(event.xmotion.x, event.xmotion.y, pos, vel); d = (move_dist - nx * pos.x - ny * pos.y - nz * pos.z) / (nx * vel.x + ny * vel.y + nz * vel.z); new_X = pos.x + vel.x * d; new_Y = pos.y + vel.y * d; new_Z = pos.z + vel.z * d; if(!(arrow_type & ARROW_X)) dom.temp_x = new_X - off_x; { dom.temp_x = new_X - off_x; if(arrow_corner & 1) dom.max_x = max(dom.min_x, dom.temp_x); else dom.min_x = min(dom.max_x, dom.temp_x); } if(!(arrow_type & ARROW_Y)) { dom.temp_y = new_Y - off_y; if(arrow_corner & 2) dom.max_y = max(dom.min_y, dom.temp_y); else dom.min_y = min(dom.max_y, dom.temp_y); } if(!(arrow_type & ARROW_Z)) { dom.temp_z = new_Z - off_z; if(arrow_corner & 4) dom.max_z = max(dom.min_z, dom.temp_z); else dom.min_z = min(dom.max_z, dom.temp_z); } point.x = dom.temp_x; point.y = dom.temp_y; point.z = dom.temp_z; d = closest_point(point, closest, selection); if(d < zoom_z * -0.01f) { if(arrow_corner & 1) dom.max_x = max(dom.min_x, closest.x); else dom.min_x = min(dom.max_x, closest.x); if(arrow_corner & 2) dom.max_y = max(dom.min_y, closest.y); else dom.min_y = min(dom.max_y, closest.y); if(arrow_corner & 4) dom.max_z = max(dom.min_z, closest.z); else dom.min_z = min(dom.max_z, closest.z); } if(!(arrow_type & ARROW_X)) dom.w = dom.max_x - dom.min_x; if(!(arrow_type & ARROW_Y)) dom.h = dom.max_y - dom.min_y; if(!(arrow_type & ARROW_Z)) dom.d = dom.max_z - dom.min_z; setup_arrows(event.xmotion.x, event.xmotion.y); changed = true; } else if(setup_arrows(event.xmotion.x, event.xmotion.y)) changed = true; break; } case KeyPress: { int key = XLookupKeysym(&event.xkey, 0); if(current_status != STATUS_NONE) { current_status = STATUS_NONE; changed = true; } if(get_subdivide) { if(key == XK_Return) { entering_subdivide = !entering_subdivide; if(subdivide_index == 3) { get_subdivide = false; if(subdivide_x != 1 || subdivide_y != 1 || subdivide_z != 1) { domain_t dom = domains.at(selection); float min_x = dom.min_x, min_y = dom.min_y, min_z = dom.min_z; float w = dom.w, h = dom.h, d = dom.d; unsigned int x, y, z; for(z = 0; z < subdivide_z; z++) { dom.min_z = min_z + d * (float)z / (float)subdivide_z; dom.max_z = min_z + d * (float)(z + 1) / (float)subdivide_z; dom.d = dom.max_z - dom.min_z; for(y = 0; y < subdivide_y; y++) { dom.min_y = min_y + h * (float)y / (float)subdivide_y; dom.max_y = min_y + h * (float)(y + 1) / (float)subdivide_y; dom.h = dom.max_y - dom.min_y; for(x = 0; x < subdivide_x; x++) { dom.min_x = min_x + w * (float)x / (float)subdivide_x; dom.max_x = min_x + w * (float)(x + 1) / (float)subdivide_x; dom.w = dom.max_x - dom.min_x; if(x || y || z) domains.push_back(dom); else domains.at(selection) = dom; } } } selection = -1; calculate_interfaces(); } } else if(entering_subdivide) { subdivide_length = 0; subdivide_string[0] = '\0'; } else if(subdivide_index == 0) { sscanf(subdivide_string, "%u", &subdivide_x); if(!subdivide_x) subdivide_x = 1; } else if(subdivide_index == 1) { sscanf(subdivide_string, "%u", &subdivide_y); if(!subdivide_y) subdivide_x = 1; } else if(subdivide_index == 2) { sscanf(subdivide_string, "%u", &subdivide_z); if(!subdivide_z) subdivide_x = 1; } changed = true; } else if(entering_subdivide) { if(key >= XK_0 && key <= XK_9 && subdivide_length < sizeof(subdivide_string) - 1) { subdivide_string[subdivide_length++] = key; subdivide_string[subdivide_length] = '\0'; changed = true; } else if((key == XK_Delete || key == XK_BackSpace) && subdivide_length) { subdivide_string[--subdivide_length] = '\0'; changed = true; } } else if(key == XK_Up) { if(subdivide_index-- == 0) subdivide_index = 3; changed = true; } else if(key == XK_Down) { if(subdivide_index++ == 3) subdivide_index = 0; changed = true; } } else if(key == XK_equal || key == XK_KP_Add) { zoom_z *= 0.9f; changed = true; setup_arrows(event.xmotion.x, event.xmotion.y); } else if(key == XK_minus || key == XK_KP_Subtract) { zoom_z /= 0.9f; changed = true; setup_arrows(event.xmotion.x, event.xmotion.y); } else if(selection != -1) { if(key == XK_Return) { entering_property = !entering_property; if(entering_property) { property_length = 0; *property_string = '\0'; } else if(property_length) { domain_t &dom = domains.at(selection); if(properties[property].type == TYPE_INT) sscanf(property_string, "%d", (int *)(((unsigned char *)&dom) + properties[property].offset)); else if(properties[property].type == TYPE_UINT) sscanf(property_string, "%u", (unsigned int *)(((unsigned char *)&dom) + properties[property].offset)); else if(properties[property].type == TYPE_FLOAT) sscanf(property_string, "%f", (float *)(((unsigned char *)&dom) + properties[property].offset)); dom.max_x = dom.min_x + dom.w; dom.max_y = dom.min_y + dom.h; dom.max_z = dom.min_z + dom.d; calculate_interfaces(); } changed = true; } else if(entering_property) { if(((key >= XK_0 && key <= XK_9) || (properties[property].type == TYPE_FLOAT && key == XK_period) || ((properties[property].type == TYPE_FLOAT || properties[property].type == TYPE_INT) && !property_length && key == XK_minus)) && property_length < sizeof(property_string) - 1) { property_string[property_length++] = key; property_string[property_length] = '\0'; changed = true; } else if((key == XK_Delete || key == XK_BackSpace) && property_length) { property_string[--property_length] = '\0'; changed = true; } } else { if(key == XK_Delete || key == XK_BackSpace) { int n; vector::iterator i; for(i = domains.begin(), n = 0; i != domains.end(); i++, n++) { if(selection == n) { domains.erase(i); calculate_interfaces(); selection = -1; changed = true; break; } } } else if(key == XK_Up) { do { if(!property--) property = sizeof(properties) / sizeof(property_t) - 1; } while(is_2d && !properties[property].is_2d); changed = true; } else if(key == XK_Down) { do { if(++property == sizeof(properties) / sizeof(property_t)) property = 0; } while(is_2d && !properties[property].is_2d); changed = true; } } } break; } case ConfigureNotify: { width = event.xconfigure.width; height = event.xconfigure.height; resize(); changed = true; break; } case Expose: { changed = true; break; } } if(buttons[BUTTON_CONVERT].state & STATE_TOGGLE) { vector::iterator i; float z = -zoom_z * 0.05f; is_2d = !is_2d; buttons[BUTTON_CONVERT].state &= ~STATE_TOGGLE; buttons[BUTTON_CONVERT].text = convert[is_2d]; if(is_2d) { buttons[BUTTON_GRID].state = (buttons[BUTTON_GRID].state & ~STATE_TOGGLE) | (buttons[BUTTON_ZPOS].state & STATE_TOGGLE); center_z = 0.0f; while(!properties[property].is_2d) { if(!property--) property = sizeof(properties) / sizeof(property_t) - 1; } } else { buttons[BUTTON_ZPOS].state = (buttons[BUTTON_ZPOS].state & ~STATE_TOGGLE) | (buttons[BUTTON_GRID].state & STATE_TOGGLE); center_z = z * -0.5f; } for(i = domains.begin(); i != domains.end(); i++) { if(is_2d) { i->min_z = i->max_z = i->d = 0.0f; i->grid_z = 1; i->inter_zneg = i->inter_zpos = 0; } else { i->min_z = 0.0f; i->max_z = i->d = z; } } } if(buttons[BUTTON_SUBDIVIDE].state & STATE_TOGGLE) { buttons[BUTTON_SUBDIVIDE].state &= ~STATE_TOGGLE; if(selection != -1) { get_subdivide = true; subdivide_x = subdivide_y = subdivide_z = 1; subdivide_index = 0; entering_subdivide = false; } } if(buttons[BUTTON_SAVE].state & STATE_TOGGLE) { current_status = save(DOMAIN_FILE) ? STATUS_SAVE : STATUS_SAVE_ERROR; buttons[BUTTON_SAVE].state &= ~STATE_TOGGLE; } } while(!changed || XPending(display)); } } else error("could not create a GLX context"); } else error("could not choose an RGBA visual"); } else error("could not find GLX"); } else error("could not open a display"); return 0; }