[226] | 1 | /* |
---|
| 2 | * ---------------------------------------------------------------------- |
---|
| 3 | * Nanovis: Visualization of Nanoelectronics Data |
---|
| 4 | * |
---|
| 5 | * ====================================================================== |
---|
| 6 | * AUTHOR: Wei Qiao <qiaow@purdue.edu> |
---|
[427] | 7 | * Michael McLennan <mmclennan@purdue.edu> |
---|
[226] | 8 | * Purdue Rendering and Perceptualization Lab (PURPL) |
---|
| 9 | * |
---|
| 10 | * Copyright (c) 2004-2006 Purdue Research Foundation |
---|
| 11 | * |
---|
| 12 | * See the file "license.terms" for information on usage and |
---|
| 13 | * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
| 14 | * ====================================================================== |
---|
| 15 | */ |
---|
[379] | 16 | |
---|
[364] | 17 | #include <stdio.h> |
---|
| 18 | #include <math.h> |
---|
| 19 | #include <fstream> |
---|
| 20 | #include <iostream> |
---|
[427] | 21 | #include <sstream> |
---|
[364] | 22 | #include <string> |
---|
[391] | 23 | #include <sys/time.h> |
---|
[445] | 24 | #include <sys/types.h> |
---|
| 25 | #include <unistd.h> |
---|
| 26 | #include <fcntl.h> |
---|
[260] | 27 | |
---|
[226] | 28 | #include "nanovis.h" |
---|
[445] | 29 | #include "RpField1D.h" |
---|
[364] | 30 | #include "RpFieldRect3D.h" |
---|
[372] | 31 | #include "RpFieldPrism3D.h" |
---|
[226] | 32 | |
---|
[380] | 33 | //transfer function headers |
---|
[379] | 34 | #include "transfer-function/TransferFunctionMain.h" |
---|
| 35 | #include "transfer-function/ControlPoint.h" |
---|
| 36 | #include "transfer-function/TransferFunctionGLUTWindow.h" |
---|
| 37 | #include "transfer-function/ColorGradientGLUTWindow.h" |
---|
| 38 | #include "transfer-function/ColorPaletteWindow.h" |
---|
| 39 | #include "transfer-function/MainWindow.h" |
---|
| 40 | |
---|
[383] | 41 | //render server |
---|
| 42 | |
---|
[406] | 43 | VolumeRenderer* vol_render; |
---|
[431] | 44 | PlaneRenderer* plane_render; |
---|
[404] | 45 | Camera* cam; |
---|
[406] | 46 | |
---|
[434] | 47 | //if true nanovis renders volumes in 3D, if not renders 2D plane |
---|
[448] | 48 | bool volume_mode = true; |
---|
[431] | 49 | |
---|
[427] | 50 | // color table for built-in transfer function editor |
---|
[380] | 51 | float color_table[256][4]; |
---|
[379] | 52 | |
---|
[427] | 53 | // default transfer function |
---|
[445] | 54 | char *def_transfunc = "transfunc define default {\n\ |
---|
[451] | 55 | 0.0 1 1 1\n\ |
---|
| 56 | 0.2 1 1 0\n\ |
---|
| 57 | 0.4 0 1 0\n\ |
---|
| 58 | 0.6 0 1 1\n\ |
---|
| 59 | 0.8 0 0 1\n\ |
---|
| 60 | 1.0 1 0 1\n\ |
---|
| 61 | } {\n\ |
---|
| 62 | 0.00 1.0\n\ |
---|
| 63 | 0.05 0.0\n\ |
---|
| 64 | 0.15 0.0\n\ |
---|
| 65 | 0.20 1.0\n\ |
---|
| 66 | 0.25 0.0\n\ |
---|
| 67 | 0.35 0.0\n\ |
---|
| 68 | 0.40 1.0\n\ |
---|
| 69 | 0.45 0.0\n\ |
---|
| 70 | 0.55 0.0\n\ |
---|
| 71 | 0.60 1.0\n\ |
---|
| 72 | 0.65 0.0\n\ |
---|
| 73 | 0.75 0.0\n\ |
---|
| 74 | 0.80 1.0\n\ |
---|
| 75 | 0.85 0.0\n\ |
---|
| 76 | 0.95 0.0\n\ |
---|
| 77 | 1.00 1.0\n\ |
---|
[445] | 78 | }"; |
---|
[427] | 79 | |
---|
[383] | 80 | #ifdef XINETD |
---|
| 81 | FILE* xinetd_log; |
---|
| 82 | #endif |
---|
| 83 | |
---|
| 84 | FILE* event_log; |
---|
| 85 | //log |
---|
| 86 | void init_event_log(); |
---|
| 87 | void end_event_log(); |
---|
[391] | 88 | double cur_time; //in seconds |
---|
| 89 | double get_time_interval(); |
---|
[383] | 90 | |
---|
[380] | 91 | int render_window; //the handle of the render window; |
---|
[378] | 92 | // forward declarations |
---|
| 93 | void init_particles(); |
---|
| 94 | void get_slice_vectors(); |
---|
[445] | 95 | Rappture::Outcome load_volume_file(int index, char *fname); |
---|
[455] | 96 | void load_volume(int index, int width, int height, int depth, int n_component, float* data, double vmin, double vmax); |
---|
[445] | 97 | TransferFunction* get_transfunc(char *name); |
---|
[455] | 98 | void resize_offscreen_buffer(int w, int h); |
---|
[457] | 99 | void offscreen_buffer_capture(); |
---|
[455] | 100 | void bmp_header_add_int(unsigned char* header, int& pos, int data); |
---|
| 101 | void bmp_write(const char* cmd); |
---|
[378] | 102 | |
---|
[273] | 103 | ParticleSystem* psys; |
---|
[274] | 104 | float psys_x=0.4, psys_y=0, psys_z=0; |
---|
[226] | 105 | |
---|
[397] | 106 | Lic* lic; |
---|
| 107 | |
---|
[445] | 108 | //frame buffer for final rendering |
---|
[427] | 109 | unsigned char* screen_buffer = NULL; |
---|
[445] | 110 | NVISid final_fbo, final_color_tex, final_depth_rb; |
---|
[226] | 111 | |
---|
| 112 | bool advect=false; |
---|
| 113 | float vert[NMESH*NMESH*3]; //particle positions in main memory |
---|
| 114 | float slice_vector[NMESH*NMESH*4]; //per slice vectors in main memory |
---|
| 115 | |
---|
| 116 | int n_volumes = 0; |
---|
[445] | 117 | // pointers to volumes, currently handle up to 10 volumes |
---|
[457] | 118 | vector<Volume*> volume; |
---|
| 119 | |
---|
[445] | 120 | // maps transfunc name to TransferFunction object |
---|
| 121 | Tcl_HashTable tftable; |
---|
[226] | 122 | |
---|
[445] | 123 | // pointers to 2D planes, currently handle up 10 |
---|
| 124 | Texture2D* plane[10]; |
---|
| 125 | |
---|
[458] | 126 | // value indicates "up" axis: x=1, y=2, z=3, -x=-1, -y=-2, -z=-3 |
---|
| 127 | int updir = 2; |
---|
| 128 | |
---|
[377] | 129 | PerfQuery* perf; //perfromance counter |
---|
[226] | 130 | |
---|
| 131 | //Nvidia CG shaders and their parameters |
---|
| 132 | CGcontext g_context; |
---|
| 133 | |
---|
| 134 | CGprogram m_passthru_fprog; |
---|
| 135 | CGparameter m_passthru_scale_param, m_passthru_bias_param; |
---|
| 136 | |
---|
| 137 | CGprogram m_copy_texcoord_fprog; |
---|
| 138 | |
---|
| 139 | CGprogram m_one_volume_fprog; |
---|
| 140 | CGparameter m_vol_one_volume_param; |
---|
[380] | 141 | CGparameter m_tf_one_volume_param; |
---|
[226] | 142 | CGparameter m_mvi_one_volume_param; |
---|
[386] | 143 | CGparameter m_mv_one_volume_param; |
---|
[226] | 144 | CGparameter m_render_param_one_volume_param; |
---|
| 145 | |
---|
| 146 | CGprogram m_vert_std_vprog; |
---|
| 147 | CGparameter m_mvp_vert_std_param; |
---|
| 148 | CGparameter m_mvi_vert_std_param; |
---|
| 149 | |
---|
| 150 | using namespace std; |
---|
| 151 | |
---|
[383] | 152 | |
---|
[226] | 153 | // Tcl interpreter for incoming messages |
---|
| 154 | static Tcl_Interp *interp; |
---|
[445] | 155 | static Tcl_DString cmdbuffer; |
---|
[226] | 156 | |
---|
[427] | 157 | static int CameraCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
| 158 | static int CutplaneCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
[455] | 159 | static int LegendCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
[434] | 160 | static int ScreenCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
[445] | 161 | static int TransfuncCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
[458] | 162 | static int UpCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
[434] | 163 | static int VolumeCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
[458] | 164 | |
---|
[432] | 165 | static int PlaneNewCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
| 166 | static int PlaneLinkCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
| 167 | static int PlaneEnableCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])); |
---|
[427] | 168 | |
---|
[457] | 169 | static int GetVolumeIndices _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST84 char *argv[], vector<int>* vectorPtr)); |
---|
[434] | 170 | static int GetAxis _ANSI_ARGS_((Tcl_Interp *interp, char *str, int *valPtr)); |
---|
| 171 | static int GetColor _ANSI_ARGS_((Tcl_Interp *interp, char *str, float *rgbPtr)); |
---|
[427] | 172 | |
---|
| 173 | /* |
---|
| 174 | * ---------------------------------------------------------------------- |
---|
| 175 | * CLIENT COMMAND: |
---|
| 176 | * camera aim <x0> <y0> <z0> |
---|
| 177 | * camera angle <xAngle> <yAngle> <zAngle> |
---|
| 178 | * camera zoom <factor> |
---|
| 179 | * |
---|
| 180 | * Clients send these commands to manipulate the camera. The "angle" |
---|
| 181 | * operation controls the angle of the camera around the focal point. |
---|
| 182 | * The "zoom" operation sets the zoom factor, moving the camera in |
---|
| 183 | * and out. |
---|
| 184 | * ---------------------------------------------------------------------- |
---|
| 185 | */ |
---|
[383] | 186 | static int |
---|
| 187 | CameraCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]) |
---|
| 188 | { |
---|
[427] | 189 | if (argc < 2) { |
---|
| 190 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 191 | " option arg arg...\"", (char*)NULL); |
---|
| 192 | return TCL_ERROR; |
---|
| 193 | } |
---|
[226] | 194 | |
---|
[427] | 195 | char c = *argv[1]; |
---|
| 196 | if (c == 'a' && strcmp(argv[1],"angle") == 0) { |
---|
| 197 | if (argc != 5) { |
---|
| 198 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 199 | " angle xangle yangle zangle\"", (char*)NULL); |
---|
| 200 | return TCL_ERROR; |
---|
| 201 | } |
---|
[383] | 202 | |
---|
[427] | 203 | double xangle, yangle, zangle; |
---|
| 204 | if (Tcl_GetDouble(interp, argv[2], &xangle) != TCL_OK) { |
---|
| 205 | return TCL_ERROR; |
---|
| 206 | } |
---|
| 207 | if (Tcl_GetDouble(interp, argv[3], &yangle) != TCL_OK) { |
---|
| 208 | return TCL_ERROR; |
---|
| 209 | } |
---|
| 210 | if (Tcl_GetDouble(interp, argv[4], &zangle) != TCL_OK) { |
---|
| 211 | return TCL_ERROR; |
---|
| 212 | } |
---|
| 213 | cam->rotate(xangle, yangle, zangle); |
---|
| 214 | |
---|
| 215 | return TCL_OK; |
---|
[383] | 216 | } |
---|
[427] | 217 | else if (c == 'a' && strcmp(argv[1],"aim") == 0) { |
---|
| 218 | if (argc != 5) { |
---|
| 219 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 220 | " aim x y z\"", (char*)NULL); |
---|
| 221 | return TCL_ERROR; |
---|
| 222 | } |
---|
| 223 | |
---|
| 224 | double x0, y0, z0; |
---|
| 225 | if (Tcl_GetDouble(interp, argv[2], &x0) != TCL_OK) { |
---|
| 226 | return TCL_ERROR; |
---|
| 227 | } |
---|
| 228 | if (Tcl_GetDouble(interp, argv[3], &y0) != TCL_OK) { |
---|
| 229 | return TCL_ERROR; |
---|
| 230 | } |
---|
| 231 | if (Tcl_GetDouble(interp, argv[4], &z0) != TCL_OK) { |
---|
| 232 | return TCL_ERROR; |
---|
| 233 | } |
---|
| 234 | cam->aim(x0, y0, z0); |
---|
| 235 | |
---|
| 236 | return TCL_OK; |
---|
[383] | 237 | } |
---|
[427] | 238 | else if (c == 'z' && strcmp(argv[1],"zoom") == 0) { |
---|
| 239 | if (argc != 3) { |
---|
| 240 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 241 | " zoom factor\"", (char*)NULL); |
---|
| 242 | return TCL_ERROR; |
---|
| 243 | } |
---|
[426] | 244 | |
---|
[427] | 245 | double zoom; |
---|
| 246 | if (Tcl_GetDouble(interp, argv[2], &zoom) != TCL_OK) { |
---|
| 247 | return TCL_ERROR; |
---|
| 248 | } |
---|
| 249 | |
---|
| 250 | live_obj_z = -2.5/zoom; |
---|
| 251 | cam->move(live_obj_x, live_obj_y, live_obj_z); |
---|
| 252 | |
---|
| 253 | return TCL_OK; |
---|
| 254 | } |
---|
| 255 | |
---|
| 256 | Tcl_AppendResult(interp, "bad option \"", argv[1], |
---|
| 257 | "\": should be aim, angle, or zoom", (char*)NULL); |
---|
| 258 | return TCL_ERROR; |
---|
[385] | 259 | } |
---|
| 260 | |
---|
[427] | 261 | /* |
---|
| 262 | * ---------------------------------------------------------------------- |
---|
| 263 | * CLIENT COMMAND: |
---|
| 264 | * cutplane state on|off <axis> ?<volume>...? |
---|
| 265 | * cutplane position <relvalue> <axis> ?<volume>...? |
---|
| 266 | * |
---|
| 267 | * Clients send these commands to manipulate the cutplanes in one or |
---|
| 268 | * more data volumes. The "state" command turns a cutplane on or |
---|
| 269 | * off. The "position" command changes the position to a relative |
---|
| 270 | * value in the range 0-1. The <axis> can be x, y, or z. These |
---|
| 271 | * operations are applied to the volumes represented by one or more |
---|
| 272 | * <volume> indices. If no volumes are specified, then all volumes |
---|
| 273 | * are updated. |
---|
| 274 | * ---------------------------------------------------------------------- |
---|
| 275 | */ |
---|
| 276 | static int |
---|
| 277 | CutplaneCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]) |
---|
| 278 | { |
---|
| 279 | if (argc < 2) { |
---|
| 280 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 281 | " option ?arg arg...?\"", (char*)NULL); |
---|
| 282 | return TCL_ERROR; |
---|
| 283 | } |
---|
[385] | 284 | |
---|
[427] | 285 | char c = *argv[1]; |
---|
| 286 | if (c == 's' && strcmp(argv[1],"state") == 0) { |
---|
| 287 | if (argc < 4) { |
---|
| 288 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 289 | " state on|off axis ?volume ...? \"", (char*)NULL); |
---|
| 290 | return TCL_ERROR; |
---|
| 291 | } |
---|
| 292 | |
---|
| 293 | int state; |
---|
| 294 | if (Tcl_GetBoolean(interp, argv[2], &state) != TCL_OK) { |
---|
| 295 | return TCL_ERROR; |
---|
| 296 | } |
---|
| 297 | |
---|
| 298 | int axis; |
---|
[448] | 299 | if (GetAxis(interp, (char*) argv[3], &axis) != TCL_OK) { |
---|
[427] | 300 | return TCL_ERROR; |
---|
| 301 | } |
---|
| 302 | |
---|
[457] | 303 | vector<int> ivol; |
---|
| 304 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 305 | return TCL_ERROR; |
---|
| 306 | } |
---|
| 307 | |
---|
| 308 | vector<int>::iterator iter = ivol.begin(); |
---|
| 309 | while (iter != ivol.end()) { |
---|
| 310 | if (state) { |
---|
| 311 | volume[*iter]->enable_cutplane(axis); |
---|
| 312 | } else { |
---|
| 313 | volume[*iter]->disable_cutplane(axis); |
---|
[427] | 314 | } |
---|
[457] | 315 | ++iter; |
---|
[427] | 316 | } |
---|
| 317 | return TCL_OK; |
---|
| 318 | } |
---|
| 319 | else if (c == 'p' && strcmp(argv[1],"position") == 0) { |
---|
| 320 | if (argc < 4) { |
---|
| 321 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 322 | " position relval axis ?volume ...? \"", (char*)NULL); |
---|
| 323 | return TCL_ERROR; |
---|
| 324 | } |
---|
| 325 | |
---|
| 326 | double relval; |
---|
| 327 | if (Tcl_GetDouble(interp, argv[2], &relval) != TCL_OK) { |
---|
| 328 | return TCL_ERROR; |
---|
| 329 | } |
---|
[434] | 330 | // keep this just inside the volume so it doesn't disappear |
---|
| 331 | if (relval < 0.01) { relval = 0.01; } |
---|
| 332 | if (relval > 0.99) { relval = 0.99; } |
---|
[427] | 333 | |
---|
| 334 | int axis; |
---|
[448] | 335 | if (GetAxis(interp, (char*) argv[3], &axis) != TCL_OK) { |
---|
[427] | 336 | return TCL_ERROR; |
---|
| 337 | } |
---|
| 338 | |
---|
[457] | 339 | vector<int> ivol; |
---|
| 340 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 341 | return TCL_ERROR; |
---|
[427] | 342 | } |
---|
[457] | 343 | |
---|
| 344 | vector<int>::iterator iter = ivol.begin(); |
---|
| 345 | while (iter != ivol.end()) { |
---|
| 346 | volume[*iter]->move_cutplane(axis, (float)relval); |
---|
| 347 | ++iter; |
---|
| 348 | } |
---|
[427] | 349 | return TCL_OK; |
---|
| 350 | } |
---|
| 351 | |
---|
| 352 | Tcl_AppendResult(interp, "bad option \"", argv[1], |
---|
| 353 | "\": should be position or state", (char*)NULL); |
---|
| 354 | return TCL_ERROR; |
---|
| 355 | } |
---|
| 356 | |
---|
[455] | 357 | /* |
---|
| 358 | * ---------------------------------------------------------------------- |
---|
| 359 | * CLIENT COMMAND: |
---|
| 360 | * legend <volumeIndex> <width> <height> |
---|
| 361 | * |
---|
| 362 | * Clients use this to generate a legend image for the specified |
---|
| 363 | * transfer function. The legend image is a color gradient from 0 |
---|
| 364 | * to one, drawn in the given transfer function. The resulting image |
---|
| 365 | * is returned in the size <width> x <height>. |
---|
| 366 | * ---------------------------------------------------------------------- |
---|
| 367 | */ |
---|
[385] | 368 | static int |
---|
[455] | 369 | LegendCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]) |
---|
[423] | 370 | { |
---|
[455] | 371 | if (argc != 4) { |
---|
| 372 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 373 | " transfunc width height\"", (char*)NULL); |
---|
| 374 | return TCL_ERROR; |
---|
| 375 | } |
---|
[423] | 376 | |
---|
[455] | 377 | TransferFunction *tf = NULL; |
---|
| 378 | int ivol; |
---|
| 379 | if (Tcl_GetInt(interp, argv[1], &ivol) != TCL_OK) { |
---|
| 380 | return TCL_ERROR; |
---|
| 381 | } |
---|
| 382 | if (ivol < n_volumes) { |
---|
| 383 | tf = vol_render->get_volume_shading(volume[ivol]); |
---|
| 384 | } |
---|
| 385 | if (tf == NULL) { |
---|
| 386 | Tcl_AppendResult(interp, "transfer function not defined for volume ", argv[1], (char*)NULL); |
---|
| 387 | return TCL_ERROR; |
---|
| 388 | } |
---|
[423] | 389 | |
---|
[455] | 390 | int old_width = win_width; |
---|
| 391 | int old_height = win_height; |
---|
[423] | 392 | |
---|
[455] | 393 | int width, height; |
---|
| 394 | if (Tcl_GetInt(interp, argv[2], &width) != TCL_OK) { |
---|
| 395 | return TCL_ERROR; |
---|
| 396 | } |
---|
| 397 | if (Tcl_GetInt(interp, argv[3], &height) != TCL_OK) { |
---|
| 398 | return TCL_ERROR; |
---|
| 399 | } |
---|
| 400 | |
---|
[457] | 401 | plane_render->set_screen_size(width, height); |
---|
[455] | 402 | resize_offscreen_buffer(width, height); |
---|
| 403 | |
---|
| 404 | // generate data for the legend |
---|
| 405 | float data[512]; |
---|
| 406 | for (int i=0; i < 256; i++) { |
---|
| 407 | data[i] = data[i+256] = (float)(i/255.0); |
---|
| 408 | } |
---|
| 409 | plane[0] = new Texture2D(256, 2, GL_FLOAT, GL_LINEAR, 1, data); |
---|
| 410 | int index = plane_render->add_plane(plane[0], tf); |
---|
| 411 | plane_render->set_active_plane(index); |
---|
[457] | 412 | |
---|
| 413 | offscreen_buffer_capture(); |
---|
| 414 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen |
---|
[455] | 415 | plane_render->render(); |
---|
| 416 | |
---|
| 417 | glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer); |
---|
| 418 | |
---|
| 419 | std::ostringstream result; |
---|
| 420 | result << "nv>legend " << argv[1]; |
---|
| 421 | result << " " << volume[ivol]->range_min(); |
---|
| 422 | result << " " << volume[ivol]->range_max(); |
---|
| 423 | bmp_write(result.str().c_str()); |
---|
| 424 | write(0, "\n", 1); |
---|
| 425 | |
---|
| 426 | plane_render->remove_plane(index); |
---|
| 427 | resize_offscreen_buffer(old_width, old_height); |
---|
| 428 | |
---|
| 429 | return TCL_OK; |
---|
[423] | 430 | } |
---|
| 431 | |
---|
| 432 | |
---|
[455] | 433 | |
---|
| 434 | /* |
---|
| 435 | * ---------------------------------------------------------------------- |
---|
| 436 | * CLIENT COMMAND: |
---|
| 437 | * screen <width> <height> |
---|
| 438 | * |
---|
| 439 | * Clients send this command to set the size of the rendering area. |
---|
| 440 | * Future images are generated at the specified width/height. |
---|
| 441 | * ---------------------------------------------------------------------- |
---|
| 442 | */ |
---|
[423] | 443 | static int |
---|
[455] | 444 | ScreenCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]) |
---|
[385] | 445 | { |
---|
[455] | 446 | int w, h; |
---|
[385] | 447 | |
---|
[455] | 448 | if (argc != 3) { |
---|
| 449 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 450 | " width height\"", (char*)NULL); |
---|
| 451 | return TCL_ERROR; |
---|
| 452 | } |
---|
| 453 | if (Tcl_GetInt(interp, argv[1], &w) != TCL_OK) { |
---|
| 454 | return TCL_ERROR; |
---|
| 455 | } |
---|
| 456 | if (Tcl_GetInt(interp, argv[2], &h) != TCL_OK) { |
---|
| 457 | return TCL_ERROR; |
---|
| 458 | } |
---|
| 459 | resize_offscreen_buffer(w, h); |
---|
| 460 | |
---|
| 461 | return TCL_OK; |
---|
[445] | 462 | } |
---|
[423] | 463 | |
---|
[445] | 464 | /* |
---|
| 465 | * ---------------------------------------------------------------------- |
---|
| 466 | * CLIENT COMMAND: |
---|
[451] | 467 | * transfunc define <name> <colormap> <alphamap> |
---|
| 468 | * where <colormap> = { <v> <r> <g> <b> ... } |
---|
| 469 | * <alphamap> = { <v> <w> ... } |
---|
[445] | 470 | * |
---|
| 471 | * Clients send these commands to manipulate the transfer functions. |
---|
| 472 | * ---------------------------------------------------------------------- |
---|
| 473 | */ |
---|
[423] | 474 | static int |
---|
[445] | 475 | TransfuncCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]) |
---|
[423] | 476 | { |
---|
[445] | 477 | if (argc < 2) { |
---|
| 478 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 479 | " option arg arg...\"", (char*)NULL); |
---|
| 480 | return TCL_ERROR; |
---|
| 481 | } |
---|
[423] | 482 | |
---|
[445] | 483 | char c = *argv[1]; |
---|
| 484 | if (c == 'd' && strcmp(argv[1],"define") == 0) { |
---|
[451] | 485 | if (argc != 5) { |
---|
[445] | 486 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
[451] | 487 | argv[1], " define name colormap alphamap\"", (char*)NULL); |
---|
[445] | 488 | return TCL_ERROR; |
---|
| 489 | } |
---|
[423] | 490 | |
---|
[445] | 491 | // decode the data and store in a series of fields |
---|
| 492 | Rappture::Field1D rFunc, gFunc, bFunc, wFunc; |
---|
[451] | 493 | int cmapc, wmapc, i, j; |
---|
| 494 | char **cmapv, **wmapv; |
---|
[423] | 495 | |
---|
[451] | 496 | if (Tcl_SplitList(interp, argv[3], &cmapc, &cmapv) != TCL_OK) { |
---|
[445] | 497 | return TCL_ERROR; |
---|
| 498 | } |
---|
[451] | 499 | if (cmapc % 4 != 0) { |
---|
| 500 | Tcl_Free((char*)cmapv); |
---|
| 501 | Tcl_AppendResult(interp, "bad colormap in transfunc: should be ", |
---|
| 502 | "{ v r g b ... }", (char*)NULL); |
---|
[445] | 503 | return TCL_ERROR; |
---|
| 504 | } |
---|
[423] | 505 | |
---|
[451] | 506 | if (Tcl_SplitList(interp, argv[4], &wmapc, &wmapv) != TCL_OK) { |
---|
| 507 | return TCL_ERROR; |
---|
| 508 | } |
---|
| 509 | if (wmapc % 2 != 0) { |
---|
| 510 | Tcl_Free((char*)cmapv); |
---|
| 511 | Tcl_Free((char*)wmapv); |
---|
| 512 | Tcl_AppendResult(interp, "bad alphamap in transfunc: should be ", |
---|
| 513 | "{ v w ... }", (char*)NULL); |
---|
| 514 | return TCL_ERROR; |
---|
| 515 | } |
---|
| 516 | |
---|
| 517 | for (i=0; i < cmapc; i += 4) { |
---|
| 518 | double vals[4]; |
---|
| 519 | for (j=0; j < 4; j++) { |
---|
| 520 | if (Tcl_GetDouble(interp, cmapv[i+j], &vals[j]) != TCL_OK) { |
---|
| 521 | Tcl_Free((char*)cmapv); |
---|
| 522 | Tcl_Free((char*)wmapv); |
---|
[445] | 523 | return TCL_ERROR; |
---|
| 524 | } |
---|
| 525 | if (vals[j] < 0 || vals[j] > 1) { |
---|
[451] | 526 | Tcl_Free((char*)cmapv); |
---|
| 527 | Tcl_Free((char*)wmapv); |
---|
| 528 | Tcl_AppendResult(interp, "bad value \"", cmapv[i+j], |
---|
[445] | 529 | "\": should be in the range 0-1", (char*)NULL); |
---|
| 530 | return TCL_ERROR; |
---|
| 531 | } |
---|
| 532 | } |
---|
| 533 | rFunc.define(vals[0], vals[1]); |
---|
| 534 | gFunc.define(vals[0], vals[2]); |
---|
| 535 | bFunc.define(vals[0], vals[3]); |
---|
| 536 | } |
---|
[426] | 537 | |
---|
[451] | 538 | for (i=0; i < wmapc; i += 2) { |
---|
| 539 | double vals[2]; |
---|
| 540 | for (j=0; j < 2; j++) { |
---|
| 541 | if (Tcl_GetDouble(interp, wmapv[i+j], &vals[j]) != TCL_OK) { |
---|
| 542 | Tcl_Free((char*)cmapv); |
---|
| 543 | Tcl_Free((char*)wmapv); |
---|
| 544 | return TCL_ERROR; |
---|
| 545 | } |
---|
| 546 | if (vals[j] < 0 || vals[j] > 1) { |
---|
| 547 | Tcl_Free((char*)cmapv); |
---|
| 548 | Tcl_Free((char*)wmapv); |
---|
| 549 | Tcl_AppendResult(interp, "bad value \"", wmapv[i+j], |
---|
| 550 | "\": should be in the range 0-1", (char*)NULL); |
---|
| 551 | return TCL_ERROR; |
---|
| 552 | } |
---|
| 553 | } |
---|
| 554 | wFunc.define(vals[0], vals[1]); |
---|
| 555 | } |
---|
| 556 | Tcl_Free((char*)cmapv); |
---|
| 557 | Tcl_Free((char*)wmapv); |
---|
| 558 | |
---|
[445] | 559 | // sample the given function into discrete slots |
---|
| 560 | const int nslots = 256; |
---|
| 561 | float data[4*nslots]; |
---|
| 562 | for (i=0; i < nslots; i++) { |
---|
| 563 | double xval = double(i)/(nslots-1); |
---|
| 564 | data[4*i] = rFunc.value(xval); |
---|
| 565 | data[4*i+1] = gFunc.value(xval); |
---|
| 566 | data[4*i+2] = bFunc.value(xval); |
---|
| 567 | data[4*i+3] = wFunc.value(xval); |
---|
| 568 | } |
---|
[426] | 569 | |
---|
[445] | 570 | // find or create this transfer function |
---|
| 571 | int newEntry; |
---|
| 572 | Tcl_HashEntry *entryPtr; |
---|
| 573 | TransferFunction *tf; |
---|
[426] | 574 | |
---|
[445] | 575 | entryPtr = Tcl_CreateHashEntry(&tftable, argv[2], &newEntry); |
---|
| 576 | if (newEntry) { |
---|
| 577 | tf = new TransferFunction(nslots, data); |
---|
| 578 | Tcl_SetHashValue(entryPtr, (ClientData)tf); |
---|
| 579 | } else { |
---|
| 580 | tf = (TransferFunction*)Tcl_GetHashValue(entryPtr); |
---|
| 581 | tf->update(data); |
---|
| 582 | } |
---|
[426] | 583 | |
---|
[445] | 584 | return TCL_OK; |
---|
| 585 | } |
---|
| 586 | Tcl_AppendResult(interp, "bad option \"", argv[1], |
---|
| 587 | "\": should be define", (char*)NULL); |
---|
[426] | 588 | return TCL_ERROR; |
---|
[423] | 589 | } |
---|
| 590 | |
---|
[434] | 591 | /* |
---|
| 592 | * ---------------------------------------------------------------------- |
---|
| 593 | * CLIENT COMMAND: |
---|
[458] | 594 | * up axis |
---|
| 595 | * |
---|
| 596 | * Clients use this to set the "up" direction for all volumes. Volumes |
---|
| 597 | * are oriented such that this direction points upward. |
---|
| 598 | * ---------------------------------------------------------------------- |
---|
| 599 | */ |
---|
| 600 | static int |
---|
| 601 | UpCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]) |
---|
| 602 | { |
---|
| 603 | if (argc != 2) { |
---|
| 604 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 605 | " x|y|z|-x|-y|-z\"", (char*)NULL); |
---|
| 606 | return TCL_ERROR; |
---|
| 607 | } |
---|
| 608 | |
---|
| 609 | int sign = 1; |
---|
| 610 | char *axisName = argv[1]; |
---|
| 611 | if (*axisName == '-') { |
---|
| 612 | sign = -1; |
---|
| 613 | axisName++; |
---|
| 614 | } |
---|
| 615 | |
---|
| 616 | int axis; |
---|
| 617 | if (GetAxis(interp, axisName, &axis) != TCL_OK) { |
---|
| 618 | return TCL_ERROR; |
---|
| 619 | } |
---|
| 620 | |
---|
| 621 | updir = (axis+1)*sign; |
---|
| 622 | |
---|
| 623 | return TCL_OK; |
---|
| 624 | } |
---|
| 625 | |
---|
| 626 | /* |
---|
| 627 | * ---------------------------------------------------------------------- |
---|
| 628 | * CLIENT COMMAND: |
---|
[449] | 629 | * volume axis label x|y|z <value> ?<volumeId> ...? |
---|
[445] | 630 | * volume data state on|off ?<volumeId> ...? |
---|
[434] | 631 | * volume outline state on|off ?<volumeId> ...? |
---|
| 632 | * volume outline color on|off ?<volumeId> ...? |
---|
[451] | 633 | * volume shading transfunc <name> ?<volumeId> ...? |
---|
[445] | 634 | * volume shading diffuse <value> ?<volumeId> ...? |
---|
| 635 | * volume shading specular <value> ?<volumeId> ...? |
---|
| 636 | * volume shading opacity <value> ?<volumeId> ...? |
---|
| 637 | * volume state on|off ?<volumeId> ...? |
---|
[434] | 638 | * |
---|
| 639 | * Clients send these commands to manipulate the volumes. |
---|
| 640 | * ---------------------------------------------------------------------- |
---|
| 641 | */ |
---|
[426] | 642 | static int |
---|
[434] | 643 | VolumeCmd(ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[]) |
---|
| 644 | { |
---|
[449] | 645 | if (argc < 2) { |
---|
| 646 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 647 | " option arg arg...\"", (char*)NULL); |
---|
| 648 | return TCL_ERROR; |
---|
[434] | 649 | } |
---|
| 650 | |
---|
| 651 | char c = *argv[1]; |
---|
[449] | 652 | if (c == 'a' && strcmp(argv[1],"axis") == 0) { |
---|
[434] | 653 | if (argc < 3) { |
---|
[449] | 654 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 655 | argv[1], " option ?arg arg...?\"", (char*)NULL); |
---|
| 656 | return TCL_ERROR; |
---|
[434] | 657 | } |
---|
| 658 | c = *argv[2]; |
---|
[449] | 659 | if (c == 'l' && strcmp(argv[2],"label") == 0) { |
---|
[445] | 660 | if (argc < 4) { |
---|
[449] | 661 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 662 | argv[1], " label x|y|z string ?volume ...?\"", (char*)NULL); |
---|
| 663 | return TCL_ERROR; |
---|
[445] | 664 | } |
---|
| 665 | |
---|
[449] | 666 | int axis; |
---|
| 667 | if (GetAxis(interp, argv[3], &axis) != TCL_OK) { |
---|
| 668 | return TCL_ERROR; |
---|
| 669 | } |
---|
| 670 | |
---|
[457] | 671 | vector<int> ivol; |
---|
| 672 | if (GetVolumeIndices(interp, argc-5, argv+5, &ivol) != TCL_OK) { |
---|
| 673 | return TCL_ERROR; |
---|
[449] | 674 | } |
---|
[457] | 675 | |
---|
| 676 | vector<int>::iterator iter = ivol.begin(); |
---|
| 677 | while (iter != ivol.end()) { |
---|
| 678 | volume[*iter]->set_label(axis, argv[4]); |
---|
| 679 | ++iter; |
---|
| 680 | } |
---|
[449] | 681 | return TCL_OK; |
---|
| 682 | } |
---|
| 683 | Tcl_AppendResult(interp, "bad option \"", argv[2], |
---|
| 684 | "\": should be label", (char*)NULL); |
---|
| 685 | return TCL_ERROR; |
---|
| 686 | } |
---|
| 687 | else if (c == 'd' && strcmp(argv[1],"data") == 0) { |
---|
| 688 | if (argc < 3) { |
---|
| 689 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 690 | argv[1], " option ?arg arg...?\"", (char*)NULL); |
---|
| 691 | return TCL_ERROR; |
---|
| 692 | } |
---|
| 693 | c = *argv[2]; |
---|
| 694 | if (c == 's' && strcmp(argv[2],"state") == 0) { |
---|
| 695 | if (argc < 4) { |
---|
| 696 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 697 | argv[1], " state on|off ?volume ...?\"", (char*)NULL); |
---|
| 698 | return TCL_ERROR; |
---|
| 699 | } |
---|
| 700 | |
---|
[445] | 701 | int state; |
---|
[449] | 702 | if (Tcl_GetBoolean(interp, argv[3], &state) != TCL_OK) { |
---|
| 703 | return TCL_ERROR; |
---|
| 704 | } |
---|
[445] | 705 | |
---|
[457] | 706 | vector<int> ivol; |
---|
| 707 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 708 | return TCL_ERROR; |
---|
| 709 | } |
---|
| 710 | |
---|
| 711 | vector<int>::iterator iter = ivol.begin(); |
---|
| 712 | while (iter != ivol.end()) { |
---|
| 713 | if (state) { |
---|
| 714 | volume[*iter]->enable_data(); |
---|
| 715 | } else { |
---|
| 716 | volume[*iter]->disable_data(); |
---|
[445] | 717 | } |
---|
[457] | 718 | ++iter; |
---|
[445] | 719 | } |
---|
| 720 | return TCL_OK; |
---|
| 721 | } |
---|
[449] | 722 | else if (c == 'f' && strcmp(argv[2],"follows") == 0) { |
---|
[445] | 723 | int nbytes; |
---|
[449] | 724 | if (Tcl_GetInt(interp, argv[3], &nbytes) != TCL_OK) { |
---|
| 725 | return TCL_ERROR; |
---|
| 726 | } |
---|
[445] | 727 | |
---|
| 728 | char fname[64]; |
---|
| 729 | sprintf(fname,"/tmp/nv%d.dat",getpid()); |
---|
| 730 | std::ofstream dfile(fname); |
---|
| 731 | |
---|
| 732 | char buffer[8096]; |
---|
| 733 | while (nbytes > 0) { |
---|
| 734 | int chunk = (sizeof(buffer) < nbytes) ? sizeof(buffer) : nbytes; |
---|
| 735 | int status = fread(buffer, 1, chunk, stdin); |
---|
| 736 | if (status > 0) { |
---|
| 737 | dfile.write(buffer,status); |
---|
| 738 | nbytes -= status; |
---|
| 739 | } else { |
---|
| 740 | Tcl_AppendResult(interp, "data unpacking failed in file ", |
---|
| 741 | fname, (char*)NULL); |
---|
| 742 | return TCL_ERROR; |
---|
| 743 | } |
---|
| 744 | } |
---|
| 745 | dfile.close(); |
---|
| 746 | |
---|
| 747 | char cmdstr[512]; |
---|
| 748 | sprintf(cmdstr, "mimedecode %s | gunzip -c > /tmp/nv%d.dx", fname, getpid()); |
---|
| 749 | if (system(cmdstr) != 0) { |
---|
| 750 | Tcl_AppendResult(interp, "data unpacking failed in file ", |
---|
| 751 | fname, (char*)NULL); |
---|
| 752 | return TCL_ERROR; |
---|
| 753 | } |
---|
| 754 | |
---|
| 755 | sprintf(fname,"/tmp/nv%d.dx",getpid()); |
---|
| 756 | |
---|
| 757 | int n = n_volumes; |
---|
| 758 | Rappture::Outcome err = load_volume_file(n, fname); |
---|
| 759 | |
---|
| 760 | sprintf(cmdstr, "rm -f /tmp/nv%d.dat /tmp/nv%d.dx", getpid(), getpid()); |
---|
| 761 | system(cmdstr); |
---|
| 762 | |
---|
| 763 | if (err) { |
---|
| 764 | Tcl_AppendResult(interp, err.remark().c_str(), (char*)NULL); |
---|
| 765 | return TCL_ERROR; |
---|
| 766 | } |
---|
| 767 | |
---|
[451] | 768 | // |
---|
| 769 | // BE CAREFUL: Set the number of slices to something |
---|
| 770 | // slightly different for each volume. If we have |
---|
| 771 | // identical volumes at exactly the same position |
---|
| 772 | // with exactly the same number of slices, the second |
---|
| 773 | // volume will overwrite the first, so the first won't |
---|
| 774 | // appear at all. |
---|
| 775 | // |
---|
| 776 | volume[n]->set_n_slice(256-n); |
---|
[445] | 777 | volume[n]->disable_cutplane(0); |
---|
| 778 | volume[n]->disable_cutplane(1); |
---|
| 779 | volume[n]->disable_cutplane(2); |
---|
| 780 | vol_render->add_volume(volume[n], get_transfunc("default")); |
---|
| 781 | |
---|
| 782 | return TCL_OK; |
---|
| 783 | } |
---|
| 784 | Tcl_AppendResult(interp, "bad option \"", argv[2], |
---|
| 785 | "\": should be follows or state", (char*)NULL); |
---|
| 786 | return TCL_ERROR; |
---|
| 787 | } |
---|
[449] | 788 | else if (c == 'o' && strcmp(argv[1],"outline") == 0) { |
---|
[445] | 789 | if (argc < 3) { |
---|
[449] | 790 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 791 | argv[1], " option ?arg arg...?\"", (char*)NULL); |
---|
| 792 | return TCL_ERROR; |
---|
[445] | 793 | } |
---|
| 794 | c = *argv[2]; |
---|
[434] | 795 | if (c == 's' && strcmp(argv[2],"state") == 0) { |
---|
| 796 | if (argc < 3) { |
---|
| 797 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 798 | argv[1], " state on|off ?volume ...? \"", (char*)NULL); |
---|
| 799 | return TCL_ERROR; |
---|
| 800 | } |
---|
| 801 | |
---|
| 802 | int state; |
---|
| 803 | if (Tcl_GetBoolean(interp, argv[3], &state) != TCL_OK) { |
---|
| 804 | return TCL_ERROR; |
---|
| 805 | } |
---|
| 806 | |
---|
[457] | 807 | vector<int> ivol; |
---|
| 808 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 809 | return TCL_ERROR; |
---|
| 810 | } |
---|
| 811 | |
---|
| 812 | vector<int>::iterator iter = ivol.begin(); |
---|
| 813 | while (iter != ivol.end()) { |
---|
| 814 | if (state) { |
---|
| 815 | volume[*iter]->enable_outline(); |
---|
| 816 | } else { |
---|
| 817 | volume[*iter]->disable_outline(); |
---|
[434] | 818 | } |
---|
[457] | 819 | ++iter; |
---|
[434] | 820 | } |
---|
| 821 | return TCL_OK; |
---|
| 822 | } |
---|
| 823 | else if (c == 'c' && strcmp(argv[2],"color") == 0) { |
---|
| 824 | if (argc < 3) { |
---|
| 825 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 826 | argv[1], " color {R G B} ?volume ...? \"", (char*)NULL); |
---|
| 827 | return TCL_ERROR; |
---|
| 828 | } |
---|
| 829 | |
---|
| 830 | float rgb[3]; |
---|
[448] | 831 | if (GetColor(interp, (char*) argv[3], rgb) != TCL_OK) { |
---|
[434] | 832 | return TCL_ERROR; |
---|
| 833 | } |
---|
| 834 | |
---|
[457] | 835 | vector<int> ivol; |
---|
| 836 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 837 | return TCL_ERROR; |
---|
[434] | 838 | } |
---|
[457] | 839 | |
---|
| 840 | vector<int>::iterator iter = ivol.begin(); |
---|
| 841 | while (iter != ivol.end()) { |
---|
| 842 | volume[*iter]->set_outline_color(rgb); |
---|
| 843 | ++iter; |
---|
| 844 | } |
---|
[434] | 845 | return TCL_OK; |
---|
| 846 | } |
---|
| 847 | |
---|
| 848 | Tcl_AppendResult(interp, "bad option \"", argv[2], |
---|
| 849 | "\": should be color or state", (char*)NULL); |
---|
| 850 | return TCL_ERROR; |
---|
| 851 | } |
---|
[449] | 852 | else if (c == 's' && strcmp(argv[1],"shading") == 0) { |
---|
[434] | 853 | if (argc < 3) { |
---|
[449] | 854 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 855 | argv[1], " option ?arg arg...?\"", (char*)NULL); |
---|
| 856 | return TCL_ERROR; |
---|
[434] | 857 | } |
---|
[445] | 858 | c = *argv[2]; |
---|
[451] | 859 | if (c == 't' && strcmp(argv[2],"transfunc") == 0) { |
---|
[445] | 860 | if (argc < 4) { |
---|
[449] | 861 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
[451] | 862 | argv[1], " transfunc name ?volume ...?\"", (char*)NULL); |
---|
[449] | 863 | return TCL_ERROR; |
---|
[445] | 864 | } |
---|
[434] | 865 | |
---|
[451] | 866 | TransferFunction *tf = get_transfunc(argv[3]); |
---|
| 867 | if (tf == NULL) { |
---|
| 868 | Tcl_AppendResult(interp, "transfer function \"", argv[3], |
---|
| 869 | "\" is not defined", (char*)NULL); |
---|
[449] | 870 | return TCL_ERROR; |
---|
| 871 | } |
---|
[434] | 872 | |
---|
[457] | 873 | vector<int> ivol; |
---|
| 874 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 875 | return TCL_ERROR; |
---|
[445] | 876 | } |
---|
[457] | 877 | |
---|
| 878 | vector<int>::iterator iter = ivol.begin(); |
---|
| 879 | while (iter != ivol.end()) { |
---|
| 880 | vol_render->shade_volume(volume[*iter], tf); |
---|
| 881 | ++iter; |
---|
| 882 | } |
---|
[445] | 883 | return TCL_OK; |
---|
| 884 | } |
---|
[449] | 885 | else if (c == 'd' && strcmp(argv[2],"diffuse") == 0) { |
---|
[445] | 886 | if (argc < 4) { |
---|
[449] | 887 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 888 | argv[1], " diffuse value ?volume ...?\"", (char*)NULL); |
---|
| 889 | return TCL_ERROR; |
---|
[445] | 890 | } |
---|
| 891 | |
---|
| 892 | double dval; |
---|
[449] | 893 | if (Tcl_GetDouble(interp, argv[3], &dval) != TCL_OK) { |
---|
| 894 | return TCL_ERROR; |
---|
| 895 | } |
---|
[445] | 896 | |
---|
[457] | 897 | vector<int> ivol; |
---|
| 898 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 899 | return TCL_ERROR; |
---|
[434] | 900 | } |
---|
[457] | 901 | |
---|
| 902 | vector<int>::iterator iter = ivol.begin(); |
---|
| 903 | while (iter != ivol.end()) { |
---|
| 904 | volume[*iter]->set_diffuse((float)dval); |
---|
| 905 | ++iter; |
---|
| 906 | } |
---|
[445] | 907 | return TCL_OK; |
---|
[434] | 908 | } |
---|
[449] | 909 | else if (c == 'o' && strcmp(argv[2],"opacity") == 0) { |
---|
[445] | 910 | if (argc < 4) { |
---|
[449] | 911 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 912 | argv[1], " opacity value ?volume ...?\"", (char*)NULL); |
---|
| 913 | return TCL_ERROR; |
---|
[445] | 914 | } |
---|
| 915 | |
---|
| 916 | double dval; |
---|
[449] | 917 | if (Tcl_GetDouble(interp, argv[3], &dval) != TCL_OK) { |
---|
| 918 | return TCL_ERROR; |
---|
| 919 | } |
---|
[445] | 920 | |
---|
[457] | 921 | vector<int> ivol; |
---|
| 922 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 923 | return TCL_ERROR; |
---|
[445] | 924 | } |
---|
[457] | 925 | |
---|
| 926 | vector<int>::iterator iter = ivol.begin(); |
---|
| 927 | while (iter != ivol.end()) { |
---|
| 928 | volume[*iter]->set_opacity_scale((float)dval); |
---|
| 929 | ++iter; |
---|
| 930 | } |
---|
[445] | 931 | return TCL_OK; |
---|
| 932 | } |
---|
[449] | 933 | else if (c == 's' && strcmp(argv[2],"specular") == 0) { |
---|
[445] | 934 | if (argc < 4) { |
---|
[449] | 935 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 936 | argv[1], " specular value ?volume ...?\"", (char*)NULL); |
---|
| 937 | return TCL_ERROR; |
---|
[445] | 938 | } |
---|
| 939 | |
---|
| 940 | double dval; |
---|
[449] | 941 | if (Tcl_GetDouble(interp, argv[3], &dval) != TCL_OK) { |
---|
| 942 | return TCL_ERROR; |
---|
| 943 | } |
---|
[445] | 944 | |
---|
[457] | 945 | vector<int> ivol; |
---|
| 946 | if (GetVolumeIndices(interp, argc-4, argv+4, &ivol) != TCL_OK) { |
---|
| 947 | return TCL_ERROR; |
---|
[445] | 948 | } |
---|
[457] | 949 | |
---|
| 950 | vector<int>::iterator iter = ivol.begin(); |
---|
| 951 | while (iter != ivol.end()) { |
---|
| 952 | volume[*iter]->set_specular((float)dval); |
---|
| 953 | ++iter; |
---|
| 954 | } |
---|
[445] | 955 | return TCL_OK; |
---|
| 956 | } |
---|
| 957 | Tcl_AppendResult(interp, "bad option \"", argv[2], |
---|
[451] | 958 | "\": should be diffuse, opacity, specular, or transfunc", (char*)NULL); |
---|
[445] | 959 | return TCL_ERROR; |
---|
| 960 | } |
---|
| 961 | else if (c == 's' && strcmp(argv[1],"state") == 0) { |
---|
| 962 | if (argc < 3) { |
---|
| 963 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 964 | argv[1], " on|off ?volume...?\"", (char*)NULL); |
---|
| 965 | return TCL_ERROR; |
---|
| 966 | } |
---|
| 967 | |
---|
| 968 | int state; |
---|
| 969 | if (Tcl_GetBoolean(interp, argv[2], &state) != TCL_OK) { |
---|
| 970 | return TCL_ERROR; |
---|
| 971 | } |
---|
| 972 | |
---|
[457] | 973 | vector<int> ivol; |
---|
| 974 | if (GetVolumeIndices(interp, argc-3, argv+3, &ivol) != TCL_OK) { |
---|
| 975 | return TCL_ERROR; |
---|
| 976 | } |
---|
| 977 | |
---|
| 978 | vector<int>::iterator iter = ivol.begin(); |
---|
| 979 | while (iter != ivol.end()) { |
---|
| 980 | if (state) { |
---|
| 981 | volume[*iter]->enable(); |
---|
| 982 | } else { |
---|
| 983 | volume[*iter]->disable(); |
---|
[445] | 984 | } |
---|
[457] | 985 | ++iter; |
---|
[445] | 986 | } |
---|
[434] | 987 | return TCL_OK; |
---|
| 988 | } |
---|
| 989 | |
---|
| 990 | Tcl_AppendResult(interp, "bad option \"", argv[1], |
---|
[445] | 991 | "\": should be data, outline, shading, or state", (char*)NULL); |
---|
[434] | 992 | return TCL_ERROR; |
---|
| 993 | } |
---|
| 994 | |
---|
| 995 | /* |
---|
| 996 | * ---------------------------------------------------------------------- |
---|
[457] | 997 | * FUNCTION: GetVolumeIndices() |
---|
| 998 | * |
---|
| 999 | * Used internally to decode a series of volume index values and |
---|
| 1000 | * store then in the specified vector. If there are no volume index |
---|
| 1001 | * arguments, this means "all volumes" to most commands, so all |
---|
| 1002 | * active volume indices are stored in the vector. |
---|
| 1003 | * |
---|
| 1004 | * Updates pushes index values into the vector. Returns TCL_OK or |
---|
| 1005 | * TCL_ERROR to indicate an error. |
---|
| 1006 | * ---------------------------------------------------------------------- |
---|
| 1007 | */ |
---|
| 1008 | static int |
---|
| 1009 | GetVolumeIndices(Tcl_Interp *interp, int argc, CONST84 char *argv[], |
---|
| 1010 | vector<int>* vectorPtr) |
---|
| 1011 | { |
---|
| 1012 | if (argc == 0) { |
---|
| 1013 | for (int n=0; n < volume.size(); n++) { |
---|
| 1014 | if (volume[n] != NULL) { |
---|
| 1015 | vectorPtr->push_back(n); |
---|
| 1016 | } |
---|
| 1017 | } |
---|
| 1018 | } else { |
---|
| 1019 | int ivol; |
---|
| 1020 | for (int n=0; n < argc; n++) { |
---|
| 1021 | if (Tcl_GetInt(interp, argv[n], &ivol) != TCL_OK) { |
---|
| 1022 | return TCL_ERROR; |
---|
| 1023 | } |
---|
| 1024 | if (ivol < 0 || ivol >= volume.size()) { |
---|
| 1025 | Tcl_AppendResult(interp, "bad volume index \"", argv[n], |
---|
| 1026 | "\"", (char*)NULL); |
---|
| 1027 | return TCL_ERROR; |
---|
| 1028 | } |
---|
| 1029 | if (volume[ivol] != NULL) { |
---|
| 1030 | vectorPtr->push_back(ivol); |
---|
| 1031 | } |
---|
| 1032 | } |
---|
| 1033 | } |
---|
| 1034 | return TCL_OK; |
---|
| 1035 | } |
---|
| 1036 | |
---|
| 1037 | /* |
---|
| 1038 | * ---------------------------------------------------------------------- |
---|
[434] | 1039 | * FUNCTION: GetAxis() |
---|
| 1040 | * |
---|
| 1041 | * Used internally to decode an axis value from a string ("x", "y", |
---|
| 1042 | * or "z") to its index (0, 1, or 2). Returns TCL_OK if successful, |
---|
| 1043 | * along with a value in valPtr. Otherwise, it returns TCL_ERROR |
---|
| 1044 | * and an error message in the interpreter. |
---|
| 1045 | * ---------------------------------------------------------------------- |
---|
| 1046 | */ |
---|
| 1047 | static int |
---|
| 1048 | GetAxis(Tcl_Interp *interp, char *str, int *valPtr) |
---|
| 1049 | { |
---|
| 1050 | if (strcmp(str,"x") == 0) { |
---|
| 1051 | *valPtr = 0; |
---|
| 1052 | return TCL_OK; |
---|
| 1053 | } |
---|
| 1054 | else if (strcmp(str,"y") == 0) { |
---|
| 1055 | *valPtr = 1; |
---|
| 1056 | return TCL_OK; |
---|
| 1057 | } |
---|
| 1058 | else if (strcmp(str,"z") == 0) { |
---|
| 1059 | *valPtr = 2; |
---|
| 1060 | return TCL_OK; |
---|
| 1061 | } |
---|
| 1062 | Tcl_AppendResult(interp, "bad axis \"", str, |
---|
| 1063 | "\": should be x, y, or z", (char*)NULL); |
---|
| 1064 | return TCL_ERROR; |
---|
| 1065 | } |
---|
[432] | 1066 | |
---|
[434] | 1067 | /* |
---|
| 1068 | * ---------------------------------------------------------------------- |
---|
| 1069 | * FUNCTION: GetColor() |
---|
| 1070 | * |
---|
| 1071 | * Used internally to decode a color value from a string ("R G B") |
---|
| 1072 | * as a list of three numbers 0-1. Returns TCL_OK if successful, |
---|
| 1073 | * along with RGB values in valPtr. Otherwise, it returns TCL_ERROR |
---|
| 1074 | * and an error message in the interpreter. |
---|
| 1075 | * ---------------------------------------------------------------------- |
---|
| 1076 | */ |
---|
[432] | 1077 | static int |
---|
[434] | 1078 | GetColor(Tcl_Interp *interp, char *str, float *rgbPtr) |
---|
[432] | 1079 | { |
---|
[434] | 1080 | int rgbc; |
---|
| 1081 | char **rgbv; |
---|
[449] | 1082 | if (Tcl_SplitList(interp, str, &rgbc, &rgbv) != TCL_OK) { |
---|
[434] | 1083 | return TCL_ERROR; |
---|
| 1084 | } |
---|
| 1085 | if (rgbc != 3) { |
---|
| 1086 | Tcl_AppendResult(interp, "bad color \"", str, |
---|
| 1087 | "\": should be {R G B} as double values 0-1", (char*)NULL); |
---|
| 1088 | return TCL_ERROR; |
---|
| 1089 | } |
---|
[432] | 1090 | |
---|
[434] | 1091 | double rval, gval, bval; |
---|
| 1092 | if (Tcl_GetDouble(interp, rgbv[0], &rval) != TCL_OK) { |
---|
| 1093 | Tcl_Free((char*)rgbv); |
---|
| 1094 | return TCL_ERROR; |
---|
| 1095 | } |
---|
| 1096 | if (Tcl_GetDouble(interp, rgbv[1], &gval) != TCL_OK) { |
---|
| 1097 | Tcl_Free((char*)rgbv); |
---|
| 1098 | return TCL_ERROR; |
---|
| 1099 | } |
---|
| 1100 | if (Tcl_GetDouble(interp, rgbv[2], &bval) != TCL_OK) { |
---|
| 1101 | Tcl_Free((char*)rgbv); |
---|
| 1102 | return TCL_ERROR; |
---|
| 1103 | } |
---|
| 1104 | Tcl_Free((char*)rgbv); |
---|
[432] | 1105 | |
---|
[434] | 1106 | rgbPtr[0] = (float)rval; |
---|
| 1107 | rgbPtr[1] = (float)gval; |
---|
| 1108 | rgbPtr[2] = (float)bval; |
---|
[432] | 1109 | |
---|
[434] | 1110 | return TCL_OK; |
---|
| 1111 | } |
---|
[432] | 1112 | |
---|
[434] | 1113 | /* |
---|
| 1114 | * ---------------------------------------------------------------------- |
---|
| 1115 | * USAGE: debug("string", ...) |
---|
| 1116 | * |
---|
| 1117 | * Use this anywhere within the package to send a debug message |
---|
| 1118 | * back to the client. The string can have % fields as used by |
---|
| 1119 | * the printf() package. Any remaining arguments are treated as |
---|
| 1120 | * field substitutions on that. |
---|
| 1121 | * ---------------------------------------------------------------------- |
---|
| 1122 | */ |
---|
| 1123 | void |
---|
| 1124 | debug(char *str) |
---|
| 1125 | { |
---|
| 1126 | write(0, str, strlen(str)); |
---|
[432] | 1127 | } |
---|
| 1128 | |
---|
[434] | 1129 | void |
---|
| 1130 | debug(char *str, double v1) |
---|
| 1131 | { |
---|
| 1132 | char buffer[512]; |
---|
| 1133 | sprintf(buffer, str, v1); |
---|
| 1134 | write(0, buffer, strlen(buffer)); |
---|
| 1135 | } |
---|
[432] | 1136 | |
---|
[434] | 1137 | void |
---|
| 1138 | debug(char *str, double v1, double v2) |
---|
| 1139 | { |
---|
| 1140 | char buffer[512]; |
---|
| 1141 | sprintf(buffer, str, v1, v2); |
---|
| 1142 | write(0, buffer, strlen(buffer)); |
---|
| 1143 | } |
---|
| 1144 | |
---|
| 1145 | void |
---|
| 1146 | debug(char *str, double v1, double v2, double v3) |
---|
| 1147 | { |
---|
| 1148 | char buffer[512]; |
---|
| 1149 | sprintf(buffer, str, v1, v2, v3); |
---|
| 1150 | write(0, buffer, strlen(buffer)); |
---|
| 1151 | } |
---|
| 1152 | |
---|
| 1153 | |
---|
[432] | 1154 | static int |
---|
| 1155 | PlaneNewCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])){ |
---|
| 1156 | fprintf(stderr, "load plane for 2D visualization command\n"); |
---|
| 1157 | |
---|
[455] | 1158 | int index, w, h; |
---|
[432] | 1159 | |
---|
| 1160 | if (argc != 4) { |
---|
| 1161 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 1162 | " plane_index w h \"", (char*)NULL); |
---|
| 1163 | return TCL_ERROR; |
---|
| 1164 | } |
---|
[455] | 1165 | if (Tcl_GetInt(interp, argv[1], &index) != TCL_OK) { |
---|
[432] | 1166 | return TCL_ERROR; |
---|
| 1167 | } |
---|
[455] | 1168 | if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) { |
---|
[432] | 1169 | return TCL_ERROR; |
---|
| 1170 | } |
---|
[455] | 1171 | if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) { |
---|
[432] | 1172 | return TCL_ERROR; |
---|
| 1173 | } |
---|
| 1174 | |
---|
| 1175 | //Now read w*h*4 bytes. The server expects the plane to be a stream of floats |
---|
| 1176 | char* tmp = new char[int(w*h*sizeof(float))]; |
---|
| 1177 | bzero(tmp, w*h*4); |
---|
| 1178 | int status = read(0, tmp, w*h*sizeof(float)); |
---|
| 1179 | if (status <= 0){ |
---|
| 1180 | exit(0); |
---|
| 1181 | } |
---|
| 1182 | |
---|
[455] | 1183 | plane[index] = new Texture2D(w, h, GL_FLOAT, GL_LINEAR, 1, (float*)tmp); |
---|
[432] | 1184 | |
---|
| 1185 | delete[] tmp; |
---|
| 1186 | return TCL_OK; |
---|
| 1187 | } |
---|
| 1188 | |
---|
| 1189 | |
---|
| 1190 | static |
---|
| 1191 | int PlaneLinkCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])){ |
---|
| 1192 | fprintf(stderr, "link the plane to the 2D renderer command\n"); |
---|
| 1193 | |
---|
[455] | 1194 | int plane_index, tf_index; |
---|
[432] | 1195 | |
---|
| 1196 | if (argc != 3) { |
---|
| 1197 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 1198 | " plane_index tf_index \"", (char*)NULL); |
---|
| 1199 | return TCL_ERROR; |
---|
| 1200 | } |
---|
[455] | 1201 | if (Tcl_GetInt(interp, argv[1], &plane_index) != TCL_OK) { |
---|
[432] | 1202 | return TCL_ERROR; |
---|
| 1203 | } |
---|
[455] | 1204 | if (Tcl_GetInt(interp, argv[2], &tf_index) != TCL_OK) { |
---|
[432] | 1205 | return TCL_ERROR; |
---|
| 1206 | } |
---|
| 1207 | |
---|
[455] | 1208 | //plane_render->add_plane(plane[plane_index], tf[tf_index]); |
---|
[432] | 1209 | |
---|
| 1210 | return TCL_OK; |
---|
| 1211 | } |
---|
| 1212 | |
---|
| 1213 | |
---|
| 1214 | //Enable a 2D plane for render |
---|
| 1215 | //The plane_index is the index mantained in the 2D plane renderer |
---|
| 1216 | static |
---|
| 1217 | int PlaneEnableCmd _ANSI_ARGS_((ClientData cdata, Tcl_Interp *interp, int argc, CONST84 char *argv[])){ |
---|
| 1218 | fprintf(stderr, "enable a plane so the 2D renderer can render it command\n"); |
---|
| 1219 | |
---|
[455] | 1220 | int plane_index, mode; |
---|
[432] | 1221 | |
---|
| 1222 | if (argc != 3) { |
---|
| 1223 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
---|
| 1224 | " plane_index mode \"", (char*)NULL); |
---|
| 1225 | return TCL_ERROR; |
---|
| 1226 | } |
---|
[455] | 1227 | if (Tcl_GetInt(interp, argv[1], &plane_index) != TCL_OK) { |
---|
[432] | 1228 | return TCL_ERROR; |
---|
| 1229 | } |
---|
[455] | 1230 | if (Tcl_GetInt(interp, argv[2], &mode) != TCL_OK) { |
---|
[432] | 1231 | return TCL_ERROR; |
---|
| 1232 | } |
---|
| 1233 | |
---|
| 1234 | if(mode==0) |
---|
| 1235 | plane_render->set_active_plane(-1); |
---|
| 1236 | else |
---|
| 1237 | plane_render->set_active_plane(plane_index); |
---|
| 1238 | |
---|
| 1239 | return TCL_OK; |
---|
| 1240 | } |
---|
| 1241 | |
---|
| 1242 | |
---|
[260] | 1243 | //report errors related to CG shaders |
---|
| 1244 | void cgErrorCallback(void) |
---|
| 1245 | { |
---|
| 1246 | CGerror lastError = cgGetError(); |
---|
| 1247 | if(lastError) { |
---|
| 1248 | const char *listing = cgGetLastListing(g_context); |
---|
| 1249 | printf("\n---------------------------------------------------\n"); |
---|
| 1250 | printf("%s\n\n", cgGetErrorString(lastError)); |
---|
| 1251 | printf("%s\n", listing); |
---|
| 1252 | printf("-----------------------------------------------------\n"); |
---|
| 1253 | printf("Cg error, exiting...\n"); |
---|
| 1254 | cgDestroyContext(g_context); |
---|
| 1255 | exit(-1); |
---|
| 1256 | } |
---|
| 1257 | } |
---|
| 1258 | |
---|
| 1259 | |
---|
[226] | 1260 | void init_glew(){ |
---|
| 1261 | GLenum err = glewInit(); |
---|
| 1262 | if (GLEW_OK != err) |
---|
| 1263 | { |
---|
| 1264 | //glew init failed, exit. |
---|
| 1265 | fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); |
---|
| 1266 | getchar(); |
---|
| 1267 | assert(false); |
---|
| 1268 | } |
---|
| 1269 | |
---|
| 1270 | fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); |
---|
| 1271 | } |
---|
| 1272 | |
---|
[260] | 1273 | |
---|
[226] | 1274 | |
---|
[378] | 1275 | /* Load a 3D vector field from a dx-format file |
---|
| 1276 | */ |
---|
| 1277 | void |
---|
| 1278 | load_vector_file(int index, char *fname) { |
---|
| 1279 | int dummy, nx, ny, nz, nxy, npts; |
---|
| 1280 | double x0, y0, z0, dx, dy, dz, ddx, ddy, ddz; |
---|
| 1281 | char line[128], type[128], *start; |
---|
| 1282 | std::ifstream fin(fname); |
---|
[260] | 1283 | |
---|
[378] | 1284 | do { |
---|
| 1285 | fin.getline(line,sizeof(line)-1); |
---|
| 1286 | for (start=&line[0]; *start == ' ' || *start == '\t'; start++) |
---|
| 1287 | ; // skip leading blanks |
---|
[226] | 1288 | |
---|
[378] | 1289 | if (*start != '#') { // skip comment lines |
---|
| 1290 | if (sscanf(start, "object %d class gridpositions counts %d %d %d", &dummy, &nx, &ny, &nz) == 4) { |
---|
| 1291 | // found grid size |
---|
| 1292 | } |
---|
| 1293 | else if (sscanf(start, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) { |
---|
| 1294 | // found origin |
---|
| 1295 | } |
---|
| 1296 | else if (sscanf(start, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) { |
---|
| 1297 | // found one of the delta lines |
---|
| 1298 | if (ddx != 0.0) { dx = ddx; } |
---|
| 1299 | else if (ddy != 0.0) { dy = ddy; } |
---|
| 1300 | else if (ddz != 0.0) { dz = ddz; } |
---|
| 1301 | } |
---|
| 1302 | else if (sscanf(start, "object %d class array type %s shape 3 rank 1 items %d data follows", &dummy, type, &npts) == 3) { |
---|
| 1303 | if (npts != nx*ny*nz) { |
---|
| 1304 | std::cerr << "inconsistent data: expected " << nx*ny*nz << " points but found " << npts << " points" << std::endl; |
---|
| 1305 | return; |
---|
| 1306 | } |
---|
| 1307 | break; |
---|
| 1308 | } |
---|
| 1309 | } |
---|
| 1310 | } while (!fin.eof()); |
---|
[226] | 1311 | |
---|
[378] | 1312 | // read data points |
---|
| 1313 | if (!fin.eof()) { |
---|
| 1314 | Rappture::Mesh1D xgrid(x0, x0+nx*dx, nx); |
---|
| 1315 | Rappture::Mesh1D ygrid(y0, y0+ny*dy, ny); |
---|
| 1316 | Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz); |
---|
| 1317 | Rappture::FieldRect3D xfield(xgrid, ygrid, zgrid); |
---|
| 1318 | Rappture::FieldRect3D yfield(xgrid, ygrid, zgrid); |
---|
| 1319 | Rappture::FieldRect3D zfield(xgrid, ygrid, zgrid); |
---|
[226] | 1320 | |
---|
[378] | 1321 | double vx, vy, vz; |
---|
| 1322 | int nread = 0; |
---|
| 1323 | for (int ix=0; ix < nx; ix++) { |
---|
| 1324 | for (int iy=0; iy < ny; iy++) { |
---|
| 1325 | for (int iz=0; iz < nz; iz++) { |
---|
| 1326 | if (fin.eof() || nread > npts) { |
---|
| 1327 | break; |
---|
| 1328 | } |
---|
| 1329 | fin.getline(line,sizeof(line)-1); |
---|
| 1330 | if (sscanf(line, "%lg %lg %lg", &vx, &vy, &vz) == 3) { |
---|
| 1331 | int nindex = iz*nx*ny + iy*nx + ix; |
---|
| 1332 | xfield.define(nindex, vx); |
---|
| 1333 | yfield.define(nindex, vy); |
---|
| 1334 | zfield.define(nindex, vz); |
---|
| 1335 | nread++; |
---|
| 1336 | } |
---|
| 1337 | } |
---|
| 1338 | } |
---|
| 1339 | } |
---|
[226] | 1340 | |
---|
[378] | 1341 | // make sure that we read all of the expected points |
---|
| 1342 | if (nread != nx*ny*nz) { |
---|
| 1343 | std::cerr << "inconsistent data: expected " << nx*ny*nz << " points but found " << nread << " points" << std::endl; |
---|
| 1344 | return; |
---|
| 1345 | } |
---|
[260] | 1346 | |
---|
[378] | 1347 | // figure out a good mesh spacing |
---|
| 1348 | int nsample = 30; |
---|
| 1349 | dx = xfield.rangeMax(Rappture::xaxis) - xfield.rangeMin(Rappture::xaxis); |
---|
| 1350 | dy = xfield.rangeMax(Rappture::yaxis) - xfield.rangeMin(Rappture::yaxis); |
---|
| 1351 | dz = xfield.rangeMax(Rappture::zaxis) - xfield.rangeMin(Rappture::zaxis); |
---|
| 1352 | double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333); |
---|
[226] | 1353 | |
---|
[378] | 1354 | nx = (int)ceil(dx/dmin); |
---|
| 1355 | ny = (int)ceil(dy/dmin); |
---|
| 1356 | nz = (int)ceil(dz/dmin); |
---|
[260] | 1357 | |
---|
| 1358 | #ifndef NV40 |
---|
[445] | 1359 | // must be an even power of 2 for older cards |
---|
| 1360 | nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0))); |
---|
| 1361 | ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0))); |
---|
| 1362 | nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0))); |
---|
[260] | 1363 | #endif |
---|
[226] | 1364 | |
---|
[378] | 1365 | float *data = new float[3*nx*ny*nz]; |
---|
[226] | 1366 | |
---|
[378] | 1367 | std::cout << "generating " << nx << "x" << ny << "x" << nz << " = " << nx*ny*nz << " points" << std::endl; |
---|
[226] | 1368 | |
---|
[378] | 1369 | // generate the uniformly sampled data that we need for a volume |
---|
| 1370 | double vmin = 0.0; |
---|
| 1371 | double vmax = 0.0; |
---|
| 1372 | int ngen = 0; |
---|
| 1373 | for (int iz=0; iz < nz; iz++) { |
---|
| 1374 | double zval = z0 + iz*dmin; |
---|
| 1375 | for (int iy=0; iy < ny; iy++) { |
---|
| 1376 | double yval = y0 + iy*dmin; |
---|
| 1377 | for (int ix=0; ix < nx; ix++) { |
---|
| 1378 | double xval = x0 + ix*dmin; |
---|
| 1379 | |
---|
| 1380 | vx = xfield.value(xval,yval,zval); |
---|
| 1381 | vy = yfield.value(xval,yval,zval); |
---|
| 1382 | vz = zfield.value(xval,yval,zval); |
---|
| 1383 | //vx = 1; |
---|
| 1384 | //vy = 1; |
---|
| 1385 | vz = 0; |
---|
| 1386 | double vm = sqrt(vx*vx + vy*vy + vz*vz); |
---|
| 1387 | |
---|
| 1388 | if (vm < vmin) { vmin = vm; } |
---|
| 1389 | if (vm > vmax) { vmax = vm; } |
---|
| 1390 | |
---|
| 1391 | data[ngen++] = vx; |
---|
| 1392 | data[ngen++] = vy; |
---|
| 1393 | data[ngen++] = vz; |
---|
| 1394 | } |
---|
| 1395 | } |
---|
| 1396 | } |
---|
| 1397 | |
---|
| 1398 | ngen = 0; |
---|
| 1399 | for (ngen=0; ngen < npts; ngen++) { |
---|
| 1400 | data[ngen] = (data[ngen]/(2.0*vmax) + 0.5); |
---|
| 1401 | } |
---|
| 1402 | |
---|
[455] | 1403 | load_volume(index, nx, ny, nz, 3, data, vmin, vmax); |
---|
[378] | 1404 | delete [] data; |
---|
| 1405 | } else { |
---|
| 1406 | std::cerr << "WARNING: data not found in file " << fname << std::endl; |
---|
| 1407 | } |
---|
[226] | 1408 | } |
---|
| 1409 | |
---|
[378] | 1410 | |
---|
[364] | 1411 | /* Load a 3D volume from a dx-format file |
---|
| 1412 | */ |
---|
[445] | 1413 | Rappture::Outcome |
---|
[364] | 1414 | load_volume_file(int index, char *fname) { |
---|
[445] | 1415 | Rappture::Outcome result; |
---|
| 1416 | |
---|
[372] | 1417 | Rappture::MeshTri2D xymesh; |
---|
| 1418 | int dummy, nx, ny, nz, nxy, npts; |
---|
[364] | 1419 | double x0, y0, z0, dx, dy, dz, ddx, ddy, ddz; |
---|
[372] | 1420 | char line[128], type[128], *start; |
---|
[364] | 1421 | std::ifstream fin(fname); |
---|
[226] | 1422 | |
---|
[372] | 1423 | int isrect = 1; |
---|
| 1424 | |
---|
[364] | 1425 | do { |
---|
| 1426 | fin.getline(line,sizeof(line)-1); |
---|
| 1427 | for (start=&line[0]; *start == ' ' || *start == '\t'; start++) |
---|
| 1428 | ; // skip leading blanks |
---|
| 1429 | |
---|
| 1430 | if (*start != '#') { // skip comment lines |
---|
| 1431 | if (sscanf(start, "object %d class gridpositions counts %d %d %d", &dummy, &nx, &ny, &nz) == 4) { |
---|
| 1432 | // found grid size |
---|
[372] | 1433 | isrect = 1; |
---|
[364] | 1434 | } |
---|
[372] | 1435 | else if (sscanf(start, "object %d class array type float rank 1 shape 3 items %d data follows", &dummy, &nxy) == 2) { |
---|
[375] | 1436 | isrect = 0; |
---|
[372] | 1437 | double xx, yy, zz; |
---|
| 1438 | for (int i=0; i < nxy; i++) { |
---|
| 1439 | fin.getline(line,sizeof(line)-1); |
---|
| 1440 | if (sscanf(line, "%lg %lg %lg", &xx, &yy, &zz) == 3) { |
---|
| 1441 | xymesh.addNode( Rappture::Node2D(xx,yy) ); |
---|
| 1442 | } |
---|
| 1443 | } |
---|
[375] | 1444 | |
---|
[445] | 1445 | char fpts[128]; |
---|
| 1446 | sprintf(fpts, "/tmp/tmppts%d", getpid()); |
---|
| 1447 | char fcells[128]; |
---|
| 1448 | sprintf(fcells, "/tmp/tmpcells%d", getpid()); |
---|
| 1449 | |
---|
| 1450 | std::ofstream ftmp(fpts); |
---|
[375] | 1451 | // save corners of bounding box first, to work around meshing |
---|
| 1452 | // problems in voronoi utility |
---|
| 1453 | ftmp << xymesh.rangeMin(Rappture::xaxis) << " " |
---|
| 1454 | << xymesh.rangeMin(Rappture::yaxis) << std::endl; |
---|
| 1455 | ftmp << xymesh.rangeMax(Rappture::xaxis) << " " |
---|
| 1456 | << xymesh.rangeMin(Rappture::yaxis) << std::endl; |
---|
| 1457 | ftmp << xymesh.rangeMax(Rappture::xaxis) << " " |
---|
| 1458 | << xymesh.rangeMax(Rappture::yaxis) << std::endl; |
---|
| 1459 | ftmp << xymesh.rangeMin(Rappture::xaxis) << " " |
---|
| 1460 | << xymesh.rangeMax(Rappture::yaxis) << std::endl; |
---|
| 1461 | for (int i=0; i < nxy; i++) { |
---|
| 1462 | ftmp << xymesh.atNode(i).x() << " " << xymesh.atNode(i).y() << std::endl; |
---|
| 1463 | } |
---|
[372] | 1464 | ftmp.close(); |
---|
| 1465 | |
---|
[445] | 1466 | char cmdstr[512]; |
---|
| 1467 | sprintf(cmdstr, "voronoi -t < %s > %s", fpts, fcells); |
---|
| 1468 | if (system(cmdstr) == 0) { |
---|
[372] | 1469 | int cx, cy, cz; |
---|
[445] | 1470 | std::ifstream ftri(fcells); |
---|
[372] | 1471 | while (!ftri.eof()) { |
---|
| 1472 | ftri.getline(line,sizeof(line)-1); |
---|
| 1473 | if (sscanf(line, "%d %d %d", &cx, &cy, &cz) == 3) { |
---|
[375] | 1474 | if (cx >= 4 && cy >= 4 && cz >= 4) { |
---|
| 1475 | // skip first 4 boundary points |
---|
| 1476 | xymesh.addCell(cx-4, cy-4, cz-4); |
---|
| 1477 | } |
---|
[372] | 1478 | } |
---|
| 1479 | } |
---|
| 1480 | ftri.close(); |
---|
| 1481 | } else { |
---|
[445] | 1482 | return result.error("triangularization failed"); |
---|
[372] | 1483 | } |
---|
[445] | 1484 | |
---|
| 1485 | sprintf(cmdstr, "rm -f %s %s", fpts, fcells); |
---|
| 1486 | system(cmdstr); |
---|
[372] | 1487 | } |
---|
| 1488 | else if (sscanf(start, "object %d class regulararray count %d", &dummy, &nz) == 2) { |
---|
| 1489 | // found z-grid |
---|
| 1490 | } |
---|
[364] | 1491 | else if (sscanf(start, "origin %lg %lg %lg", &x0, &y0, &z0) == 3) { |
---|
| 1492 | // found origin |
---|
| 1493 | } |
---|
| 1494 | else if (sscanf(start, "delta %lg %lg %lg", &ddx, &ddy, &ddz) == 3) { |
---|
| 1495 | // found one of the delta lines |
---|
| 1496 | if (ddx != 0.0) { dx = ddx; } |
---|
| 1497 | else if (ddy != 0.0) { dy = ddy; } |
---|
| 1498 | else if (ddz != 0.0) { dz = ddz; } |
---|
| 1499 | } |
---|
[372] | 1500 | else if (sscanf(start, "object %d class array type %s rank 0 items %d data follows", &dummy, type, &npts) == 3) { |
---|
| 1501 | if (isrect && (npts != nx*ny*nz)) { |
---|
[445] | 1502 | char mesg[256]; |
---|
| 1503 | sprintf(mesg,"inconsistent data: expected %d points but found %d points", nx*ny*nz, npts); |
---|
| 1504 | return result.error(mesg); |
---|
[364] | 1505 | } |
---|
[372] | 1506 | else if (!isrect && (npts != nxy*nz)) { |
---|
[445] | 1507 | char mesg[256]; |
---|
| 1508 | sprintf(mesg,"inconsistent data: expected %d points but found %d points", nxy*nz, npts); |
---|
| 1509 | return result.error(mesg); |
---|
[372] | 1510 | } |
---|
[364] | 1511 | break; |
---|
| 1512 | } |
---|
| 1513 | } |
---|
| 1514 | } while (!fin.eof()); |
---|
| 1515 | |
---|
| 1516 | // read data points |
---|
| 1517 | if (!fin.eof()) { |
---|
[372] | 1518 | if (isrect) { |
---|
| 1519 | Rappture::Mesh1D xgrid(x0, x0+nx*dx, nx); |
---|
| 1520 | Rappture::Mesh1D ygrid(y0, y0+ny*dy, ny); |
---|
| 1521 | Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz); |
---|
| 1522 | Rappture::FieldRect3D field(xgrid, ygrid, zgrid); |
---|
[364] | 1523 | |
---|
[372] | 1524 | double dval; |
---|
| 1525 | int nread = 0; |
---|
[378] | 1526 | for (int ix=0; ix < nx; ix++) { |
---|
| 1527 | for (int iy=0; iy < ny; iy++) { |
---|
| 1528 | for (int iz=0; iz < nz; iz++) { |
---|
| 1529 | if (fin.eof() || nread > npts) { |
---|
| 1530 | break; |
---|
| 1531 | } |
---|
| 1532 | fin.getline(line,sizeof(line)-1); |
---|
| 1533 | if (sscanf(line, "%lg", &dval) == 1) { |
---|
| 1534 | int nindex = iz*nx*ny + iy*nx + ix; |
---|
| 1535 | field.define(nindex, dval); |
---|
| 1536 | nread++; |
---|
| 1537 | } |
---|
| 1538 | } |
---|
[372] | 1539 | } |
---|
[364] | 1540 | } |
---|
| 1541 | |
---|
[372] | 1542 | // make sure that we read all of the expected points |
---|
| 1543 | if (nread != nx*ny*nz) { |
---|
[445] | 1544 | char mesg[256]; |
---|
| 1545 | sprintf(mesg,"inconsistent data: expected %d points but found %d points", nx*ny*nz, nread); |
---|
| 1546 | result.error(mesg); |
---|
| 1547 | return result; |
---|
[372] | 1548 | } |
---|
[364] | 1549 | |
---|
[372] | 1550 | // figure out a good mesh spacing |
---|
| 1551 | int nsample = 30; |
---|
| 1552 | dx = field.rangeMax(Rappture::xaxis) - field.rangeMin(Rappture::xaxis); |
---|
| 1553 | dy = field.rangeMax(Rappture::yaxis) - field.rangeMin(Rappture::yaxis); |
---|
| 1554 | dz = field.rangeMax(Rappture::zaxis) - field.rangeMin(Rappture::zaxis); |
---|
| 1555 | double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333); |
---|
[364] | 1556 | |
---|
[372] | 1557 | nx = (int)ceil(dx/dmin); |
---|
[373] | 1558 | ny = (int)ceil(dy/dmin); |
---|
| 1559 | nz = (int)ceil(dz/dmin); |
---|
| 1560 | |
---|
| 1561 | #ifndef NV40 |
---|
[445] | 1562 | // must be an even power of 2 for older cards |
---|
| 1563 | nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0))); |
---|
| 1564 | ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0))); |
---|
| 1565 | nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0))); |
---|
[373] | 1566 | #endif |
---|
| 1567 | |
---|
[372] | 1568 | float *data = new float[4*nx*ny*nz]; |
---|
[364] | 1569 | |
---|
[372] | 1570 | double vmin = field.valueMin(); |
---|
| 1571 | double dv = field.valueMax() - field.valueMin(); |
---|
| 1572 | if (dv == 0.0) { dv = 1.0; } |
---|
| 1573 | |
---|
| 1574 | // generate the uniformly sampled data that we need for a volume |
---|
| 1575 | int ngen = 0; |
---|
| 1576 | for (int iz=0; iz < nz; iz++) { |
---|
| 1577 | double zval = z0 + iz*dmin; |
---|
| 1578 | for (int iy=0; iy < ny; iy++) { |
---|
| 1579 | double yval = y0 + iy*dmin; |
---|
| 1580 | for (int ix=0; ix < nx; ix++) { |
---|
| 1581 | double xval = x0 + ix*dmin; |
---|
| 1582 | double v = field.value(xval,yval,zval); |
---|
[384] | 1583 | |
---|
| 1584 | // scale all values [0-1], -1 => out of bounds |
---|
| 1585 | v = (isnan(v)) ? -1.0 : (v - vmin)/dv; |
---|
[386] | 1586 | data[ngen] = v; |
---|
[451] | 1587 | ngen += 4; |
---|
| 1588 | } |
---|
| 1589 | } |
---|
| 1590 | } |
---|
[384] | 1591 | |
---|
[451] | 1592 | // Compute the gradient of this data. BE CAREFUL: center |
---|
| 1593 | // calculation on each node to avoid skew in either direction. |
---|
| 1594 | ngen = 0; |
---|
| 1595 | for (int iz=0; iz < nz; iz++) { |
---|
| 1596 | for (int iy=0; iy < ny; iy++) { |
---|
| 1597 | for (int ix=0; ix < nx; ix++) { |
---|
[384] | 1598 | // gradient in x-direction |
---|
[451] | 1599 | double valm1 = (ix == 0) ? 0.0 : data[ngen-1]; |
---|
| 1600 | double valp1 = (ix == nx-1) ? 0.0 : data[ngen+1]; |
---|
| 1601 | if (valm1 < 0 || valp1 < 0) { |
---|
| 1602 | data[ngen+1] = 0.0; |
---|
| 1603 | } else { |
---|
| 1604 | data[ngen+1] = valp1-valm1; // assume dx=1 |
---|
| 1605 | } |
---|
[384] | 1606 | |
---|
| 1607 | // gradient in y-direction |
---|
[451] | 1608 | valm1 = (iy == 0) ? 0.0 : data[ngen-4*nx]; |
---|
| 1609 | valp1 = (iy == ny-1) ? 0.0 : data[ngen+4*nx]; |
---|
| 1610 | if (valm1 < 0 || valp1 < 0) { |
---|
| 1611 | data[ngen+2] = 0.0; |
---|
| 1612 | } else { |
---|
| 1613 | data[ngen+2] = valp1-valm1; // assume dy=1 |
---|
| 1614 | } |
---|
[384] | 1615 | |
---|
| 1616 | // gradient in z-direction |
---|
[451] | 1617 | valm1 = (iz == 0) ? 0.0 : data[ngen-4*nx*ny]; |
---|
| 1618 | valp1 = (iz == nz-1) ? 0.0 : data[ngen+4*nx*ny]; |
---|
| 1619 | if (valm1 < 0 || valp1 < 0) { |
---|
| 1620 | data[ngen+3] = 0.0; |
---|
| 1621 | } else { |
---|
| 1622 | data[ngen+3] = valp1-valm1; // assume dz=1 |
---|
| 1623 | } |
---|
| 1624 | |
---|
[445] | 1625 | ngen += 4; |
---|
[372] | 1626 | } |
---|
[364] | 1627 | } |
---|
| 1628 | } |
---|
[392] | 1629 | |
---|
[455] | 1630 | load_volume(index, nx, ny, nz, 4, data, |
---|
| 1631 | field.valueMin(), field.valueMax()); |
---|
| 1632 | |
---|
[372] | 1633 | delete [] data; |
---|
| 1634 | |
---|
| 1635 | } else { |
---|
| 1636 | Rappture::Mesh1D zgrid(z0, z0+nz*dz, nz); |
---|
| 1637 | Rappture::FieldPrism3D field(xymesh, zgrid); |
---|
| 1638 | |
---|
| 1639 | double dval; |
---|
| 1640 | int nread = 0; |
---|
| 1641 | while (!fin.eof() && nread < npts) { |
---|
| 1642 | if (!(fin >> dval).fail()) { |
---|
| 1643 | field.define(nread++, dval); |
---|
| 1644 | } |
---|
| 1645 | } |
---|
| 1646 | |
---|
| 1647 | // make sure that we read all of the expected points |
---|
| 1648 | if (nread != nxy*nz) { |
---|
[445] | 1649 | char mesg[256]; |
---|
| 1650 | sprintf(mesg,"inconsistent data: expected %d points but found %d points", nxy*nz, nread); |
---|
| 1651 | return result.error(mesg); |
---|
[372] | 1652 | } |
---|
| 1653 | |
---|
| 1654 | // figure out a good mesh spacing |
---|
| 1655 | int nsample = 30; |
---|
| 1656 | x0 = field.rangeMin(Rappture::xaxis); |
---|
| 1657 | dx = field.rangeMax(Rappture::xaxis) - field.rangeMin(Rappture::xaxis); |
---|
| 1658 | y0 = field.rangeMin(Rappture::yaxis); |
---|
| 1659 | dy = field.rangeMax(Rappture::yaxis) - field.rangeMin(Rappture::yaxis); |
---|
| 1660 | z0 = field.rangeMin(Rappture::zaxis); |
---|
| 1661 | dz = field.rangeMax(Rappture::zaxis) - field.rangeMin(Rappture::zaxis); |
---|
| 1662 | double dmin = pow((dx*dy*dz)/(nsample*nsample*nsample), 0.333); |
---|
| 1663 | |
---|
| 1664 | nx = (int)ceil(dx/dmin); |
---|
| 1665 | ny = (int)ceil(dy/dmin); |
---|
| 1666 | nz = (int)ceil(dz/dmin); |
---|
[445] | 1667 | #ifndef NV40 |
---|
| 1668 | // must be an even power of 2 for older cards |
---|
| 1669 | nx = (int)pow(2.0, ceil(log10((double)nx)/log10(2.0))); |
---|
| 1670 | ny = (int)pow(2.0, ceil(log10((double)ny)/log10(2.0))); |
---|
| 1671 | nz = (int)pow(2.0, ceil(log10((double)nz)/log10(2.0))); |
---|
| 1672 | #endif |
---|
[372] | 1673 | float *data = new float[4*nx*ny*nz]; |
---|
| 1674 | |
---|
| 1675 | double vmin = field.valueMin(); |
---|
| 1676 | double dv = field.valueMax() - field.valueMin(); |
---|
| 1677 | if (dv == 0.0) { dv = 1.0; } |
---|
| 1678 | |
---|
| 1679 | // generate the uniformly sampled data that we need for a volume |
---|
| 1680 | int ngen = 0; |
---|
| 1681 | for (int iz=0; iz < nz; iz++) { |
---|
| 1682 | double zval = z0 + iz*dmin; |
---|
| 1683 | for (int iy=0; iy < ny; iy++) { |
---|
| 1684 | double yval = y0 + iy*dmin; |
---|
| 1685 | for (int ix=0; ix < nx; ix++) { |
---|
| 1686 | double xval = x0 + ix*dmin; |
---|
| 1687 | double v = field.value(xval,yval,zval); |
---|
[445] | 1688 | |
---|
| 1689 | // scale all values [0-1], -1 => out of bounds |
---|
| 1690 | v = (isnan(v)) ? -1.0 : (v - vmin)/dv; |
---|
| 1691 | data[ngen] = v; |
---|
| 1692 | |
---|
[451] | 1693 | ngen += 4; |
---|
| 1694 | } |
---|
| 1695 | } |
---|
| 1696 | } |
---|
| 1697 | |
---|
| 1698 | // Compute the gradient of this data. BE CAREFUL: center |
---|
| 1699 | // calculation on each node to avoid skew in either direction. |
---|
| 1700 | ngen = 0; |
---|
| 1701 | for (int iz=0; iz < nz; iz++) { |
---|
| 1702 | for (int iy=0; iy < ny; iy++) { |
---|
| 1703 | for (int ix=0; ix < nx; ix++) { |
---|
[445] | 1704 | // gradient in x-direction |
---|
[451] | 1705 | double valm1 = (ix == 0) ? 0.0 : data[ngen-1]; |
---|
| 1706 | double valp1 = (ix == nx-1) ? 0.0 : data[ngen+1]; |
---|
| 1707 | if (valm1 < 0 || valp1 < 0) { |
---|
| 1708 | data[ngen+1] = 0.0; |
---|
| 1709 | } else { |
---|
| 1710 | data[ngen+1] = valp1-valm1; // assume dx=1 |
---|
| 1711 | } |
---|
[445] | 1712 | |
---|
| 1713 | // gradient in y-direction |
---|
[451] | 1714 | valm1 = (iy == 0) ? 0.0 : data[ngen-4*nx]; |
---|
| 1715 | valp1 = (iy == ny-1) ? 0.0 : data[ngen+4*nx]; |
---|
| 1716 | if (valm1 < 0 || valp1 < 0) { |
---|
| 1717 | data[ngen+2] = 0.0; |
---|
| 1718 | } else { |
---|
| 1719 | data[ngen+2] = valp1-valm1; // assume dy=1 |
---|
| 1720 | } |
---|
[445] | 1721 | |
---|
| 1722 | // gradient in z-direction |
---|
[451] | 1723 | valm1 = (iz == 0) ? 0.0 : data[ngen-4*nx*ny]; |
---|
| 1724 | valp1 = (iz == nz-1) ? 0.0 : data[ngen+4*nx*ny]; |
---|
| 1725 | if (valm1 < 0 || valp1 < 0) { |
---|
| 1726 | data[ngen+3] = 0.0; |
---|
| 1727 | } else { |
---|
| 1728 | data[ngen+3] = valp1-valm1; // assume dz=1 |
---|
| 1729 | } |
---|
| 1730 | |
---|
[445] | 1731 | ngen += 4; |
---|
[372] | 1732 | } |
---|
| 1733 | } |
---|
| 1734 | } |
---|
[451] | 1735 | |
---|
[455] | 1736 | load_volume(index, nx, ny, nz, 4, data, |
---|
| 1737 | field.valueMin(), field.valueMax()); |
---|
| 1738 | |
---|
[372] | 1739 | delete [] data; |
---|
[364] | 1740 | } |
---|
| 1741 | } else { |
---|
[445] | 1742 | char mesg[256]; |
---|
| 1743 | sprintf(mesg,"data not found in file %s", fname); |
---|
| 1744 | return result.error(mesg); |
---|
[364] | 1745 | } |
---|
[445] | 1746 | |
---|
| 1747 | // |
---|
| 1748 | // Center this new volume on the origin. |
---|
| 1749 | // |
---|
| 1750 | float dx0 = -0.5; |
---|
| 1751 | float dy0 = -0.5*dy/dx; |
---|
| 1752 | float dz0 = -0.5*dz/dx; |
---|
| 1753 | volume[index]->move(Vector3(dx0, dy0, dz0)); |
---|
| 1754 | |
---|
| 1755 | return result; |
---|
[364] | 1756 | } |
---|
| 1757 | |
---|
[260] | 1758 | /* Load a 3D volume |
---|
[226] | 1759 | * index: the index into the volume array, which stores pointers to 3D volume instances |
---|
| 1760 | * data: pointer to an array of floats. |
---|
| 1761 | * n_component: the number of scalars for each space point. |
---|
| 1762 | * All component scalars for a point are placed consequtively in data array |
---|
| 1763 | * width, height and depth: number of points in each dimension |
---|
| 1764 | */ |
---|
[455] | 1765 | void load_volume(int index, int width, int height, int depth, |
---|
[457] | 1766 | int n_component, float* data, double vmin, double vmax) |
---|
| 1767 | { |
---|
| 1768 | while (n_volumes <= index) { |
---|
| 1769 | volume.push_back(NULL); |
---|
| 1770 | n_volumes++; |
---|
| 1771 | } |
---|
[226] | 1772 | |
---|
[457] | 1773 | if (volume[index] != NULL) { |
---|
| 1774 | delete volume[index]; |
---|
| 1775 | volume[index] = NULL; |
---|
| 1776 | } |
---|
[434] | 1777 | |
---|
[457] | 1778 | volume[index] = new Volume(0.f, 0.f, 0.f, width, height, depth, 1., |
---|
| 1779 | n_component, data, vmin, vmax); |
---|
| 1780 | assert(volume[index]!=0); |
---|
[226] | 1781 | } |
---|
| 1782 | |
---|
| 1783 | |
---|
[445] | 1784 | // get a colormap 1D texture by name |
---|
| 1785 | TransferFunction* |
---|
| 1786 | get_transfunc(char *name) { |
---|
| 1787 | Tcl_HashEntry *entryPtr; |
---|
| 1788 | entryPtr = Tcl_FindHashEntry(&tftable, name); |
---|
| 1789 | if (entryPtr) { |
---|
| 1790 | return (TransferFunction*)Tcl_GetHashValue(entryPtr); |
---|
| 1791 | } |
---|
| 1792 | return NULL; |
---|
[226] | 1793 | } |
---|
| 1794 | |
---|
| 1795 | |
---|
[423] | 1796 | //Update the transfer function using local GUI in the non-server mode |
---|
[380] | 1797 | extern void update_tf_texture(){ |
---|
| 1798 | glutSetWindow(render_window); |
---|
| 1799 | |
---|
[381] | 1800 | //fprintf(stderr, "tf update\n"); |
---|
[445] | 1801 | TransferFunction *tf = get_transfunc("default"); |
---|
| 1802 | if (tf == NULL) return; |
---|
[380] | 1803 | |
---|
| 1804 | float data[256*4]; |
---|
| 1805 | for(int i=0; i<256; i++){ |
---|
| 1806 | data[4*i+0] = color_table[i][0]; |
---|
| 1807 | data[4*i+1] = color_table[i][1]; |
---|
| 1808 | data[4*i+2] = color_table[i][2]; |
---|
| 1809 | data[4*i+3] = color_table[i][3]; |
---|
[381] | 1810 | //fprintf(stderr, "(%f,%f,%f,%f) ", data[4*i+0], data[4*i+1], data[4*i+2], data[4*i+3]); |
---|
[380] | 1811 | } |
---|
| 1812 | |
---|
[445] | 1813 | tf->update(data); |
---|
[383] | 1814 | |
---|
| 1815 | #ifdef EVENTLOG |
---|
| 1816 | float param[3] = {0,0,0}; |
---|
[391] | 1817 | Event* tmp = new Event(EVENT_ROTATE, param, get_time_interval()); |
---|
[383] | 1818 | tmp->write(event_log); |
---|
| 1819 | delete tmp; |
---|
| 1820 | #endif |
---|
[380] | 1821 | } |
---|
| 1822 | |
---|
| 1823 | |
---|
[226] | 1824 | //initialize frame buffer objects for offscreen rendering |
---|
[423] | 1825 | void init_offscreen_buffer(){ |
---|
[226] | 1826 | |
---|
[273] | 1827 | //initialize final fbo for final display |
---|
| 1828 | glGenFramebuffersEXT(1, &final_fbo); |
---|
| 1829 | glGenTextures(1, &final_color_tex); |
---|
| 1830 | glGenRenderbuffersEXT(1, &final_depth_rb); |
---|
[226] | 1831 | |
---|
[273] | 1832 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo); |
---|
[226] | 1833 | |
---|
[273] | 1834 | //initialize final color texture |
---|
| 1835 | glBindTexture(GL_TEXTURE_2D, final_color_tex); |
---|
| 1836 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
---|
| 1837 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
---|
[383] | 1838 | #ifdef NV40 |
---|
[381] | 1839 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0, |
---|
[273] | 1840 | GL_RGB, GL_INT, NULL); |
---|
[383] | 1841 | #else |
---|
| 1842 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0, |
---|
| 1843 | GL_RGB, GL_INT, NULL); |
---|
| 1844 | #endif |
---|
[273] | 1845 | glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, |
---|
| 1846 | GL_COLOR_ATTACHMENT0_EXT, |
---|
| 1847 | GL_TEXTURE_2D, final_color_tex, 0); |
---|
[226] | 1848 | |
---|
| 1849 | |
---|
[273] | 1850 | // initialize final depth renderbuffer |
---|
| 1851 | glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb); |
---|
| 1852 | glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, |
---|
| 1853 | GL_DEPTH_COMPONENT24, win_width, win_height); |
---|
| 1854 | glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, |
---|
| 1855 | GL_DEPTH_ATTACHMENT_EXT, |
---|
| 1856 | GL_RENDERBUFFER_EXT, final_depth_rb); |
---|
[226] | 1857 | |
---|
[273] | 1858 | // Check framebuffer completeness at the end of initialization. |
---|
| 1859 | CHECK_FRAMEBUFFER_STATUS(); |
---|
| 1860 | assert(glGetError()==0); |
---|
[226] | 1861 | } |
---|
| 1862 | |
---|
| 1863 | |
---|
[423] | 1864 | //resize the offscreen buffer |
---|
| 1865 | void resize_offscreen_buffer(int w, int h){ |
---|
| 1866 | win_width = w; |
---|
| 1867 | win_height = h; |
---|
| 1868 | |
---|
[431] | 1869 | //fprintf(stderr, "screen_buffer size: %d\n", sizeof(screen_buffer)); |
---|
| 1870 | |
---|
[427] | 1871 | if (screen_buffer) { |
---|
| 1872 | delete[] screen_buffer; |
---|
[434] | 1873 | screen_buffer = NULL; |
---|
[427] | 1874 | } |
---|
[432] | 1875 | screen_buffer = new unsigned char[4*win_width*win_height]; |
---|
[434] | 1876 | assert(screen_buffer != NULL); |
---|
[423] | 1877 | |
---|
| 1878 | //delete the current render buffer resources |
---|
| 1879 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo); |
---|
| 1880 | glDeleteTextures(1, &final_color_tex); |
---|
| 1881 | glDeleteFramebuffersEXT(1, &final_fbo); |
---|
| 1882 | |
---|
| 1883 | glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb); |
---|
| 1884 | glDeleteRenderbuffersEXT(1, &final_depth_rb); |
---|
[427] | 1885 | fprintf(stdin," after glDeleteRenderbuffers\n"); |
---|
[423] | 1886 | |
---|
| 1887 | //change the camera setting |
---|
| 1888 | cam->set_screen_size(win_width, win_height); |
---|
[432] | 1889 | plane_render->set_screen_size(win_width, win_height); |
---|
[423] | 1890 | |
---|
| 1891 | //Reinitialize final fbo for final display |
---|
| 1892 | glGenFramebuffersEXT(1, &final_fbo); |
---|
| 1893 | glGenTextures(1, &final_color_tex); |
---|
| 1894 | glGenRenderbuffersEXT(1, &final_depth_rb); |
---|
[427] | 1895 | fprintf(stdin," after glGenRenderbuffers\n"); |
---|
[423] | 1896 | |
---|
| 1897 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo); |
---|
| 1898 | |
---|
| 1899 | //initialize final color texture |
---|
| 1900 | glBindTexture(GL_TEXTURE_2D, final_color_tex); |
---|
| 1901 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
---|
| 1902 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
---|
| 1903 | #ifdef NV40 |
---|
| 1904 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, win_width, win_height, 0, |
---|
| 1905 | GL_RGB, GL_INT, NULL); |
---|
| 1906 | #else |
---|
| 1907 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_width, win_height, 0, |
---|
| 1908 | GL_RGB, GL_INT, NULL); |
---|
| 1909 | #endif |
---|
| 1910 | glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, |
---|
| 1911 | GL_COLOR_ATTACHMENT0_EXT, |
---|
| 1912 | GL_TEXTURE_2D, final_color_tex, 0); |
---|
[427] | 1913 | fprintf(stdin," after glFramebufferTexture2DEXT\n"); |
---|
[423] | 1914 | |
---|
| 1915 | // initialize final depth renderbuffer |
---|
| 1916 | glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, final_depth_rb); |
---|
| 1917 | glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, |
---|
| 1918 | GL_DEPTH_COMPONENT24, win_width, win_height); |
---|
| 1919 | glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, |
---|
| 1920 | GL_DEPTH_ATTACHMENT_EXT, |
---|
| 1921 | GL_RENDERBUFFER_EXT, final_depth_rb); |
---|
[427] | 1922 | fprintf(stdin," after glFramebufferRenderEXT\n"); |
---|
[423] | 1923 | |
---|
| 1924 | // Check framebuffer completeness at the end of initialization. |
---|
| 1925 | CHECK_FRAMEBUFFER_STATUS(); |
---|
| 1926 | assert(glGetError()==0); |
---|
[427] | 1927 | fprintf(stdin," after assert\n"); |
---|
[423] | 1928 | } |
---|
| 1929 | |
---|
| 1930 | |
---|
[226] | 1931 | void init_cg(){ |
---|
| 1932 | cgSetErrorCallback(cgErrorCallback); |
---|
| 1933 | g_context = cgCreateContext(); |
---|
| 1934 | |
---|
| 1935 | #ifdef NEW_CG |
---|
| 1936 | m_posvel_fprog = loadProgram(g_context, CG_PROFILE_FP40, CG_SOURCE, "./shaders/update_pos_vel.cg"); |
---|
| 1937 | m_posvel_timestep_param = cgGetNamedParameter(m_posvel_fprog, "timestep"); |
---|
| 1938 | m_posvel_damping_param = cgGetNamedParameter(m_posvel_fprog, "damping"); |
---|
| 1939 | m_posvel_gravity_param = cgGetNamedParameter(m_posvel_fprog, "gravity"); |
---|
| 1940 | m_posvel_spherePos_param = cgGetNamedParameter(m_posvel_fprog, "spherePos"); |
---|
| 1941 | m_posvel_sphereVel_param = cgGetNamedParameter(m_posvel_fprog, "sphereVel"); |
---|
| 1942 | #endif |
---|
[374] | 1943 | } |
---|
[226] | 1944 | |
---|
[374] | 1945 | |
---|
| 1946 | //switch shader to change render mode |
---|
| 1947 | void switch_shader(int choice){ |
---|
| 1948 | |
---|
| 1949 | switch (choice){ |
---|
| 1950 | case 0: |
---|
| 1951 | break; |
---|
| 1952 | |
---|
| 1953 | case 1: |
---|
[406] | 1954 | break; |
---|
[374] | 1955 | |
---|
| 1956 | default: |
---|
| 1957 | break; |
---|
| 1958 | } |
---|
[226] | 1959 | } |
---|
| 1960 | |
---|
| 1961 | void init_particles(){ |
---|
| 1962 | //random placement on a slice |
---|
[274] | 1963 | float* data = new float[psys->psys_width * psys->psys_height * 4]; |
---|
| 1964 | bzero(data, sizeof(float)*4* psys->psys_width * psys->psys_height); |
---|
| 1965 | |
---|
| 1966 | for (int i=0; i<psys->psys_width; i++){ |
---|
| 1967 | for (int j=0; j<psys->psys_height; j++){ |
---|
| 1968 | int index = i + psys->psys_height*j; |
---|
[392] | 1969 | bool particle = rand() % 256 > 150; |
---|
[379] | 1970 | //particle = true; |
---|
[396] | 1971 | if(particle) /*&& i/float(psys->psys_width)>0.3 && i/float(psys->psys_width)<0.7 |
---|
| 1972 | && j/float(psys->psys_height)>0.1 && j/float(psys->psys_height)<0.4)*/ |
---|
[226] | 1973 | { |
---|
[378] | 1974 | //assign any location (x,y,z) in range [0,1] |
---|
[379] | 1975 | data[4*index] = lic_slice_x; |
---|
[378] | 1976 | data[4*index+1]= j/float(psys->psys_height); |
---|
[379] | 1977 | data[4*index+2]= i/float(psys->psys_width); |
---|
[378] | 1978 | data[4*index+3]= 30; //shorter life span, quicker iterations |
---|
[226] | 1979 | } |
---|
| 1980 | else |
---|
| 1981 | { |
---|
| 1982 | data[4*index] = 0; |
---|
| 1983 | data[4*index+1]= 0; |
---|
| 1984 | data[4*index+2]= 0; |
---|
| 1985 | data[4*index+3]= 0; |
---|
| 1986 | } |
---|
| 1987 | } |
---|
| 1988 | } |
---|
| 1989 | |
---|
[273] | 1990 | psys->initialize((Particle*)data); |
---|
[226] | 1991 | delete[] data; |
---|
| 1992 | } |
---|
| 1993 | |
---|
| 1994 | |
---|
[397] | 1995 | //init line integral convolution |
---|
| 1996 | void init_lic(){ |
---|
[423] | 1997 | lic = new Lic(NMESH, win_width, win_height, 0.3, g_context, volume[1]->id, |
---|
| 1998 | volume[1]->aspect_ratio_width, |
---|
| 1999 | volume[1]->aspect_ratio_height, |
---|
| 2000 | volume[1]->aspect_ratio_depth); |
---|
[397] | 2001 | } |
---|
| 2002 | |
---|
[423] | 2003 | //init the particle system using vector field volume->[1] |
---|
| 2004 | void init_particle_system(){ |
---|
| 2005 | psys = new ParticleSystem(NMESH, NMESH, g_context, volume[1]->id, |
---|
| 2006 | 1./volume[1]->aspect_ratio_width, |
---|
| 2007 | 1./volume[1]->aspect_ratio_height, |
---|
| 2008 | 1./volume[1]->aspect_ratio_depth); |
---|
| 2009 | |
---|
| 2010 | init_particles(); //fill initial particles |
---|
| 2011 | } |
---|
| 2012 | |
---|
| 2013 | |
---|
[431] | 2014 | void make_test_2D_data(){ |
---|
| 2015 | |
---|
| 2016 | int w = 300; |
---|
| 2017 | int h = 200; |
---|
| 2018 | float* data = new float[w*h]; |
---|
| 2019 | |
---|
| 2020 | //procedurally make a gradient plane |
---|
| 2021 | for(int j=0; j<h; j++){ |
---|
| 2022 | for(int i=0; i<w; i++){ |
---|
| 2023 | data[w*j+i] = float(i)/float(w); |
---|
| 2024 | } |
---|
| 2025 | } |
---|
| 2026 | |
---|
| 2027 | plane[0] = new Texture2D(w, h, GL_FLOAT, GL_LINEAR, 1, data); |
---|
| 2028 | |
---|
| 2029 | delete[] data; |
---|
| 2030 | } |
---|
| 2031 | |
---|
| 2032 | |
---|
[226] | 2033 | /*----------------------------------------------------*/ |
---|
| 2034 | void initGL(void) |
---|
| 2035 | { |
---|
[377] | 2036 | system_info(); |
---|
[226] | 2037 | init_glew(); |
---|
| 2038 | |
---|
[427] | 2039 | //buffer to store data read from the screen |
---|
| 2040 | if (screen_buffer) { |
---|
| 2041 | delete[] screen_buffer; |
---|
[434] | 2042 | screen_buffer = NULL; |
---|
[427] | 2043 | } |
---|
[432] | 2044 | screen_buffer = new unsigned char[4*win_width*win_height]; |
---|
[434] | 2045 | assert(screen_buffer != NULL); |
---|
[427] | 2046 | |
---|
[404] | 2047 | //create the camera with default setting |
---|
| 2048 | cam = new Camera(win_width, win_height, |
---|
| 2049 | live_obj_x, live_obj_y, live_obj_z, |
---|
| 2050 | 0., 0., 100., |
---|
[423] | 2051 | (int)live_rot_x, (int)live_rot_y, (int)live_rot_z); |
---|
[226] | 2052 | |
---|
| 2053 | glEnable(GL_TEXTURE_2D); |
---|
| 2054 | glShadeModel(GL_FLAT); |
---|
| 2055 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
---|
[392] | 2056 | glClearColor(0,0,0,1); |
---|
[226] | 2057 | glClear(GL_COLOR_BUFFER_BIT); |
---|
| 2058 | |
---|
[392] | 2059 | //initialize lighting |
---|
| 2060 | GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0}; |
---|
| 2061 | GLfloat mat_shininess[] = {30.0}; |
---|
| 2062 | GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0}; |
---|
| 2063 | GLfloat green_light[] = {0.1, 0.5, 0.1, 1.0}; |
---|
| 2064 | |
---|
| 2065 | glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); |
---|
| 2066 | glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); |
---|
| 2067 | glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light); |
---|
| 2068 | glLightfv(GL_LIGHT0, GL_SPECULAR, white_light); |
---|
| 2069 | glLightfv(GL_LIGHT1, GL_DIFFUSE, green_light); |
---|
| 2070 | glLightfv(GL_LIGHT1, GL_SPECULAR, white_light); |
---|
| 2071 | |
---|
[445] | 2072 | // init table of transfer functions |
---|
| 2073 | Tcl_InitHashTable(&tftable, TCL_STRING_KEYS); |
---|
| 2074 | |
---|
[377] | 2075 | //check if performance query is supported |
---|
| 2076 | if(check_query_support()){ |
---|
| 2077 | //create queries to count number of rendered pixels |
---|
| 2078 | perf = new PerfQuery(); |
---|
| 2079 | } |
---|
| 2080 | |
---|
| 2081 | //load_volume_file(0, "./data/A-apbs-2-out-potential-PE0.dx"); |
---|
[372] | 2082 | //load_volume_file(0, "./data/nw-AB-Vg=0.000-Vd=1.000-potential.dx"); |
---|
| 2083 | //load_volume_file(0, "./data/test2.dx"); |
---|
[448] | 2084 | //load_volume_file(0, "./data/mu-wire-3d.dx"); //I added this line to debug: Wei |
---|
[423] | 2085 | //load_volume_file(0, "./data/input_nd_dx_4"); //take a VERY long time? |
---|
| 2086 | //load_vector_file(1, "./data/J-wire-vec.dx"); |
---|
[448] | 2087 | //load_volume_file(1, "./data/mu-wire-3d.dx"); //I added this line to debug: Wei |
---|
[417] | 2088 | //load_volume_file(3, "./data/mu-wire-3d.dx"); |
---|
[423] | 2089 | //load_volume_file(4, "./data/mu-wire-3d.dx"); |
---|
[378] | 2090 | |
---|
[423] | 2091 | init_offscreen_buffer(); //frame buffer object for offscreen rendering |
---|
| 2092 | init_cg(); //create cg shader context |
---|
[226] | 2093 | |
---|
[416] | 2094 | //create volume renderer and add volumes to it |
---|
[418] | 2095 | vol_render = new VolumeRenderer(g_context); |
---|
| 2096 | |
---|
[453] | 2097 | |
---|
[448] | 2098 | /* |
---|
| 2099 | //I added this to debug : Wei |
---|
| 2100 | float tmp_data[4*124]; |
---|
[453] | 2101 | memset(tmp_data, 0, 4*4*124); |
---|
[448] | 2102 | TransferFunction* tmp_tf = new TransferFunction(124, tmp_data); |
---|
| 2103 | vol_render->add_volume(volume[0], tmp_tf); |
---|
[453] | 2104 | volume[0]->get_cutplane(0)->enabled = false; |
---|
| 2105 | volume[0]->get_cutplane(1)->enabled = false; |
---|
| 2106 | volume[0]->get_cutplane(2)->enabled = false; |
---|
| 2107 | |
---|
| 2108 | //volume[1]->move(Vector3(0.5, 0.6, 0.7)); |
---|
| 2109 | //vol_render->add_volume(volume[1], tmp_tf); |
---|
[448] | 2110 | */ |
---|
| 2111 | |
---|
[453] | 2112 | |
---|
[431] | 2113 | //create an 2D plane renderer |
---|
| 2114 | plane_render = new PlaneRenderer(g_context, win_width, win_height); |
---|
| 2115 | make_test_2D_data(); |
---|
| 2116 | |
---|
[445] | 2117 | plane_render->add_plane(plane[0], get_transfunc("default")); |
---|
[431] | 2118 | |
---|
[448] | 2119 | assert(glGetError()==0); |
---|
| 2120 | |
---|
[423] | 2121 | //init_particle_system(); |
---|
| 2122 | //init_lic(); |
---|
[226] | 2123 | } |
---|
| 2124 | |
---|
| 2125 | |
---|
[397] | 2126 | |
---|
[226] | 2127 | void initTcl(){ |
---|
[434] | 2128 | interp = Tcl_CreateInterp(); |
---|
| 2129 | Tcl_MakeSafe(interp); |
---|
[383] | 2130 | |
---|
[445] | 2131 | Tcl_DStringInit(&cmdbuffer); |
---|
| 2132 | |
---|
[434] | 2133 | // manipulate the viewpoint |
---|
| 2134 | Tcl_CreateCommand(interp, "camera", CameraCmd, |
---|
| 2135 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
[426] | 2136 | |
---|
[434] | 2137 | // turn on/off cut planes in x/y/z directions |
---|
| 2138 | Tcl_CreateCommand(interp, "cutplane", CutplaneCmd, |
---|
| 2139 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
[427] | 2140 | |
---|
[455] | 2141 | // request the legend for a plot (transfer function) |
---|
| 2142 | Tcl_CreateCommand(interp, "legend", LegendCmd, |
---|
| 2143 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
| 2144 | |
---|
[434] | 2145 | // change the size of the screen (size of picture generated) |
---|
| 2146 | Tcl_CreateCommand(interp, "screen", ScreenCmd, |
---|
| 2147 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
[426] | 2148 | |
---|
[445] | 2149 | // manipulate transfer functions |
---|
| 2150 | Tcl_CreateCommand(interp, "transfunc", TransfuncCmd, |
---|
| 2151 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
| 2152 | |
---|
[458] | 2153 | // set the "up" direction for volumes |
---|
| 2154 | Tcl_CreateCommand(interp, "up", UpCmd, |
---|
| 2155 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
| 2156 | |
---|
[434] | 2157 | // manipulate volume data |
---|
| 2158 | Tcl_CreateCommand(interp, "volume", VolumeCmd, |
---|
| 2159 | (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL); |
---|
| 2160 | |
---|
[445] | 2161 | // create a default transfer function |
---|
| 2162 | if (Tcl_Eval(interp, def_transfunc) != TCL_OK) { |
---|
| 2163 | fprintf(stdin, "WARNING: bad default transfer function\n"); |
---|
| 2164 | fprintf(stdin, Tcl_GetStringResult(interp)); |
---|
| 2165 | } |
---|
[226] | 2166 | } |
---|
| 2167 | |
---|
| 2168 | |
---|
| 2169 | void read_screen(){ |
---|
[389] | 2170 | //glBindTexture(GL_TEXTURE_2D, 0); |
---|
[406] | 2171 | //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo); |
---|
[431] | 2172 | |
---|
[432] | 2173 | glReadPixels(0, 0, win_width, win_height, GL_RGB, GL_UNSIGNED_BYTE, screen_buffer); |
---|
[226] | 2174 | assert(glGetError()==0); |
---|
| 2175 | } |
---|
| 2176 | |
---|
[383] | 2177 | void display(); |
---|
[226] | 2178 | |
---|
[389] | 2179 | |
---|
[461] | 2180 | #if DO_RLE |
---|
[389] | 2181 | char rle[512*512*3]; |
---|
| 2182 | int rle_size; |
---|
| 2183 | |
---|
| 2184 | short offsets[512*512*3]; |
---|
| 2185 | int offsets_size; |
---|
| 2186 | |
---|
| 2187 | void do_rle(){ |
---|
| 2188 | int len = win_width*win_height*3; |
---|
| 2189 | rle_size = 0; |
---|
| 2190 | offsets_size = 0; |
---|
| 2191 | |
---|
| 2192 | int i=0; |
---|
| 2193 | while(i<len){ |
---|
| 2194 | if (screen_buffer[i] == 0) { |
---|
| 2195 | int pos = i+1; |
---|
| 2196 | while ( (pos<len) && (screen_buffer[pos] == 0)) { |
---|
| 2197 | pos++; |
---|
| 2198 | } |
---|
| 2199 | offsets[offsets_size++] = -(pos - i); |
---|
| 2200 | i = pos; |
---|
| 2201 | } |
---|
| 2202 | |
---|
| 2203 | else { |
---|
| 2204 | int pos; |
---|
| 2205 | for (pos = i; (pos<len) && (screen_buffer[pos] != 0); pos++) { |
---|
| 2206 | rle[rle_size++] = screen_buffer[pos]; |
---|
| 2207 | } |
---|
| 2208 | offsets[offsets_size++] = (pos - i); |
---|
| 2209 | i = pos; |
---|
| 2210 | } |
---|
| 2211 | |
---|
| 2212 | } |
---|
| 2213 | } |
---|
[461] | 2214 | #endif |
---|
[389] | 2215 | |
---|
[414] | 2216 | // used internally to build up the BMP file header |
---|
| 2217 | // writes an integer value into the header data structure at pos |
---|
| 2218 | void |
---|
| 2219 | bmp_header_add_int(unsigned char* header, int& pos, int data) |
---|
| 2220 | { |
---|
| 2221 | header[pos++] = data & 0xff; |
---|
| 2222 | header[pos++] = (data >> 8) & 0xff; |
---|
| 2223 | header[pos++] = (data >> 16) & 0xff; |
---|
| 2224 | header[pos++] = (data >> 24) & 0xff; |
---|
| 2225 | } |
---|
[389] | 2226 | |
---|
[455] | 2227 | void |
---|
| 2228 | bmp_write(const char* cmd) |
---|
| 2229 | { |
---|
| 2230 | unsigned char header[54]; |
---|
| 2231 | int pos = 0; |
---|
| 2232 | header[pos++] = 'B'; |
---|
| 2233 | header[pos++] = 'M'; |
---|
[414] | 2234 | |
---|
[461] | 2235 | // BE CAREFUL: BMP files must have an even multiple of 4 bytes |
---|
| 2236 | // on each scan line. If need be, we add padding to each line. |
---|
| 2237 | int pad = 0; |
---|
| 2238 | if ((3*win_width) % 4 > 0) { |
---|
| 2239 | pad = 4 - ((3*win_width) % 4); |
---|
| 2240 | } |
---|
| 2241 | |
---|
[455] | 2242 | // file size in bytes |
---|
[461] | 2243 | int fsize = (3*win_width+pad)*win_height + sizeof(header); |
---|
[455] | 2244 | bmp_header_add_int(header, pos, fsize); |
---|
| 2245 | |
---|
| 2246 | // reserved value (must be 0) |
---|
| 2247 | bmp_header_add_int(header, pos, 0); |
---|
| 2248 | |
---|
| 2249 | // offset in bytes to start of bitmap data |
---|
| 2250 | bmp_header_add_int(header, pos, sizeof(header)); |
---|
| 2251 | |
---|
| 2252 | // size of the BITMAPINFOHEADER |
---|
| 2253 | bmp_header_add_int(header, pos, 40); |
---|
| 2254 | |
---|
| 2255 | // width of the image in pixels |
---|
| 2256 | bmp_header_add_int(header, pos, win_width); |
---|
| 2257 | |
---|
| 2258 | // height of the image in pixels |
---|
| 2259 | bmp_header_add_int(header, pos, win_height); |
---|
| 2260 | |
---|
[461] | 2261 | // 1 plane + (24 bits/pixel << 16) |
---|
[455] | 2262 | bmp_header_add_int(header, pos, 1572865); |
---|
| 2263 | |
---|
| 2264 | // no compression |
---|
| 2265 | // size of image for compression |
---|
| 2266 | bmp_header_add_int(header, pos, 0); |
---|
| 2267 | bmp_header_add_int(header, pos, 0); |
---|
| 2268 | |
---|
| 2269 | // x pixels per meter |
---|
| 2270 | // y pixels per meter |
---|
| 2271 | bmp_header_add_int(header, pos, 0); |
---|
| 2272 | bmp_header_add_int(header, pos, 0); |
---|
| 2273 | |
---|
| 2274 | // number of colors used (0 = compute from bits/pixel) |
---|
| 2275 | // number of important colors (0 = all colors important) |
---|
| 2276 | bmp_header_add_int(header, pos, 0); |
---|
| 2277 | bmp_header_add_int(header, pos, 0); |
---|
| 2278 | |
---|
| 2279 | // BE CAREFUL: BMP format wants BGR ordering for screen data |
---|
[461] | 2280 | unsigned char* scr = screen_buffer; |
---|
| 2281 | for (int row=0; row < win_height; row++) { |
---|
| 2282 | for (int col=0; col < win_width; col++) { |
---|
| 2283 | unsigned char tmp = scr[2]; |
---|
| 2284 | scr[2] = scr[0]; // B |
---|
| 2285 | scr[0] = tmp; // R |
---|
| 2286 | scr += 3; |
---|
| 2287 | } |
---|
| 2288 | scr += pad; // skip over padding already in screen data |
---|
[455] | 2289 | } |
---|
| 2290 | |
---|
| 2291 | std::ostringstream result; |
---|
| 2292 | result << cmd << " " << fsize << "\n"; |
---|
| 2293 | write(0, result.str().c_str(), result.str().size()); |
---|
| 2294 | |
---|
| 2295 | write(0, header, sizeof(header)); |
---|
[461] | 2296 | write(0, screen_buffer, (3*win_width+pad)*win_height); |
---|
[455] | 2297 | } |
---|
| 2298 | |
---|
| 2299 | |
---|
[226] | 2300 | void xinetd_listen(){ |
---|
| 2301 | |
---|
[445] | 2302 | int flags = fcntl(0, F_GETFL, 0); |
---|
| 2303 | fcntl(0, F_SETFL, flags & ~O_NONBLOCK); |
---|
| 2304 | |
---|
| 2305 | int status = TCL_OK; |
---|
| 2306 | int npass = 0; |
---|
| 2307 | |
---|
| 2308 | // |
---|
| 2309 | // Read and execute as many commands as we can from stdin... |
---|
| 2310 | // |
---|
| 2311 | while (status == TCL_OK) { |
---|
| 2312 | // |
---|
| 2313 | // Read the next command from the buffer. First time through |
---|
| 2314 | // we block here and wait if necessary until a command comes in. |
---|
| 2315 | // |
---|
| 2316 | // BE CAREFUL: Read only one command, up to a newline. |
---|
| 2317 | // The "volume data follows" command needs to be able to read |
---|
| 2318 | // the data immediately following the command, and we shouldn't |
---|
| 2319 | // consume it here. |
---|
| 2320 | // |
---|
| 2321 | while (1) { |
---|
| 2322 | char c = getchar(); |
---|
| 2323 | if (c <= 0) { |
---|
| 2324 | if (npass == 0) { |
---|
| 2325 | exit(0); // EOF -- we're done! |
---|
| 2326 | } else { |
---|
| 2327 | break; |
---|
| 2328 | } |
---|
| 2329 | } |
---|
| 2330 | Tcl_DStringAppend(&cmdbuffer, &c, 1); |
---|
| 2331 | |
---|
| 2332 | if (c=='\n' && Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer))) { |
---|
| 2333 | break; |
---|
| 2334 | } |
---|
| 2335 | } |
---|
| 2336 | |
---|
| 2337 | // no command? then we're done for now |
---|
| 2338 | if (Tcl_DStringLength(&cmdbuffer) == 0) { |
---|
| 2339 | break; |
---|
| 2340 | } |
---|
| 2341 | |
---|
| 2342 | // back to original flags during command evaluation... |
---|
| 2343 | fcntl(0, F_SETFL, flags & ~O_NONBLOCK); |
---|
| 2344 | |
---|
| 2345 | status = Tcl_Eval(interp, Tcl_DStringValue(&cmdbuffer)); |
---|
| 2346 | Tcl_DStringSetLength(&cmdbuffer, 0); |
---|
| 2347 | |
---|
| 2348 | // non-blocking for next read -- we might not get anything |
---|
| 2349 | fcntl(0, F_SETFL, flags | O_NONBLOCK); |
---|
| 2350 | npass++; |
---|
[389] | 2351 | } |
---|
[445] | 2352 | fcntl(0, F_SETFL, flags); |
---|
[226] | 2353 | |
---|
[445] | 2354 | if (status != TCL_OK) { |
---|
| 2355 | std::ostringstream errmsg; |
---|
| 2356 | errmsg << "ERROR: " << Tcl_GetStringResult(interp) << std::endl; |
---|
| 2357 | write(0, errmsg.str().c_str(), errmsg.str().size()); |
---|
| 2358 | return; |
---|
[226] | 2359 | } |
---|
| 2360 | |
---|
[445] | 2361 | // |
---|
| 2362 | // Generate the latest frame and send it back to the client |
---|
| 2363 | // |
---|
[383] | 2364 | display(); |
---|
[385] | 2365 | |
---|
[389] | 2366 | #if DO_RLE |
---|
| 2367 | do_rle(); |
---|
| 2368 | int sizes[2] = { offsets_size*sizeof(offsets[0]), rle_size }; |
---|
| 2369 | fprintf(stderr, "Writing %d,%d\n", sizes[0], sizes[1]); fflush(stderr); |
---|
| 2370 | write(0, &sizes, sizeof(sizes)); |
---|
| 2371 | write(0, offsets, offsets_size*sizeof(offsets[0])); |
---|
| 2372 | write(0, rle, rle_size); //unsigned byte |
---|
| 2373 | #else |
---|
[455] | 2374 | bmp_write("nv>image -bytes"); |
---|
[389] | 2375 | #endif |
---|
[226] | 2376 | } |
---|
| 2377 | |
---|
| 2378 | |
---|
| 2379 | /* |
---|
| 2380 | //draw vectors |
---|
| 2381 | void draw_arrows(){ |
---|
| 2382 | glColor4f(0.,0.,1.,1.); |
---|
| 2383 | for(int i=0; i<NMESH; i++){ |
---|
| 2384 | for(int j=0; j<NMESH; j++){ |
---|
| 2385 | Vector2 v = grid.get(i, j); |
---|
| 2386 | |
---|
| 2387 | int x1 = i*DM; |
---|
| 2388 | int y1 = j*DM; |
---|
| 2389 | |
---|
| 2390 | int x2 = x1 + v.x; |
---|
| 2391 | int y2 = y1 + v.y; |
---|
| 2392 | |
---|
| 2393 | glBegin(GL_LINES); |
---|
| 2394 | glVertex2d(x1, y1); |
---|
| 2395 | glVertex2d(x2, y2); |
---|
| 2396 | glEnd(); |
---|
| 2397 | } |
---|
| 2398 | } |
---|
| 2399 | } |
---|
| 2400 | */ |
---|
| 2401 | |
---|
| 2402 | |
---|
| 2403 | /*----------------------------------------------------*/ |
---|
| 2404 | void idle(){ |
---|
[380] | 2405 | glutSetWindow(render_window); |
---|
| 2406 | |
---|
[396] | 2407 | |
---|
[397] | 2408 | /* |
---|
[226] | 2409 | struct timespec ts; |
---|
| 2410 | ts.tv_sec = 0; |
---|
[396] | 2411 | ts.tv_nsec = 300000000; |
---|
[226] | 2412 | nanosleep(&ts, 0); |
---|
[397] | 2413 | */ |
---|
[396] | 2414 | |
---|
[226] | 2415 | |
---|
[383] | 2416 | #ifdef XINETD |
---|
| 2417 | xinetd_listen(); |
---|
| 2418 | #else |
---|
[226] | 2419 | glutPostRedisplay(); |
---|
[383] | 2420 | #endif |
---|
[226] | 2421 | } |
---|
| 2422 | |
---|
| 2423 | |
---|
[423] | 2424 | void display_offscreen_buffer(){ |
---|
[226] | 2425 | glEnable(GL_TEXTURE_2D); |
---|
| 2426 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); |
---|
| 2427 | glBindTexture(GL_TEXTURE_2D, final_color_tex); |
---|
| 2428 | |
---|
[425] | 2429 | glViewport(0, 0, win_width, win_height); |
---|
[226] | 2430 | glMatrixMode(GL_PROJECTION); |
---|
| 2431 | glLoadIdentity(); |
---|
[425] | 2432 | gluOrtho2D(0, win_width, 0, win_height); |
---|
[226] | 2433 | glMatrixMode(GL_MODELVIEW); |
---|
| 2434 | glLoadIdentity(); |
---|
| 2435 | |
---|
[423] | 2436 | glColor3f(1.,1.,1.); //MUST HAVE THIS LINE!!! |
---|
[226] | 2437 | glBegin(GL_QUADS); |
---|
[425] | 2438 | glTexCoord2f(0, 0); glVertex2f(0, 0); |
---|
| 2439 | glTexCoord2f(1, 0); glVertex2f(win_width, 0); |
---|
| 2440 | glTexCoord2f(1, 1); glVertex2f(win_width, win_height); |
---|
| 2441 | glTexCoord2f(0, 1); glVertex2f(0, win_height); |
---|
[226] | 2442 | glEnd(); |
---|
| 2443 | } |
---|
| 2444 | |
---|
[423] | 2445 | void offscreen_buffer_capture(){ |
---|
[226] | 2446 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, final_fbo); |
---|
| 2447 | } |
---|
| 2448 | |
---|
| 2449 | void draw_bounding_box(float x0, float y0, float z0, |
---|
| 2450 | float x1, float y1, float z1, |
---|
| 2451 | float r, float g, float b, float line_width) |
---|
| 2452 | { |
---|
| 2453 | glDisable(GL_TEXTURE_2D); |
---|
| 2454 | |
---|
| 2455 | glColor4d(r, g, b, 1.0); |
---|
| 2456 | glLineWidth(line_width); |
---|
| 2457 | |
---|
| 2458 | glBegin(GL_LINE_LOOP); |
---|
| 2459 | |
---|
| 2460 | glVertex3d(x0, y0, z0); |
---|
| 2461 | glVertex3d(x1, y0, z0); |
---|
| 2462 | glVertex3d(x1, y1, z0); |
---|
| 2463 | glVertex3d(x0, y1, z0); |
---|
| 2464 | |
---|
| 2465 | glEnd(); |
---|
| 2466 | |
---|
| 2467 | glBegin(GL_LINE_LOOP); |
---|
| 2468 | |
---|
| 2469 | glVertex3d(x0, y0, z1); |
---|
| 2470 | glVertex3d(x1, y0, z1); |
---|
| 2471 | glVertex3d(x1, y1, z1); |
---|
| 2472 | glVertex3d(x0, y1, z1); |
---|
| 2473 | |
---|
| 2474 | glEnd(); |
---|
| 2475 | |
---|
| 2476 | |
---|
| 2477 | glBegin(GL_LINE_LOOP); |
---|
| 2478 | |
---|
| 2479 | glVertex3d(x0, y0, z0); |
---|
| 2480 | glVertex3d(x0, y0, z1); |
---|
| 2481 | glVertex3d(x0, y1, z1); |
---|
| 2482 | glVertex3d(x0, y1, z0); |
---|
| 2483 | |
---|
| 2484 | glEnd(); |
---|
| 2485 | |
---|
| 2486 | glBegin(GL_LINE_LOOP); |
---|
| 2487 | |
---|
| 2488 | glVertex3d(x1, y0, z0); |
---|
| 2489 | glVertex3d(x1, y0, z1); |
---|
| 2490 | glVertex3d(x1, y1, z1); |
---|
| 2491 | glVertex3d(x1, y1, z0); |
---|
| 2492 | |
---|
| 2493 | glEnd(); |
---|
| 2494 | |
---|
| 2495 | glEnable(GL_TEXTURE_2D); |
---|
| 2496 | } |
---|
| 2497 | |
---|
| 2498 | |
---|
| 2499 | |
---|
| 2500 | int particle_distance_sort(const void* a, const void* b){ |
---|
[273] | 2501 | if((*((Particle*)a)).aux > (*((Particle*)b)).aux) |
---|
[226] | 2502 | return -1; |
---|
| 2503 | else |
---|
| 2504 | return 1; |
---|
| 2505 | } |
---|
| 2506 | |
---|
| 2507 | |
---|
| 2508 | void soft_read_verts(){ |
---|
[274] | 2509 | glReadPixels(0, 0, psys->psys_width, psys->psys_height, GL_RGB, GL_FLOAT, vert); |
---|
[226] | 2510 | //fprintf(stderr, "soft_read_vert"); |
---|
| 2511 | |
---|
| 2512 | //cpu sort the distance |
---|
[274] | 2513 | Particle* p = (Particle*) malloc(sizeof(Particle)* psys->psys_width * psys->psys_height); |
---|
| 2514 | for(int i=0; i<psys->psys_width * psys->psys_height; i++){ |
---|
[226] | 2515 | float x = vert[3*i]; |
---|
| 2516 | float y = vert[3*i+1]; |
---|
| 2517 | float z = vert[3*i+2]; |
---|
| 2518 | |
---|
| 2519 | float dis = (x-live_obj_x)*(x-live_obj_x) + (y-live_obj_y)*(y-live_obj_y) + (z-live_obj_z)*(z-live_obj_z); |
---|
| 2520 | p[i].x = x; |
---|
| 2521 | p[i].y = y; |
---|
| 2522 | p[i].z = z; |
---|
[273] | 2523 | p[i].aux = dis; |
---|
[226] | 2524 | } |
---|
| 2525 | |
---|
[274] | 2526 | qsort(p, psys->psys_width * psys->psys_height, sizeof(Particle), particle_distance_sort); |
---|
[226] | 2527 | |
---|
[274] | 2528 | for(int i=0; i<psys->psys_width * psys->psys_height; i++){ |
---|
[226] | 2529 | vert[3*i] = p[i].x; |
---|
| 2530 | vert[3*i+1] = p[i].y; |
---|
| 2531 | vert[3*i+2] = p[i].z; |
---|
| 2532 | } |
---|
| 2533 | |
---|
| 2534 | free(p); |
---|
| 2535 | } |
---|
| 2536 | |
---|
| 2537 | |
---|
[259] | 2538 | //display the content of a texture as a screen aligned quad |
---|
| 2539 | void display_texture(NVISid tex, int width, int height){ |
---|
[226] | 2540 | glPushMatrix(); |
---|
| 2541 | |
---|
| 2542 | glEnable(GL_TEXTURE_2D); |
---|
| 2543 | glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex); |
---|
| 2544 | |
---|
| 2545 | glViewport(0, 0, width, height); |
---|
| 2546 | glMatrixMode(GL_PROJECTION); |
---|
| 2547 | glLoadIdentity(); |
---|
| 2548 | gluOrtho2D(0, width, 0, height); |
---|
| 2549 | glMatrixMode(GL_MODELVIEW); |
---|
| 2550 | glLoadIdentity(); |
---|
| 2551 | |
---|
| 2552 | cgGLBindProgram(m_passthru_fprog); |
---|
| 2553 | cgGLEnableProfile(CG_PROFILE_FP30); |
---|
| 2554 | |
---|
| 2555 | cgGLSetParameter4f(m_passthru_scale_param, 1.0, 1.0, 1.0, 1.0); |
---|
| 2556 | cgGLSetParameter4f(m_passthru_bias_param, 0.0, 0.0, 0.0, 0.0); |
---|
| 2557 | |
---|
| 2558 | draw_quad(width, height, width, height); |
---|
| 2559 | cgGLDisableProfile(CG_PROFILE_FP30); |
---|
| 2560 | |
---|
| 2561 | glPopMatrix(); |
---|
| 2562 | |
---|
| 2563 | assert(glGetError()==0); |
---|
| 2564 | } |
---|
| 2565 | |
---|
| 2566 | |
---|
[259] | 2567 | //draw vertices in the main memory |
---|
[226] | 2568 | void soft_display_verts(){ |
---|
| 2569 | glDisable(GL_TEXTURE_2D); |
---|
| 2570 | glEnable(GL_BLEND); |
---|
| 2571 | |
---|
[274] | 2572 | glPointSize(0.5); |
---|
[226] | 2573 | glColor4f(0,0.8,0.8,0.6); |
---|
| 2574 | glBegin(GL_POINTS); |
---|
[274] | 2575 | for(int i=0; i<psys->psys_width * psys->psys_height; i++){ |
---|
[226] | 2576 | glVertex3f(vert[3*i], vert[3*i+1], vert[3*i+2]); |
---|
| 2577 | } |
---|
| 2578 | glEnd(); |
---|
| 2579 | //fprintf(stderr, "soft_display_vert"); |
---|
| 2580 | } |
---|
| 2581 | |
---|
| 2582 | |
---|
[251] | 2583 | #if 0 |
---|
| 2584 | |
---|
[226] | 2585 | //oddeven sort on GPU |
---|
| 2586 | void sortstep() |
---|
| 2587 | { |
---|
| 2588 | // perform one step of the current sorting algorithm |
---|
| 2589 | |
---|
| 2590 | /* |
---|
| 2591 | // swap buffers |
---|
| 2592 | int sourceBuffer = targetBuffer; |
---|
| 2593 | targetBuffer = (targetBuffer+1)%2; |
---|
| 2594 | int pstage = (1<<stage); |
---|
| 2595 | int ppass = (1<<pass); |
---|
| 2596 | int activeBitonicShader = 0; |
---|
| 2597 | |
---|
| 2598 | #ifdef _WIN32 |
---|
| 2599 | buffer->BindBuffer(wglTargets[sourceBuffer]); |
---|
| 2600 | #else |
---|
| 2601 | buffer->BindBuffer(glTargets[sourceBuffer]); |
---|
| 2602 | #endif |
---|
| 2603 | if (buffer->IsDoubleBuffered()) glDrawBuffer(glTargets[targetBuffer]); |
---|
| 2604 | */ |
---|
| 2605 | |
---|
| 2606 | checkGLError("after db"); |
---|
| 2607 | |
---|
| 2608 | int pstage = (1<<stage); |
---|
| 2609 | int ppass = (1<<pass); |
---|
| 2610 | //int activeBitonicShader = 0; |
---|
| 2611 | |
---|
| 2612 | // switch on correct sorting shader |
---|
| 2613 | oddevenMergeSort.bind(); |
---|
| 2614 | glUniform3fARB(oddevenMergeSort.getUniformLocation("Param1"), float(pstage+pstage), |
---|
| 2615 | float(ppass%pstage), float((pstage+pstage)-(ppass%pstage)-1)); |
---|
| 2616 | glUniform3fARB(oddevenMergeSort.getUniformLocation("Param2"), float(psys_width), float(psys_height), float(ppass)); |
---|
| 2617 | glUniform1iARB(oddevenMergeSort.getUniformLocation("Data"), 0); |
---|
| 2618 | staticdebugmsg("sort","stage "<<pstage<<" pass "<<ppass); |
---|
| 2619 | |
---|
| 2620 | // This clear is not necessary for sort to function. But if we are in interactive mode |
---|
| 2621 | // unused parts of the texture that are visible will look bad. |
---|
| 2622 | //if (!perfTest) glClear(GL_COLOR_BUFFER_BIT); |
---|
| 2623 | |
---|
| 2624 | //buffer->Bind(); |
---|
| 2625 | //buffer->EnableTextureTarget(); |
---|
| 2626 | |
---|
| 2627 | // initiate the sorting step on the GPU |
---|
| 2628 | // a full-screen quad |
---|
| 2629 | glBegin(GL_QUADS); |
---|
| 2630 | /* |
---|
| 2631 | glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f); glVertex2f(-1.0f,-1.0f); |
---|
| 2632 | glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f); glVertex2f(1.0f,-1.0f); |
---|
| 2633 | glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f); glVertex2f(1.0f,1.0f); |
---|
| 2634 | glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f); glVertex2f(-1.0f,1.0f); |
---|
| 2635 | */ |
---|
| 2636 | glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,0.0f,0.0f,1.0f); glVertex2f(0.,0.); |
---|
| 2637 | glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),0.0f,1.0f,1.0f); glVertex2f(float(psys_width), 0.); |
---|
| 2638 | glMultiTexCoord4fARB(GL_TEXTURE0_ARB,float(psys_width),float(psys_height),1.0f,0.0f); glVertex2f(float(psys_width), float(psys_height)); |
---|
| 2639 | glMultiTexCoord4fARB(GL_TEXTURE0_ARB,0.0f,float(psys_height),0.0f,0.0f); glVertex2f(0., float(psys_height)); |
---|
| 2640 | glEnd(); |
---|
| 2641 | |
---|
| 2642 | |
---|
| 2643 | // switch off sorting shader |
---|
| 2644 | oddevenMergeSort.release(); |
---|
| 2645 | |
---|
| 2646 | //buffer->DisableTextureTarget(); |
---|
| 2647 | |
---|
| 2648 | assert(glGetError()==0); |
---|
| 2649 | } |
---|
| 2650 | |
---|
[251] | 2651 | #endif |
---|
[226] | 2652 | |
---|
| 2653 | |
---|
[392] | 2654 | void draw_3d_axis(){ |
---|
| 2655 | glDisable(GL_TEXTURE_2D); |
---|
| 2656 | glEnable(GL_DEPTH_TEST); |
---|
| 2657 | |
---|
| 2658 | //draw axes |
---|
| 2659 | GLUquadric *obj; |
---|
| 2660 | obj = gluNewQuadric(); |
---|
| 2661 | |
---|
| 2662 | glDepthFunc(GL_LESS); |
---|
| 2663 | glEnable(GL_DEPTH_TEST); |
---|
| 2664 | glDisable(GL_BLEND); |
---|
| 2665 | |
---|
[404] | 2666 | int segments = 50; |
---|
[392] | 2667 | |
---|
| 2668 | glColor3f(0.8, 0.8, 0.8); |
---|
| 2669 | glPushMatrix(); |
---|
[404] | 2670 | glTranslatef(0.4, 0., 0.); |
---|
[453] | 2671 | glRotatef(90, 1, 0, 0); |
---|
| 2672 | glRotatef(180, 0, 1, 0); |
---|
[404] | 2673 | glScalef(0.0005, 0.0005, 0.0005); |
---|
[392] | 2674 | glutStrokeCharacter(GLUT_STROKE_ROMAN, 'x'); |
---|
| 2675 | glPopMatrix(); |
---|
| 2676 | |
---|
| 2677 | glPushMatrix(); |
---|
[404] | 2678 | glTranslatef(0., 0.4, 0.); |
---|
[453] | 2679 | glRotatef(90, 1, 0, 0); |
---|
| 2680 | glRotatef(180, 0, 1, 0); |
---|
[404] | 2681 | glScalef(0.0005, 0.0005, 0.0005); |
---|
[392] | 2682 | glutStrokeCharacter(GLUT_STROKE_ROMAN, 'y'); |
---|
| 2683 | glPopMatrix(); |
---|
| 2684 | |
---|
| 2685 | glPushMatrix(); |
---|
[404] | 2686 | glTranslatef(0., 0., 0.4); |
---|
[453] | 2687 | glRotatef(90, 1, 0, 0); |
---|
| 2688 | glRotatef(180, 0, 1, 0); |
---|
[404] | 2689 | glScalef(0.0005, 0.0005, 0.0005); |
---|
[392] | 2690 | glutStrokeCharacter(GLUT_STROKE_ROMAN, 'z'); |
---|
| 2691 | glPopMatrix(); |
---|
| 2692 | |
---|
| 2693 | glEnable(GL_LIGHTING); |
---|
| 2694 | glEnable(GL_LIGHT0); |
---|
| 2695 | |
---|
| 2696 | glColor3f(0.2, 0.2, 0.8); |
---|
| 2697 | glPushMatrix(); |
---|
| 2698 | glutSolidSphere(0.02, segments, segments ); |
---|
| 2699 | glPopMatrix(); |
---|
| 2700 | |
---|
| 2701 | glPushMatrix(); |
---|
| 2702 | glRotatef(-90, 1, 0, 0); |
---|
[404] | 2703 | gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments); |
---|
[392] | 2704 | glPopMatrix(); |
---|
| 2705 | |
---|
| 2706 | glPushMatrix(); |
---|
[404] | 2707 | glTranslatef(0., 0.3, 0.); |
---|
[392] | 2708 | glRotatef(-90, 1, 0, 0); |
---|
| 2709 | gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments); |
---|
| 2710 | glPopMatrix(); |
---|
| 2711 | |
---|
| 2712 | glPushMatrix(); |
---|
| 2713 | glRotatef(90, 0, 1, 0); |
---|
[404] | 2714 | gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments); |
---|
[392] | 2715 | glPopMatrix(); |
---|
| 2716 | |
---|
| 2717 | glPushMatrix(); |
---|
[404] | 2718 | glTranslatef(0.3, 0., 0.); |
---|
[392] | 2719 | glRotatef(90, 0, 1, 0); |
---|
| 2720 | gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments); |
---|
| 2721 | glPopMatrix(); |
---|
| 2722 | |
---|
| 2723 | glPushMatrix(); |
---|
[404] | 2724 | gluCylinder(obj, 0.01, 0.01, 0.3, segments, segments); |
---|
[392] | 2725 | glPopMatrix(); |
---|
| 2726 | |
---|
| 2727 | glPushMatrix(); |
---|
[404] | 2728 | glTranslatef(0., 0., 0.3); |
---|
[392] | 2729 | gluCylinder(obj, 0.02, 0.0, 0.06, segments, segments); |
---|
| 2730 | glPopMatrix(); |
---|
| 2731 | |
---|
| 2732 | glDisable(GL_LIGHTING); |
---|
| 2733 | glDisable(GL_DEPTH_TEST); |
---|
| 2734 | gluDeleteQuadric(obj); |
---|
| 2735 | |
---|
| 2736 | glEnable(GL_TEXTURE_2D); |
---|
| 2737 | glDisable(GL_DEPTH_TEST); |
---|
| 2738 | } |
---|
| 2739 | |
---|
| 2740 | |
---|
[378] | 2741 | void draw_axis(){ |
---|
[374] | 2742 | |
---|
[378] | 2743 | glDisable(GL_TEXTURE_2D); |
---|
| 2744 | glEnable(GL_DEPTH_TEST); |
---|
| 2745 | |
---|
| 2746 | //red x |
---|
| 2747 | glColor3f(1,0,0); |
---|
| 2748 | glBegin(GL_LINES); |
---|
| 2749 | glVertex3f(0,0,0); |
---|
| 2750 | glVertex3f(1.5,0,0); |
---|
| 2751 | glEnd(); |
---|
| 2752 | |
---|
| 2753 | //blue y |
---|
| 2754 | glColor3f(0,0,1); |
---|
| 2755 | glBegin(GL_LINES); |
---|
| 2756 | glVertex3f(0,0,0); |
---|
| 2757 | glVertex3f(0,1.5,0); |
---|
| 2758 | glEnd(); |
---|
| 2759 | |
---|
| 2760 | //green z |
---|
| 2761 | glColor3f(0,1,0); |
---|
| 2762 | glBegin(GL_LINES); |
---|
| 2763 | glVertex3f(0,0,0); |
---|
| 2764 | glVertex3f(0,0,1.5); |
---|
| 2765 | glEnd(); |
---|
| 2766 | |
---|
| 2767 | glEnable(GL_TEXTURE_2D); |
---|
| 2768 | glDisable(GL_DEPTH_TEST); |
---|
| 2769 | } |
---|
| 2770 | |
---|
| 2771 | |
---|
| 2772 | |
---|
[226] | 2773 | /*----------------------------------------------------*/ |
---|
| 2774 | void display() |
---|
| 2775 | { |
---|
| 2776 | |
---|
| 2777 | assert(glGetError()==0); |
---|
| 2778 | |
---|
[423] | 2779 | //lic->convolve(); //flow line integral convolution |
---|
| 2780 | //psys->advect(); //advect particles |
---|
[226] | 2781 | |
---|
[425] | 2782 | offscreen_buffer_capture(); //enable offscreen render |
---|
| 2783 | //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); //enable onscreen render |
---|
[226] | 2784 | |
---|
| 2785 | //start final rendering |
---|
[397] | 2786 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear screen |
---|
[226] | 2787 | |
---|
[458] | 2788 | if (volume_mode) { |
---|
| 2789 | //3D rendering mode |
---|
[431] | 2790 | glEnable(GL_TEXTURE_2D); |
---|
| 2791 | glEnable(GL_DEPTH_TEST); |
---|
[226] | 2792 | |
---|
[431] | 2793 | //camera setting activated |
---|
| 2794 | cam->activate(); |
---|
[226] | 2795 | |
---|
[458] | 2796 | //set up the orientation of items in the scene. |
---|
| 2797 | glPushMatrix(); |
---|
| 2798 | switch (updir) { |
---|
| 2799 | case 1: // x |
---|
| 2800 | glRotatef(90, 0, 0, 1); |
---|
| 2801 | glRotatef(90, 1, 0, 0); |
---|
| 2802 | break; |
---|
| 2803 | |
---|
| 2804 | case 2: // y |
---|
| 2805 | // this is the default |
---|
| 2806 | break; |
---|
| 2807 | |
---|
| 2808 | case 3: // z |
---|
| 2809 | glRotatef(-90, 1, 0, 0); |
---|
| 2810 | glRotatef(-90, 0, 0, 1); |
---|
| 2811 | break; |
---|
| 2812 | |
---|
| 2813 | case -1: // -x |
---|
| 2814 | glRotatef(-90, 0, 0, 1); |
---|
| 2815 | break; |
---|
| 2816 | |
---|
| 2817 | case -2: // -y |
---|
| 2818 | glRotatef(180, 0, 0, 1); |
---|
| 2819 | glRotatef(-90, 0, 1, 0); |
---|
| 2820 | break; |
---|
| 2821 | |
---|
| 2822 | case -3: // -z |
---|
| 2823 | glRotatef(90, 1, 0, 0); |
---|
| 2824 | break; |
---|
| 2825 | } |
---|
| 2826 | |
---|
| 2827 | //now render things in the scene |
---|
| 2828 | draw_3d_axis(); |
---|
| 2829 | |
---|
| 2830 | //lic->render(); //display the line integral convolution result |
---|
| 2831 | //soft_display_verts(); |
---|
| 2832 | //perf->enable(); |
---|
| 2833 | // psys->render(); |
---|
| 2834 | //perf->disable(); |
---|
| 2835 | //fprintf(stderr, "particle pixels: %d\n", perf->get_pixel_count()); |
---|
| 2836 | //perf->reset(); |
---|
| 2837 | |
---|
| 2838 | perf->enable(); |
---|
| 2839 | vol_render->render_all(); |
---|
| 2840 | perf->disable(); |
---|
| 2841 | |
---|
| 2842 | glPopMatrix(); |
---|
[431] | 2843 | } |
---|
[458] | 2844 | else{ |
---|
| 2845 | //2D rendering mode |
---|
[431] | 2846 | perf->enable(); |
---|
| 2847 | plane_render->render(); |
---|
| 2848 | perf->disable(); |
---|
| 2849 | } |
---|
[378] | 2850 | |
---|
[431] | 2851 | |
---|
[391] | 2852 | #ifdef XINETD |
---|
[389] | 2853 | float cost = perf->get_pixel_count(); |
---|
| 2854 | write(3, &cost, sizeof(cost)); |
---|
[391] | 2855 | #endif |
---|
[377] | 2856 | perf->reset(); |
---|
[374] | 2857 | |
---|
[423] | 2858 | display_offscreen_buffer(); //display the final rendering on screen |
---|
[226] | 2859 | |
---|
[391] | 2860 | #ifdef XINETD |
---|
[389] | 2861 | read_screen(); |
---|
[406] | 2862 | #else |
---|
[432] | 2863 | //read_screen(); |
---|
[406] | 2864 | #endif |
---|
| 2865 | |
---|
[226] | 2866 | glutSwapBuffers(); |
---|
| 2867 | } |
---|
| 2868 | |
---|
| 2869 | |
---|
| 2870 | void mouse(int button, int state, int x, int y){ |
---|
| 2871 | if(button==GLUT_LEFT_BUTTON){ |
---|
| 2872 | |
---|
| 2873 | if(state==GLUT_DOWN){ |
---|
| 2874 | left_last_x = x; |
---|
| 2875 | left_last_y = y; |
---|
| 2876 | left_down = true; |
---|
| 2877 | right_down = false; |
---|
| 2878 | } |
---|
| 2879 | else{ |
---|
| 2880 | left_down = false; |
---|
| 2881 | right_down = false; |
---|
| 2882 | } |
---|
| 2883 | } |
---|
| 2884 | else{ |
---|
| 2885 | //fprintf(stderr, "right mouse\n"); |
---|
| 2886 | |
---|
| 2887 | if(state==GLUT_DOWN){ |
---|
| 2888 | //fprintf(stderr, "right mouse down\n"); |
---|
| 2889 | right_last_x = x; |
---|
| 2890 | right_last_y = y; |
---|
| 2891 | left_down = false; |
---|
| 2892 | right_down = true; |
---|
| 2893 | } |
---|
| 2894 | else{ |
---|
| 2895 | //fprintf(stderr, "right mouse up\n"); |
---|
| 2896 | left_down = false; |
---|
| 2897 | right_down = false; |
---|
| 2898 | } |
---|
| 2899 | } |
---|
| 2900 | } |
---|
| 2901 | |
---|
| 2902 | |
---|
| 2903 | void update_rot(int delta_x, int delta_y){ |
---|
| 2904 | live_rot_x += delta_x; |
---|
| 2905 | live_rot_y += delta_y; |
---|
| 2906 | |
---|
| 2907 | if(live_rot_x > 360.0) |
---|
| 2908 | live_rot_x -= 360.0; |
---|
| 2909 | else if(live_rot_x < -360.0) |
---|
| 2910 | live_rot_x += 360.0; |
---|
| 2911 | |
---|
| 2912 | if(live_rot_y > 360.0) |
---|
| 2913 | live_rot_y -= 360.0; |
---|
| 2914 | else if(live_rot_y < -360.0) |
---|
| 2915 | live_rot_y += 360.0; |
---|
[404] | 2916 | |
---|
| 2917 | cam->rotate(live_rot_x, live_rot_y, live_rot_z); |
---|
[226] | 2918 | } |
---|
| 2919 | |
---|
| 2920 | |
---|
| 2921 | void update_trans(int delta_x, int delta_y, int delta_z){ |
---|
| 2922 | live_obj_x += delta_x*0.03; |
---|
| 2923 | live_obj_y += delta_y*0.03; |
---|
| 2924 | live_obj_z += delta_z*0.03; |
---|
| 2925 | } |
---|
| 2926 | |
---|
[383] | 2927 | void end_service(); |
---|
[226] | 2928 | |
---|
| 2929 | void keyboard(unsigned char key, int x, int y){ |
---|
[383] | 2930 | |
---|
| 2931 | bool log = false; |
---|
| 2932 | |
---|
[226] | 2933 | switch (key){ |
---|
| 2934 | case 'q': |
---|
[383] | 2935 | #ifdef XINETD |
---|
| 2936 | end_service(); |
---|
| 2937 | #endif |
---|
[226] | 2938 | exit(0); |
---|
| 2939 | break; |
---|
| 2940 | case '+': |
---|
[378] | 2941 | lic_slice_z+=0.05; |
---|
[397] | 2942 | lic->set_offset(lic_slice_z); |
---|
[226] | 2943 | break; |
---|
| 2944 | case '-': |
---|
[378] | 2945 | lic_slice_z-=0.05; |
---|
[397] | 2946 | lic->set_offset(lic_slice_z); |
---|
[226] | 2947 | break; |
---|
[379] | 2948 | case ',': |
---|
| 2949 | lic_slice_x+=0.05; |
---|
| 2950 | init_particles(); |
---|
| 2951 | break; |
---|
| 2952 | case '.': |
---|
| 2953 | lic_slice_x-=0.05; |
---|
| 2954 | init_particles(); |
---|
| 2955 | break; |
---|
[226] | 2956 | case '1': |
---|
| 2957 | advect = true; |
---|
| 2958 | break; |
---|
| 2959 | case '2': |
---|
[392] | 2960 | psys_x+=0.05; |
---|
[226] | 2961 | break; |
---|
| 2962 | case '3': |
---|
[392] | 2963 | psys_x-=0.05; |
---|
[226] | 2964 | break; |
---|
[378] | 2965 | case 'w': //zoom out |
---|
[392] | 2966 | live_obj_z-=0.05; |
---|
[383] | 2967 | log = true; |
---|
[404] | 2968 | cam->move(live_obj_x, live_obj_y, live_obj_z); |
---|
[378] | 2969 | break; |
---|
| 2970 | case 's': //zoom in |
---|
[392] | 2971 | live_obj_z+=0.05; |
---|
[383] | 2972 | log = true; |
---|
[404] | 2973 | cam->move(live_obj_x, live_obj_y, live_obj_z); |
---|
[378] | 2974 | break; |
---|
| 2975 | case 'a': //left |
---|
[392] | 2976 | live_obj_x-=0.05; |
---|
[383] | 2977 | log = true; |
---|
[404] | 2978 | cam->move(live_obj_x, live_obj_y, live_obj_z); |
---|
[378] | 2979 | break; |
---|
| 2980 | case 'd': //right |
---|
[392] | 2981 | live_obj_x+=0.05; |
---|
[383] | 2982 | log = true; |
---|
[404] | 2983 | cam->move(live_obj_x, live_obj_y, live_obj_z); |
---|
[378] | 2984 | break; |
---|
| 2985 | case 'i': |
---|
| 2986 | init_particles(); |
---|
| 2987 | break; |
---|
[415] | 2988 | case 'v': |
---|
| 2989 | vol_render->switch_volume_mode(); |
---|
| 2990 | break; |
---|
| 2991 | case 'b': |
---|
| 2992 | vol_render->switch_slice_mode(); |
---|
| 2993 | break; |
---|
[423] | 2994 | case 'n': |
---|
| 2995 | resize_offscreen_buffer(win_width*2, win_height*2); |
---|
| 2996 | break; |
---|
| 2997 | case 'm': |
---|
| 2998 | resize_offscreen_buffer(win_width/2, win_height/2); |
---|
| 2999 | break; |
---|
[386] | 3000 | |
---|
[226] | 3001 | default: |
---|
| 3002 | break; |
---|
| 3003 | } |
---|
[383] | 3004 | |
---|
| 3005 | #ifdef EVENTLOG |
---|
| 3006 | if(log){ |
---|
| 3007 | float param[3] = {live_obj_x, live_obj_y, live_obj_z}; |
---|
[391] | 3008 | Event* tmp = new Event(EVENT_MOVE, param, get_time_interval()); |
---|
[383] | 3009 | tmp->write(event_log); |
---|
| 3010 | delete tmp; |
---|
| 3011 | } |
---|
| 3012 | #endif |
---|
[226] | 3013 | } |
---|
| 3014 | |
---|
| 3015 | void motion(int x, int y){ |
---|
| 3016 | |
---|
| 3017 | int old_x, old_y; |
---|
| 3018 | |
---|
| 3019 | if(left_down){ |
---|
| 3020 | old_x = left_last_x; |
---|
| 3021 | old_y = left_last_y; |
---|
| 3022 | } |
---|
| 3023 | else if(right_down){ |
---|
| 3024 | old_x = right_last_x; |
---|
| 3025 | old_y = right_last_y; |
---|
| 3026 | } |
---|
| 3027 | |
---|
| 3028 | int delta_x = x - old_x; |
---|
| 3029 | int delta_y = y - old_y; |
---|
| 3030 | |
---|
| 3031 | //more coarse event handling |
---|
[396] | 3032 | //if(abs(delta_x)<10 && abs(delta_y)<10) |
---|
| 3033 | //return; |
---|
[226] | 3034 | |
---|
| 3035 | if(left_down){ |
---|
| 3036 | left_last_x = x; |
---|
| 3037 | left_last_y = y; |
---|
| 3038 | |
---|
[406] | 3039 | update_rot(-delta_y, -delta_x); |
---|
[226] | 3040 | } |
---|
| 3041 | else if (right_down){ |
---|
| 3042 | //fprintf(stderr, "right mouse motion (%d,%d)\n", x, y); |
---|
| 3043 | |
---|
| 3044 | right_last_x = x; |
---|
| 3045 | right_last_y = y; |
---|
| 3046 | |
---|
| 3047 | update_trans(0, 0, delta_x); |
---|
| 3048 | } |
---|
| 3049 | |
---|
[383] | 3050 | #ifdef EVENTLOG |
---|
| 3051 | float param[3] = {live_rot_x, live_rot_y, live_rot_z}; |
---|
[391] | 3052 | Event* tmp = new Event(EVENT_ROTATE, param, get_time_interval()); |
---|
[383] | 3053 | tmp->write(event_log); |
---|
| 3054 | delete tmp; |
---|
| 3055 | #endif |
---|
| 3056 | |
---|
[226] | 3057 | glutPostRedisplay(); |
---|
| 3058 | } |
---|
| 3059 | |
---|
[383] | 3060 | #ifdef XINETD |
---|
| 3061 | void init_service(){ |
---|
| 3062 | //open log and map stderr to log file |
---|
| 3063 | xinetd_log = fopen("log.txt", "w"); |
---|
| 3064 | close(2); |
---|
| 3065 | dup2(fileno(xinetd_log), 2); |
---|
[389] | 3066 | dup2(2,1); |
---|
[226] | 3067 | |
---|
[383] | 3068 | //flush junk |
---|
| 3069 | fflush(stdout); |
---|
| 3070 | fflush(stderr); |
---|
| 3071 | } |
---|
| 3072 | |
---|
| 3073 | void end_service(){ |
---|
| 3074 | //close log file |
---|
| 3075 | fclose(xinetd_log); |
---|
| 3076 | } |
---|
| 3077 | #endif |
---|
| 3078 | |
---|
| 3079 | void init_event_log(){ |
---|
| 3080 | event_log = fopen("event.txt", "w"); |
---|
| 3081 | assert(event_log!=0); |
---|
[391] | 3082 | |
---|
| 3083 | struct timeval time; |
---|
| 3084 | gettimeofday(&time, NULL); |
---|
| 3085 | cur_time = time.tv_sec*1000. + time.tv_usec/1000.; |
---|
[383] | 3086 | } |
---|
| 3087 | |
---|
| 3088 | void end_event_log(){ |
---|
| 3089 | fclose(event_log); |
---|
| 3090 | } |
---|
[391] | 3091 | |
---|
| 3092 | double get_time_interval(){ |
---|
| 3093 | struct timeval time; |
---|
| 3094 | gettimeofday(&time, NULL); |
---|
| 3095 | double new_time = time.tv_sec*1000. + time.tv_usec/1000.; |
---|
| 3096 | |
---|
| 3097 | double interval = new_time - cur_time; |
---|
| 3098 | cur_time = new_time; |
---|
| 3099 | return interval; |
---|
| 3100 | } |
---|
| 3101 | |
---|
[383] | 3102 | |
---|
[226] | 3103 | /*----------------------------------------------------*/ |
---|
| 3104 | int main(int argc, char** argv) |
---|
| 3105 | { |
---|
[389] | 3106 | #ifdef XINETD |
---|
| 3107 | init_service(); |
---|
| 3108 | #endif |
---|
[379] | 3109 | |
---|
[226] | 3110 | glutInit(&argc, argv); |
---|
[381] | 3111 | glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); |
---|
[379] | 3112 | |
---|
[425] | 3113 | glutInitWindowSize(win_width, win_height); |
---|
[379] | 3114 | glutInitWindowPosition(10, 10); |
---|
[380] | 3115 | render_window = glutCreateWindow(argv[0]); |
---|
[445] | 3116 | glutDisplayFunc(display); |
---|
[379] | 3117 | |
---|
[427] | 3118 | #ifndef XINETD |
---|
[448] | 3119 | //MainTransferFunctionWindow * tf_window; |
---|
| 3120 | //tf_window = new MainTransferFunctionWindow(); |
---|
| 3121 | //tf_window->mainInit(); |
---|
[445] | 3122 | |
---|
[226] | 3123 | glutMouseFunc(mouse); |
---|
| 3124 | glutMotionFunc(motion); |
---|
| 3125 | glutKeyboardFunc(keyboard); |
---|
[427] | 3126 | #endif |
---|
[226] | 3127 | glutIdleFunc(idle); |
---|
[427] | 3128 | glutReshapeFunc(resize_offscreen_buffer); |
---|
[379] | 3129 | |
---|
[226] | 3130 | initGL(); |
---|
| 3131 | initTcl(); |
---|
| 3132 | |
---|
[383] | 3133 | #ifdef EVENTLOG |
---|
| 3134 | init_event_log(); |
---|
| 3135 | #endif |
---|
| 3136 | //event loop |
---|
| 3137 | glutMainLoop(); |
---|
| 3138 | #ifdef EVENTLOG |
---|
| 3139 | end_event_log(); |
---|
| 3140 | #endif |
---|
[226] | 3141 | |
---|
[383] | 3142 | #ifdef XINETD |
---|
| 3143 | end_service(); |
---|
| 3144 | #endif |
---|
| 3145 | |
---|
[226] | 3146 | return 0; |
---|
| 3147 | } |
---|