/* * This file is part of rasdaman community. * * Rasdaman community is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Rasdaman community is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * Purpose: * * rView graphical display modes (flat and rendered images). Renderers * provided by the cube_render sources, pixmap interface provided by * the new wxWindows class wxPixmap. Also includes the ColourspaceMapper * object. * * COMMENTS: * None */ // Standard wxWindows preamble. #ifdef __GNUG__ #pragma implementation #endif #include #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include #endif #include #include #include #include #include #include // I hate Windows... #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifdef EARLY_TEMPLATE #define __EXECUTABLE__ #endif #include "raslib/rmdebug.hh" #include "rasodmg/fastscale.hh" // For information about bit order and so on #include "wx_pixmap.h" #include "wx_pixmap_translate.h" #include "cube_render.h" #include "rviewTypes.hh" #include "labelManager.hh" #include "rviewUtils.hh" #include "rviewMDD.hh" #include "rviewDModes.hh" #include "rviewColMap.hh" #include "rviewPrefs.hh" #include "rviewIO.hh" #include "rviewDb.hh" // Table mapping base types to visualisztion types int rviewImageTypes[] = { RVIEW_IMGTYPE_NONE, // rbt_none RVIEW_IMGTYPE_MONO, // rbt_bool RVIEW_IMGTYPE_GREY, // rbt_char RVIEW_IMGTYPE_GREY, // rbt_uchar RVIEW_IMGTYPE_GREY12, // rbt_short RVIEW_IMGTYPE_HIGH, // rbt_ushort RVIEW_IMGTYPE_TRUE32, // rbt_long RVIEW_IMGTYPE_TRUE32, // rbt_ulong RVIEW_IMGTYPE_TRUE24, // rbt_rgb RVIEW_IMGTYPE_NONE, // rbt_float RVIEW_IMGTYPE_NONE // rbt_double }; /* * rviewImageSetup members */ const int rviewImageSetup::imgset_border = rviewDisplay::display_border; const int rviewImageSetup::imgset_theight = 30; const int rviewImageSetup::imgset_chkheight = 24; const int rviewImageSetup::imgset_renheight = 206; const int rviewImageSetup::imgset_voxheight = 256; const int rviewImageSetup::imgset_hgtheight = 60; const int rviewImageSetup::imgset_bwidth = 80; const int rviewImageSetup::imgset_bheight = 40; const int rviewImageSetup::imgset_chowidth = 130; const int rviewImageSetup::imgset_choheight = 30; const int rviewImageSetup::imgset_width = 400; const int rviewImageSetup::imgset_height = rviewImageSetup::imgset_renheight + rviewImageSetup::imgset_voxheight + rviewImageSetup::imgset_hgtheight + rviewImageSetup::imgset_bheight + 5*rviewImageSetup::imgset_border + rview_window_extra_height; const char *rviewImageSetup::normalKernelSizes[] = { "0", "1", "2", "3", NULL }; const keyword_to_ident_c rviewImageSetup::normalKernelTypes[] = { {RENDER_NORM_KERNEL_HOMO, "kernelTypeAvg"}, {RENDER_NORM_KERNEL_LINEAR, "kernelTypeLin"}, {RENDER_NORM_KERNEL_GAUSS, "kernelTypeGauss"}, {0, NULL} }; rviewImageSetup::rviewImageSetup(rview_image_setup *ris, rviewRenderImage *parentWin) : rviewFrame(NULL, lman->lookup("titleImgSetup"), 0, 0, imgset_width, imgset_height) { char buffer[STRINGSIZE]; int w, h, x, y, off, posx, posy; char **ktypes; char *b; int i; parent = parentWin; imgSetup = ris; memcpy(&oldSetup, ris, sizeof(rview_image_setup)); GetClientSize(&w, &h); panel = new wxPanel((wxWindow*)this, 0, 0, w, h); w -= 2*imgset_border; posx = imgset_border; posy = imgset_border; renderGroup = new wxGroupBox(panel, "", posx, posy, w, imgset_renheight); posy += imgset_renheight + imgset_border; voxelGroup = new wxGroupBox(panel, "", posx, posy, w, imgset_voxheight); posy += imgset_voxheight + imgset_border; heightGroup = new wxGroupBox(panel, "", posx, posy, w, imgset_hgtheight); w -= 2*imgset_border; y = imgset_border; posx += imgset_border; renderGroup->GetClientSize(&x, &h); off = y + imgset_renheight - h; h = (h - 5*imgset_theight) / 5; zproWidget = new rviewText(panel); clipzWidget = new rviewText(panel); useLights = new rviewCheckBox(panel); lightsAngle = new rviewText(panel); lightsScintAngle = new rviewText(panel); lightsAmbient = new rviewText(panel); lightsGain = new rviewText(panel); lightsDir = new rviewText(panel); lightsDist = new rviewText(panel); pixThreshLowWidget = new rviewText(panel); pixThreshHighWidget = new rviewText(panel); wgtThreshWidget = new rviewText(panel); wgtQuantWidget = new rviewText(panel); kernelSize = new rviewChoice(panel, 4, (char**)normalKernelSizes, lman->lookup("imgSetKernSize")); ktypes = new char *[3]; b = buffer; for (i=0; i<3; i++) { ktypes[i] = b; b += 1 + sprintf(b, "%s", lman->lookup(normalKernelTypes[i].keyword)); } kernelType = new rviewChoice(panel, 3, ktypes, lman->lookup("imgSetKernType")); delete [] ktypes; useVoxCol = new rviewCheckBox(panel); useRgbBrightness = new rviewCheckBox(panel); voxColour = new rviewText(panel); gridSize = new rviewText(panel); scaleHeight = new rviewText(panel); okBut = new rviewButton(panel); cancelBut = new rviewButton(panel); label(); updateSettings(*ris); frameWidth=-1; frameHeight=-1; OnSize(imgset_width, imgset_height); OnSize(imgset_width, imgset_height); Show(TRUE); } rviewImageSetup::~rviewImageSetup(void) { if (parent != NULL) { user_event ue; ue.type = usr_child_closed; ue.data = (void*)this; parent->userEvent(ue); } } const char *rviewImageSetup::getFrameName(void) const { return "rviewImageSetup"; } rviewFrameType rviewImageSetup::getFrameType(void) const { return rviewFrameTypeImgSet; } void rviewImageSetup::unlinkParent(void) { parent = NULL; } void rviewImageSetup::updateSettings(const rview_image_setup &ris) { char buffer[STRINGSIZE]; char *b; int i; zproWidget->SetValue((long)(ris.zpro)); clipzWidget->SetValue((long)(ris.clipz)); useLights->SetValue(ris.useLights); lightsAngle->SetValue(ris.lightsAngle); lightsScintAngle->SetValue(ris.lightsScintAngle); lightsAmbient->SetValue(ris.lightsAmbient); lightsGain->SetValue(ris.lightsGain); lightsDist->SetValue(ris.lightsDist); pixThreshLowWidget->SetValue(ris.pixelThresholdLow, TRUE); pixThreshHighWidget->SetValue(ris.pixelThresholdHigh, TRUE); wgtThreshWidget->SetValue(ris.weightThreshold, TRUE); wgtQuantWidget->SetValue(ris.weightQuantisation); useRgbBrightness->SetValue(ris.useRgbBrightness); useVoxCol->SetValue(ris.useVoxCol); voxColour->SetValue(ris.voxColour); gridSize->SetValue(ris.gridSize); scaleHeight->SetValue(ris.scaleHeight); if ((ris.kernelSize >= 0) && (ris.kernelSize < 4)) { kernelSize->SetSelection(ris.kernelSize); } for (i=0; normalKernelTypes[i].keyword != NULL; i++) { if (normalKernelTypes[i].ident == ris.kernelType) { kernelType->SetSelection(i); break; } } b = buffer; if ((ris.lightsDir & RVIEW_LIGHTDIR_LEFT) != 0) *b++ = 'l'; else if ((ris.lightsDir & RVIEW_LIGHTDIR_RIGHT) != 0) *b++ = 'r'; if ((ris.lightsDir & RVIEW_LIGHTDIR_DOWN) != 0) *b++ = 'd'; else if ((ris.lightsDir & RVIEW_LIGHTDIR_UP) != 0) *b++ = 'u'; if ((ris.lightsDir & RVIEW_LIGHTDIR_FRONT) != 0) *b++ = 'f'; else if ((ris.lightsDir & RVIEW_LIGHTDIR_BACK) != 0) *b++ = 'b'; *b++ = '\0'; lightsDir->SetValue(buffer); } int rviewImageSetup::parseLightDirection(const char *dir) { char *b; int val; b = (char*)dir; val = 0; while (*b != '\0') { switch (*b) { case 'l': val |= RVIEW_LIGHTDIR_LEFT; break; case 'r': val |= RVIEW_LIGHTDIR_RIGHT; break; case 'd': val |= RVIEW_LIGHTDIR_DOWN; break; case 'u': val |= RVIEW_LIGHTDIR_UP; break; case 'f': val |= RVIEW_LIGHTDIR_FRONT; break; case 'b': val |= RVIEW_LIGHTDIR_BACK; break; default: break; } b++; } return val; } void rviewImageSetup::readNewSetup(void) { long val; val = asctoi(zproWidget->GetValue()); if (val > 0) imgSetup->zpro = (unsigned long)val; val = asctoi(clipzWidget->GetValue()); if (val > 0) imgSetup->clipz = (unsigned long)val; imgSetup->useLights = useLights->GetValue(); imgSetup->lightsAngle = atof(lightsAngle->GetValue()); imgSetup->lightsScintAngle = atof(lightsScintAngle->GetValue()); imgSetup->lightsAmbient = atof(lightsAmbient->GetValue()); imgSetup->lightsGain = atof(lightsGain->GetValue()); imgSetup->lightsDist = asctoi(lightsDist->GetValue()); imgSetup->pixelThresholdLow = asctof(pixThreshLowWidget->GetValue()); imgSetup->pixelThresholdHigh = asctof(pixThreshHighWidget->GetValue()); imgSetup->weightThreshold = asctof(wgtThreshWidget->GetValue()); imgSetup->useRgbBrightness = useRgbBrightness->GetValue(); val = asctoi(wgtQuantWidget->GetValue()); if (val >= 0) imgSetup->weightQuantisation = (int)val; imgSetup->kernelSize = kernelSize->GetSelection(); imgSetup->kernelType = normalKernelTypes[kernelType->GetSelection()].ident; imgSetup->useVoxCol = useVoxCol->GetValue(); imgSetup->voxColour = asctof(voxColour->GetValue()); imgSetup->lightsDir = parseLightDirection(lightsDir->GetValue()); imgSetup->gridSize = asctoi(gridSize->GetValue()); imgSetup->scaleHeight = atof(scaleHeight->GetValue()); } void rviewImageSetup::label(void) { SetTitle(lman->lookup("titleImgSetup")); renderGroup->SetLabel(lman->lookup("imgSetRender")); voxelGroup->SetLabel(lman->lookup("imgSetVoxel")); heightGroup->SetLabel(lman->lookup("imgSetHeight")); zproWidget->SetLabel(lman->lookup("imgSetRenZpro")); clipzWidget->SetLabel(lman->lookup("imgSetRenClipz")); useLights->SetLabel(lman->lookup("imgSetRenUseLight")); lightsAngle->SetLabel(lman->lookup("imgSetRenLightAn")); lightsScintAngle->SetLabel(lman->lookup("imgSetRenLightSc")); lightsAmbient->SetLabel(lman->lookup("imgSetRenLightAm")); lightsGain->SetLabel(lman->lookup("imgSetRenLightGn")); lightsDir->SetLabel(lman->lookup("imgSetRenLightDr")); lightsDist->SetLabel(lman->lookup("imgSetRenLightDs")); pixThreshLowWidget->SetLabel(lman->lookup("imgSetVoxPixThreshLow")); pixThreshHighWidget->SetLabel(lman->lookup("imgSetVoxPixThreshHigh")); wgtThreshWidget->SetLabel(lman->lookup("imgSetVoxWgtThresh")); wgtQuantWidget->SetLabel(lman->lookup("imgSetVoxWgtQuant")); useRgbBrightness->SetLabel(lman->lookup("imgSetVoxRgbBright")); kernelSize->SetLabel(lman->lookup("imgSetKernSize")); kernelType->SetLabel(lman->lookup("imgSetKernType")); useVoxCol->SetLabel(lman->lookup("imgSetUseVCol")); voxColour->SetLabel(lman->lookup("imgSetVoxCol")); gridSize->SetLabel(lman->lookup("imgSetGridSize")); scaleHeight->SetLabel(lman->lookup("imgSetHgtScale")); okBut->SetLabel(lman->lookup("textOK")); cancelBut->SetLabel(lman->lookup("textCancel")); } void rviewImageSetup::OnSize(int w, int h) { int x, y, width, height, off, posx, posy; GetClientSize(&width, &height); //need to resize? if (( imgset_width != width) || ( imgset_height != height)) { frameWidth = imgset_width; frameHeight = imgset_height; width= imgset_width; height = imgset_height; SetClientSize(width, height); return; } panel->SetSize(0, 0, width, height); width -= 2*imgset_border; height -= 2*imgset_border; posx = imgset_border; posy = imgset_border; renderGroup->SetSize(posx, posy, width, imgset_renheight); posy += imgset_renheight + imgset_border; voxelGroup->SetSize(posx, posy, width, imgset_voxheight); posy += imgset_voxheight + imgset_border; heightGroup->SetSize(posx, posy, width, imgset_hgtheight); width -= 2*imgset_border; y = imgset_border; posx += imgset_border; posy += imgset_border; renderGroup->GetClientSize(&x, &height); off = y + imgset_renheight - height; height = (height - 5*imgset_theight) / 5; posy = off + height/2; zproWidget->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER); clipzWidget->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER); posy += height + imgset_theight; useLights->SetSize(posx, posy, width/2, imgset_theight); posy += height + imgset_theight; lightsAngle->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER); lightsScintAngle->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER); posy += height + imgset_theight; lightsAmbient->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER); lightsGain->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER); posy += height + imgset_theight; lightsDir->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER); lightsDist->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER); y += imgset_renheight + imgset_border; voxelGroup->GetClientSize(&x, &height); off = y + imgset_voxheight - height; height = (height - 5*imgset_theight - imgset_chkheight - imgset_choheight) / 6; posy = off + height/2; pixThreshLowWidget->SetSize(posx, posy, width, imgset_theight, wxTE_PROCESS_ENTER); posy += height + imgset_theight; pixThreshHighWidget->SetSize(posx, posy, width, imgset_theight, wxTE_PROCESS_ENTER); posy += height + imgset_theight; wgtThreshWidget->SetSize(posx, posy, width, imgset_theight, wxTE_PROCESS_ENTER); posy += height + imgset_theight; wgtQuantWidget->SetSize(posx, posy, width, imgset_theight, wxTE_PROCESS_ENTER); posy += height + imgset_theight; kernelSize->SetSize(posx, posy, imgset_chowidth, imgset_choheight); kernelType->SetSize(width - imgset_chowidth - 3*imgset_border, posy, imgset_chowidth, imgset_choheight); posy += height + imgset_theight; useVoxCol->SetSize(posx, posy, width/2, imgset_theight); useRgbBrightness->SetSize(posx + width/2, posy, width/2, imgset_theight); posy += height + imgset_chkheight; voxColour->SetSize(posx, posy, width, imgset_theight); y += imgset_voxheight + imgset_border; heightGroup->GetClientSize(&x, &height); off = y + imgset_hgtheight - height; height = (height - imgset_theight); posy = off + height/2; gridSize->SetSize(posx, posy, width/2 - imgset_border, imgset_theight, wxTE_PROCESS_ENTER); scaleHeight->SetSize(posx + width/2, posy, width/2, imgset_theight, wxTE_PROCESS_ENTER); y += imgset_hgtheight + imgset_border; off = (width - 2*imgset_bwidth) / 2; okBut->SetSize(posx + off/2, y, imgset_bwidth, imgset_bheight); cancelBut->SetSize(posx + (3*off)/2 + imgset_bwidth, y, imgset_bwidth, imgset_bheight); } int rviewImageSetup::process(wxObject &obj, wxEvent &evt) { int type; type = evt.GetEventType(); if (type == wxEVENT_TYPE_BUTTON_COMMAND) { if (&obj == (wxObject*)okBut) { readNewSetup(); if (parent != NULL) parent->closeEditor(TRUE); return 1; } else if (&obj == (wxObject*)cancelBut) { memcpy(imgSetup, &oldSetup, sizeof(rview_image_setup)); if (parent != NULL) parent->closeEditor(TRUE); return 1; } } else if ((type == wxEVENT_TYPE_TEXT_ENTER_COMMAND) || (type == wxEVENT_TYPE_CHECKBOX_COMMAND)) { int setFlags = -1; if ((&obj == (wxObject*)zproWidget) || (&obj == (wxObject*)clipzWidget) || (&obj == (wxObject*)useLights)) setFlags = 0; // These only require an update of the view-window when voxel mode is on. else if ((&obj == (wxObject*)pixThreshLowWidget) || (&obj == (wxObject*)pixThreshHighWidget) || (&obj == (wxObject*)wgtThreshWidget) || (&obj == (wxObject*)wgtQuantWidget) || (&obj == (wxObject*)useRgbBrightness)) setFlags = RVIEW_IFLAG_VOXEL; // These only require an update of the view-window when lights are on. else if ((&obj == (wxObject*)useVoxCol) || (&obj == (wxObject*)lightsAngle) || (&obj == (wxObject*)lightsScintAngle) || (&obj == (wxObject*)lightsAmbient) || (&obj == (wxObject*)lightsGain) || (&obj == (wxObject*)lightsDir) || (&obj == (wxObject*)lightsDist)) setFlags = RVIEW_IFLAG_LIGHT; // These only require an update of the view-window when height mode is on else if ((&obj == (wxObject*)gridSize) || (&obj == (wxObject*)scaleHeight)) setFlags = RVIEW_IFLAG_HEIGHT; // Mixed modes else if (&obj == (wxObject*)voxColour) setFlags = RVIEW_IFLAG_LIGHT | RVIEW_IFLAG_HEIGHT; if (setFlags >= 0) { readNewSetup(); if (parent != NULL) parent->updateSettings(setFlags); return 1; } } else if (type == wxEVENT_TYPE_CHOICE_COMMAND) { if ((&obj == (wxObject*)kernelSize) || (&obj == (wxObject*)kernelType)) { readNewSetup(); if (parent != NULL) parent->updateSettings(TRUE); return 1; } } return 0; } /* * rendererControl class. For advanced control of the renderers + animations */ const int rendererControl::rctrl_border = rviewDisplay::display_border; const int rendererControl::rctrl_bwidth = 80; const int rendererControl::rctrl_bheight = 30; const int rendererControl::rctrl_rwidth = 30; const int rendererControl::rctrl_rheight = 30; const int rendererControl::rctrl_sheight = 50; const int rendererControl::rctrl_width = 300; const int rendererControl::rctrl_height = 5*rendererControl::rctrl_border + 3*rendererControl::rctrl_sheight + rendererControl::rctrl_bheight + rview_window_extra_height; rendererControl::rendererControl(float drx, float dry, float drz, int mode, rviewRenderImage *parentWin) : rviewFrame(NULL, lman->lookup("titleRendererCtrl"), 0, 0, rctrl_width, rctrl_height) { int w; parent = parentWin; active = mode; panel = new wxPanel((wxWindow*)this, 0, 0, rctrl_width, rctrl_height); w = rctrl_width - 2*rctrl_border; rotx = new rviewSlider(panel, 1000*drx, -1000, 1000, w, lman->lookup("textRotX")); roty = new rviewSlider(panel, 1000*dry, -1000, 1000, w, lman->lookup("textRotY")); rotz = new rviewSlider(panel, 1000*drz, -1000, 1000, w, lman->lookup("textRotZ")); resetX = new rviewButton(panel, "0"); resetY = new rviewButton(panel, "0"); resetZ = new rviewButton(panel, "0"); actionBut = new rviewButton(panel); closeBut = new rviewButton(panel); label(); OnSize(rctrl_width, rctrl_height); Show(TRUE); } rendererControl::~rendererControl(void) { if (parent != NULL) { user_event ue; ue.type = usr_child_closed; ue.data = (void*)this; parent->userEvent(ue); } } const char *rendererControl::getFrameName(void) const { return "rendererControl"; } rviewFrameType rendererControl::getFrameType(void) const { return rviewFrameTypeRenCtrl; } void rendererControl::unlinkParent(void) { parent = NULL; } void rendererControl::OnSize(int w, int h) { int x, y, dx, dy; GetClientSize(&x, &y); panel->SetSize(0, 0, x, y, wxSIZE_ALLOW_MINUS_ONE); dx = (x - 2*rctrl_bwidth) / 2; dy = (rctrl_sheight - rctrl_rheight) / 2; x -= 3*rctrl_border + rctrl_rwidth; y = rctrl_border; rotx->SetSize(rctrl_border, y, x, rctrl_sheight); resetX->SetSize(2*rctrl_border + x, y+dy, rctrl_rwidth, rctrl_rheight); y += rctrl_border + rctrl_sheight; roty->SetSize(rctrl_border, y, x, rctrl_sheight); resetY->SetSize(2*rctrl_border + x, y+dy, rctrl_rwidth, rctrl_rheight); y += rctrl_border + rctrl_sheight; rotz->SetSize(rctrl_border, y, x, rctrl_sheight); resetZ->SetSize(2*rctrl_border + x, y+dy, rctrl_rwidth, rctrl_rheight); y += rctrl_border + rctrl_sheight; actionBut->SetSize(dx/2, y, rctrl_bwidth, rctrl_bheight); closeBut->SetSize((3*dx)/2 + rctrl_bwidth, y, rctrl_bwidth, rctrl_bheight); } void rendererControl::setActiveMode(int mode) { active = mode; actionBut->SetLabel(lman->lookup((active == 0) ? "textStart" : "textStop")); actionBut->SetSize(-1, -1, rctrl_bwidth, rctrl_bheight); } void rendererControl::label(void) { rotx->SetLabel(lman->lookup("textRotX")); roty->SetLabel(lman->lookup("textRotY")); rotz->SetLabel(lman->lookup("textRotZ")); closeBut->SetLabel(lman->lookup("textClose")); setActiveMode(active); } void rendererControl::updateParameters(void) { if (parent != NULL) { if (active == 0) { parent->setAutoRotation(1000.0, 1000.0, 1000.0); } else { parent->setAutoRotation((rotx->GetValue()) / 1000.0, (roty->GetValue()) / 1000.0, (rotz->GetValue()) / 1000.0); } } } int rendererControl::process(wxObject &obj, wxEvent &evt) { int type = evt.GetEventType(); if (type == wxEVENT_TYPE_SLIDER_COMMAND) { if ((&obj == (wxObject*)rotx) || (&obj == (wxObject*)roty) || (&obj == (wxObject*)rotz)) { updateParameters(); return 1; } } else if (type == wxEVENT_TYPE_BUTTON_COMMAND) { if (&obj == (wxObject*)actionBut) { setActiveMode(active ^ 1); updateParameters(); return 1; } else if (&obj == (wxObject*)closeBut) { if (parent != NULL) parent->closeRendererControls(); return 1; } else if ((&obj == (wxObject*)resetX) || (&obj == (wxObject*)resetY) || (&obj == (wxObject*)resetZ)) { if (&obj == (wxObject*)resetX) rotx->SetValue(0); else if (&obj == (wxObject*)resetY) roty->SetValue(0); else if (&obj == (wxObject*)resetZ) rotz->SetValue(0); updateParameters(); return 1; } } return 0; } /* * Renderer view window */ const int rendererCurrentView::rcview_border = rviewDisplay::display_border; const int rendererCurrentView::rcview_bwidth = 80; const int rendererCurrentView::rcview_bheight = 30; const int rendererCurrentView::rcview_theight = 30; const int rendererCurrentView::rcview_width = 180; const int rendererCurrentView::rcview_height = 220; rendererCurrentView::rendererCurrentView(const vertex_fp &angles, long off, double scale, rviewRenderImage *parentWin) : rviewFrame(NULL, lman->lookup("titleRendererView"), 0, 0, rcview_width, rcview_height) { parent = parentWin; panel = new wxPanel((wxWindow*)this, 0, 0, rcview_width, rcview_height); rotx = new rviewText(panel); roty = new rviewText(panel); rotz = new rviewText(panel); zoff = new rviewText(panel); cubeScale = new rviewText(panel); applyButton = new rviewButton(panel); closeButton = new rviewButton(panel); label(); updateView(angles, off, scale); OnSize(rcview_width, rcview_height); Show(TRUE); } rendererCurrentView::~rendererCurrentView(void) { if (parent != NULL) { user_event ue; ue.type = usr_child_closed; ue.data = (void*)this; parent->userEvent(ue); } } const char *rendererCurrentView::getFrameName(void) const { return "rendererCurrentView"; } rviewFrameType rendererCurrentView::getFrameType(void) const { return rviewFrameTypeRenView; } void rendererCurrentView::unlinkParent(void) { parent = NULL; } void rendererCurrentView::OnSize(int w, int h) { int x, y; GetClientSize(&x, &y); panel->SetSize(0, 0, w, h, wxSIZE_ALLOW_MINUS_ONE); x -= 2*rcview_border; rotx->SetSize(rcview_border, rcview_border, x, rcview_theight); roty->SetSize(rcview_border, rcview_border + rcview_theight, x, rcview_theight); rotz->SetSize(rcview_border, rcview_border + 2*rcview_theight, x, rcview_theight); zoff->SetSize(rcview_border, rcview_border + 3*rcview_theight, x, rcview_theight); cubeScale->SetSize(rcview_border, rcview_border + 4*rcview_theight, x, rcview_theight); x -= 2*rcview_bwidth; if (x < 0) x = 0; applyButton->SetSize(rcview_border + x/4, 3*rcview_border + 5*rcview_theight, rcview_bwidth, rcview_bheight); closeButton->SetSize(rcview_border + (3*x)/4 + rcview_bwidth, 3*rcview_border + 5*rcview_theight, rcview_bwidth, rcview_bheight); } void rendererCurrentView::label(void) { rotx->SetLabel(lman->lookup("textRotX")); roty->SetLabel(lman->lookup("textRotY")); rotz->SetLabel(lman->lookup("textRotZ")); zoff->SetLabel(lman->lookup("textZOffset")); cubeScale->SetLabel(lman->lookup("textScale")); applyButton->SetLabel(lman->lookup("textApply")); closeButton->SetLabel(lman->lookup("textClose")); } int rendererCurrentView::process(wxObject &obj, wxEvent &evt) { int type = evt.GetEventType(); if (type == wxEVENT_TYPE_BUTTON_COMMAND) { if (&obj == (wxObject*)applyButton) { updateParameters(); return 1; } else if (&obj == (wxObject*)closeButton) { Close(TRUE); return 1; } } else if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND) { updateParameters(); return 1; } return 0; } void rendererCurrentView::updateView(const vertex_fp &angles, long off, double scale) { rotx->SetValue((double)angles.x); roty->SetValue((double)angles.y); rotz->SetValue((double)angles.z); zoff->SetValue(off); cubeScale->SetValue(scale); } void rendererCurrentView::updateParameters(void) { if (parent != NULL) { vertex_fp angles; angles.x = atof(rotx->GetValue()); angles.y = atof(roty->GetValue()); angles.z = atof(rotz->GetValue()); parent->setCurrentView(angles, atoi(zoff->GetValue()), atof(cubeScale->GetValue())); } } /* * pixmapCanvas class. For displaying wxPixmaps */ pixmapCanvas::pixmapCanvas(rviewImage *parent, int x, int y, int w, int h, long style) : wxCanvas((wxWindow*)parent, x, y, w, h, style) { pixmap = NULL; font = NULL; parentWin = parent; myDC = (wxDC*)GetDC(); brush.SetStyle(wxSOLID); brush.SetColour(0,0,0); border.SetStyle(wxSOLID); border.SetColour(0,0,0); bpen.SetStyle(wxSOLID); bpen.SetColour(0,0,0); // Pen used for frames fpen.SetStyle(wxSOLID); fpen.SetColour((char)0xff, (char)0xff, (char)0xff); fpen.SetCap(wxCAP_BUTT); fpen.SetJoin(wxJOIN_BEVEL); SetBackground(&brush); rect_x0 = -1; rect_y0 = -1; rect_x1 = -1; rect_y1 = -1; aspectRatio = 0; } // Don't delete the pixmap! This is not our job. pixmapCanvas::~pixmapCanvas(void) { if (font != NULL) { SetFont(NULL); delete font; } SetBackground(NULL); } void pixmapCanvas::setPixmap(wxPixmap *pmap) { pixmap = pmap; pixWidth = pmap->getWidth(); pixHeight = pmap->getHeight(); if (rect_x0 >= 0) { if (((rect_x0 >= pixWidth) && (rect_x1 >= pixWidth)) || ((rect_y0 >= pixHeight) && (rect_y1 >= pixHeight))) { rect_x0 = -1; rect_y0 = -1; rect_x1 = -1; rect_y1 = -1; } else { if (rect_x0 >= pixWidth) rect_x0 = pixWidth-1; if (rect_x1 >= pixWidth) rect_x1 = pixWidth-1; if (rect_y0 >= pixHeight) rect_y0 = pixHeight-1; if (rect_y1 >= pixHeight) rect_y1 = pixHeight-1; } } } void pixmapCanvas::SetAspectRatio(double ratio) { aspectRatio = ratio; } void pixmapCanvas::adjustBoxToRatio(void) { if ((rect_x0 >= 0) && (aspectRatio > 0)) { int width, height; width = rect_x1 - rect_x0; if (width < 0) width = -width; height = (int)(width * aspectRatio); if (rect_y1 < rect_y0) height = -height; rect_y1 = rect_y0 + height; if ((rect_y1 < 0) || (rect_y1 >= pixHeight)) { if (rect_y1 < 0) rect_y1 = 0; else rect_y1 = pixHeight-1; height = rect_y1 - rect_y0; if (height < 0) height = -height; width = (int)(height / aspectRatio); if (rect_x1 < rect_x0) width = -width; rect_x1 = rect_x0 + width; } } } void pixmapCanvas::ToggleDragBox(bool clearMode) { int minx, miny, maxx, maxy; // Drag box defined? if (rect_x0 < 0) return; if (rect_x0 < rect_x1) { minx = rect_x0; maxx = rect_x1; } else { minx = rect_x1; maxx = rect_x0; } if (rect_y0 < rect_y1) { miny = rect_y0; maxy = rect_y1; } else { miny = rect_y1; maxy = rect_y0; } // Only redraw the drag box if it's visible... if ((rect_x0 != rect_x1) && (rect_y0 != rect_y1)) { int ominx, ominy, omaxx, omaxy; SetLogicalFunction(wxINVERT); SetPen(&fpen); //cout << "Draw " << minx << ',' << miny << ',' << maxx << ',' << maxy << endl; ominx = minx + offX; ominy = miny + offY; omaxx = maxx + offX; omaxy = maxy + offY; SetClippingRegion((float)ominx, (float)ominy, omaxx-ominx+1.0, omaxy-ominy+1.0); IntDrawLine(ominx, ominy, omaxx - 1, ominy); IntDrawLine(omaxx, ominy, omaxx, omaxy - 1); IntDrawLine(omaxx, omaxy, ominx + 1, omaxy); IntDrawLine(ominx, omaxy, ominx, ominy + 1); DestroyClippingRegion(); } if ((rect_x0 == rect_x1) && (rect_y0 == rect_y1) && !clearMode) return; // Is the old rectangle to be removed or the new one to be plotted? // This makes a difference with the text! if (clearMode) { Refresh(FALSE, &textBBox); } else { float posx, posy, twidth, theight; char buffer[STRINGSIZE]; // Create font on demand only if (font == NULL) { // Do not use pure white as background, this isn't handled correctly under X wxColour tfore(0, 0, 0), tback((char)0xf0, (char)0xf0, (char)0xf0); font = new wxFont(12, wxROMAN, wxNORMAL, wxNORMAL); SetFont(font); SetTextForeground(&tfore); SetTextBackground(&tback); textBack.SetColour(tback); textBack.SetStyle(wxSOLID); } SetBrush(&textBack); SetPen(&bpen); SetLogicalFunction(wxCOPY); sprintf(buffer, "%d:%d, %d:%d", minx, maxx, miny, maxy); GetTextExtent(buffer, &twidth, &theight); posx = minx + offX + rviewImage::image_dragtoff; posy = miny + offY + rviewImage::image_dragtoff; #ifdef wx_msw textBBox.x = (int)posx - rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL); textBBox.y = (int)posy - rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL); #else textBBox.x = (int)posx; textBBox.y = (int)posy; #endif twidth += rviewImage::image_dragtspace; theight += rviewImage::image_dragtspace; textBBox.width = (int)twidth; textBBox.height = (int)theight; DrawRectangle(posx, posy, twidth, theight); DrawText(buffer, posx + rviewImage::image_dragtspace/2, posy + rviewImage::image_dragtspace/2); SetBrush(NULL); } SetPen(NULL); } void pixmapCanvas::SetDragBox(int x0, int y0, int x1, int y1) { int scrollX, scrollY; ToggleDragBox(TRUE); scrollX = 0;//rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL); scrollY = 0;//rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL); rect_x0 = x0 - offX + scrollX; rect_y0 = y0 - offY + scrollY; rect_x1 = x1 - offX + scrollX; rect_y1 = y1 - offY + scrollY; if (((rect_x0 < 0) && (rect_x1 < 0)) || ((rect_x0 >= pixWidth) && (rect_x1 >= pixWidth)) || ((rect_y0 < 0) && (rect_y1 < 0)) || ((rect_y0 >= pixHeight) && (rect_y1 >= pixHeight))) { rect_x0 = -1; rect_y0 = -1; rect_x1 = -1; rect_y1 = -1; return; } adjustBoxToRatio(); if (rect_x0 < 0) rect_x0 = 0; if (rect_x0 >= pixWidth) rect_x0 = pixWidth-1; if (rect_y0 < 0) rect_y0 = 0; if (rect_y0 >= pixHeight) rect_y0 = pixHeight-1; if (rect_x1 < 0) rect_x1 = 0; if (rect_x1 >= pixWidth) rect_x1 = pixWidth-1; if (rect_y1 < 0) rect_y1 = 0; if (rect_y1 >= pixHeight) rect_y1 = pixHeight-1; ToggleDragBox(FALSE); } bool pixmapCanvas::HasDragBox(void) const { return ((rect_x0 >= 0) && (rect_x0 != rect_x1)); } bool pixmapCanvas::GetDragBox(int &x0, int &y0, int &x1, int &y1) const { if ((rect_x0 < 0) || (rect_x0 == rect_x1)) return FALSE; // output sorted: x0 < x1, y0 < y1 if (rect_x0 < rect_x1) { x0 = rect_x0; x1 = rect_x1; } else { x0 = rect_x1; x1 = rect_x0; } if (rect_y0 < rect_y1) { y0 = rect_y0; y1 = rect_y1; } else { y0 = rect_y1; y1 = rect_y0; } return TRUE; } void pixmapCanvas::UpdateDragBox(int x1, int y1) { if (rect_x0 < 0) return; ToggleDragBox(TRUE); rect_x1 = x1 - offX; if (rect_x1 < 0) rect_x1 = 0; if (rect_x1 >= pixWidth) rect_x1 = pixWidth-1; rect_y1 = y1 - offY; if (rect_y1 < 0) rect_y1 = 0; if (rect_y1 >= pixHeight) rect_y1 = pixHeight-1; adjustBoxToRatio(); ToggleDragBox(FALSE); #if 0 int width, height; int scrollX, scrollY; int mapX, mapY; scrollX = GetScrollPos(wxHORIZONTAL); scrollY = GetScrollPos(wxVERTICAL); mapX = x1 - scrollX * rviewDisplay::display_scrstep; mapY = y1 - scrollY * rviewDisplay::display_scrstep; // Autoscroll? GetClientSize(&width, &height); if (width >= 2*rviewImage::image_draghotzone) { if (mapX < rviewImage::image_draghotzone) { scrollX -= (rviewImage::image_draghotzone - mapX + rviewDisplay::display_scrstep-1) / rviewDisplay::display_scrstep; if (scrollX >= 0) { SetScrollPos(wxHORIZONTAL, scrollX); x1 = rviewImage::image_draghotzone + (x1-mapX); WarpPointer(x1, y1); } } else if (mapX > (width - rviewImage::image_draghotzone)) { scrollX += (mapX - width + rviewImage::image_draghotzone + rviewDisplay::display_scrstep-1) / rviewDisplay::display_scrstep; if (scrollX <= GetScrollRange(wxHORIZONTAL)) { SetScrollPos(wxHORIZONTAL, scrollX); x1 = (width - rviewImage::image_draghotzone) + (x1-mapX); WarpPointer(x1, y1); } } } if (height >= 2*rviewImage::image_draghotzone) { if (mapY < rviewImage::image_draghotzone) { scrollY -= (rviewImage::image_draghotzone - mapY + rviewDisplay::display_scrstep-1) / rviewDisplay::display_scrstep; if (scrollY >= 0) { SetScrollPos(wxVERTICAL, scrollY); WarpPointer(x1, rviewImage::image_draghotzone + scrollY * rviewDisplay::display_scrstep); } } else if (mapY > (height - rviewImage::image_draghotzone)) { scrollY += (mapY - height + rviewImage::image_draghotzone + rviewDisplay::display_scrstep-1) / rviewDisplay::display_scrstep; if (scrollY <= GetScrollRange(wxVERTICAL)) { SetScrollPos(wxVERTICAL, scrollY); WarpPointer(x1, height-rviewImage::image_draghotzone + scrollY * rviewDisplay::display_scrstep); } } } #endif } void pixmapCanvas::AdjustDragBox(int x1, int y1) { if (rect_x0 < 0) SetDragBox(x1, y1, x1, y1); else { ToggleDragBox(TRUE); x1 = x1 - offX;// + rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL); if (x1 < 0) x1 = 0; if (x1 >= pixWidth) x1 = pixWidth-1; y1 = y1 - offY;// + rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL); if (y1 < 0) y1 = 0; if (y1 >= pixHeight) y1 = pixHeight-1; if (abs(x1 - rect_x0) < abs(x1 - rect_x1)) rect_x0 = rect_x1; if (abs(y1 - rect_y0) < abs(y1 - rect_y1)) rect_y0 = rect_y1; rect_x1 = x1; rect_y1 = y1; adjustBoxToRatio(); ToggleDragBox(FALSE); } } // Core functionality for plotting picture + border void pixmapCanvas::paintCore(int x, int y) { int sx, sy; GetSize(&sx, &sy); if ((offX > 0) || (offY > 0)) { float bordx, bordy, height; bordx = (float)offX; bordy = (float)offY; height = (float)sy; SetLogicalFunction(wxCOPY); SetPen(&bpen); SetBrush(&border); if (offX > 0) { DrawRectangle(0.0, 0.0, bordx, height); DrawRectangle(bordx + pixWidth, 0.0, bordx+1, height); } if (offY > 0) { DrawRectangle(bordx, 0.0, (float)pixWidth, bordy); DrawRectangle(bordx, bordy + pixHeight, (float)pixWidth, bordy+1); } SetPen(NULL); SetBrush(NULL); } pixmap->plotPixmap(offX - x, offY - y); ToggleDragBox(FALSE); } void pixmapCanvas::OnPaint(void) { wxUpdateIterator upd(this); wxRect rect; int w, h, x, y; GetClientSize(&w, &h); x = rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL); y = rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL); offX = (w - pixWidth) / 2; if (offX < 0) offX = 0; offY = (h - pixHeight) / 2; if (offY < 0) offY = 0; BeginDrawing(); while (upd) { //upd.GetRect(&rect); paintCore(x, y); upd++; } EndDrawing(); } void pixmapCanvas::updateDisplay(bool borders) { if (parentWin->IsShown()) { int cw, ch; int x, y; x = rviewDisplay::display_scrstep * GetScrollPos(wxHORIZONTAL); y = rviewDisplay::display_scrstep * GetScrollPos(wxVERTICAL); GetClientSize(&cw, &ch); offX = (cw - pixWidth)/2; if (offX < 0) offX = 0; offY = (ch - pixHeight)/2; if (offY < 0) offY = 0; pixmap->invalidatePixmap(); if (borders) { int sx, sy; GetVirtualSize(&sx, &sy); sx *= rviewDisplay::display_scrstep; sy *= rviewDisplay::display_scrstep; SetClippingRegion(0, 0, sx, sy); paintCore(x, y); } else { SetClippingRegion(offX, offY, pixWidth, pixHeight); paintCore(x, y); } DestroyClippingRegion(); } } void pixmapCanvas::OnEvent(wxMouseEvent &mevt) { parentWin->processMouseEvent(mevt); } /* * rviewImage members */ const int rviewImage::image_swidth = 100; const int rviewImage::image_sheight = 40; const int rviewImage::image_pbwidth = rviewDisplay::display_pbwidth; const int rviewImage::image_pbheight = 30; const int rviewImage::image_minwidth = 50; const int rviewImage::image_minheight = 50; const int rviewImage::image_chkwidth = 80; const int rviewImage::image_chkheight = 30; const int rviewImage::image_bbwidth = 60; const int rviewImage::image_bbheight = 20; const int rviewImage::image_twidth = 100; const int rviewImage::image_theight = 50; const int rviewImage::image_bwidth = 64; const int rviewImage::image_bheight = 30; const int rviewImage::image_dragtoff = 8; const int rviewImage::image_dragtspace = 8; const int rviewImage::image_draghotzone = 32; const int rviewImage::image_ctrly = 60; const int rviewImage::image_totaly = rviewDisplay::display_cheight + rviewImage::image_ctrly; const char *rviewImage::view_ScrollPos = "scrollPos"; const char *rviewImage::view_UseCspace = "useCspace"; const char *rviewImage::view_CspaceFull = "cspaceFull"; const char *rviewImage::view_CspaceProj = "cspaceProj"; const char *rviewImage::view_CspaceMeans = "cspaceMeans"; const char *rviewImage::view_CspaceSigmas = "cspaceSigmas"; const char *rviewImage::view_CspaceType = "cspaceType"; const char *rviewImage::view_CspaceRange = "cspaceRange"; const char *rviewImage::view_ScaleValue = "scaleValue"; rviewImage::rviewImage(mdd_frame *mf, int es, unsigned int flags) : rviewDisplay(mf, es+image_ctrly, flags) { RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "rviewImage()"); // make destructor safe first. csmap = NULL; // signifies no data for value->colourspace mapping initialised yet csInterv = NULL; pixmap = NULL; pcanv = NULL; scaleSlider = NULL; cspar = NULL; // This variable is set to true once openViewerEpilogue() is called. Its main use is // 1) on Windows: trap calls to OnSize() happening before the object is fully initialized // 2) for the renderers: avoid actually drawing anything until the window size is fixed. initPhaseFinished = FALSE; // Check the base type immediately: if (baseType == rbt_none) { objectInitializedOK = FALSE; return; } #if 0 // Test resampling routines... r_Ref mddPtr; r_Minterval newInterv(dimMDD); //for (i=0; ispatial_domain()[i].low(), 4*mddObj->spatial_domain()[i].high()); //mdd_objectScaleInter(mddObj, mddPtr, newInterv, baseType); for (i=0; ispatial_domain()[i].low()), (r_Range)(0.5*mddObj->spatial_domain()[i].high())); mdd_objectScaleAverage(mddObj, mddPtr, newInterv, baseType); mddObj.destroy(); mddObj = mddPtr; interv = mddObj->spatial_domain(); #endif } rviewImage::~rviewImage(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "~rviewImage()"); if (cspar != NULL) delete cspar; if (csmap != NULL) delete csmap; if (csInterv != NULL) delete csInterv; delete pixmap; } // concentrate most intelligence in this function rather than the constructor // because we can't use virtual functions (correctly) in the constructor. int rviewImage::openViewer(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "openViewer()"); if (!objectInitializedOK) return -1; // init lower level stuff like the menu bar rviewDisplay::openViewer(); wxMenu *config; wxMenu *submenu; char buffer[STRINGSIZE]; config = new wxMenu; configMenuInitHook(config); submenu = new wxMenu; submenu->Append(MENU_IMAGE_CSPACE_ON, "", NULL, TRUE); submenu->Append(MENU_IMAGE_CSPACE_FULL, "", NULL, TRUE); submenu->Append(MENU_IMAGE_CSPACE_PROJ, "", NULL, TRUE); submenu->Append(MENU_IMAGE_CSPACE_EDIT, ""); config->Append(MENU_IMAGE_SETUP_CSPACE, lman->lookup("menCspaceTitle"), submenu, NULL); if (moviePossible()) { submenu = new wxMenu; submenu->Append(MENU_IMAGE_MOVIE_ONCE, "", NULL, TRUE); submenu->Append(MENU_IMAGE_MOVIE_START, "", NULL, TRUE); submenu->Append(MENU_IMAGE_MOVIE_SWITCH, "", NULL, TRUE); config->AppendSeparator(); config->Append(MENU_IMAGE_SETUP_MOVIE, lman->lookup("menImgSetupMovie"), submenu, NULL); } sprintf(buffer, "&%s", lman->lookup("menImgSetup")); mBar->Append(config, buffer); mBar->Enable(MENU_IMAGE_CSPACE_EDIT, FALSE); pcanv = NULL; imgData = NULL; scaleValue = 100.0; // Colourspace mapper doValToCspace = (prefs->rgbSpace != 0); doFullRangeCspace = (prefs->rgbSpace == 2); // We're not allowed to call setCspaceProjMode before a projection is set // in the init... functions doProjRangeCspace = (prefs->rgbSpace == 3); if (modeNeedsCspace(baseType)) doValToCspace = TRUE; mousex = -1.0; mousey = -1.0; mousebut = 0; if (showScaleSlider()) scaleSlider = new rviewSlider(ctrlPanel, (int)scaleValue, 0, 500, image_swidth, lman->lookup("textScale")); if (rviewCheckInitCspace(baseType, NULL, mddObj) != 0) { mBar->Check(MENU_IMAGE_CSPACE_ON, doValToCspace); mBar->Check(MENU_IMAGE_CSPACE_FULL, doFullRangeCspace); mBar->Check(MENU_IMAGE_CSPACE_PROJ, doProjRangeCspace); mBar->Enable(MENU_IMAGE_CSPACE_FULL, doValToCspace); mBar->Enable(MENU_IMAGE_CSPACE_PROJ, doValToCspace); mBar->Enable(MENU_IMAGE_CSPACE_EDIT, doValToCspace); cspaceForType = TRUE; } else { cspaceForType = FALSE; } configureCspace(cspaceForType); if (moviePossible()) { switch (prefs->movieMode) { case 1: lastMovieMode = MENU_IMAGE_MOVIE_START; break; case 2: lastMovieMode = MENU_IMAGE_MOVIE_SWITCH; break; default: lastMovieMode = MENU_IMAGE_MOVIE_ONCE; break; } playDirection = 0; playBack = new rviewButton(ctrlPanel, "<"); playStop = new rviewButton(ctrlPanel, "[]"); playFwd = new rviewButton(ctrlPanel, ">"); mBar->Check(lastMovieMode, TRUE); } else { playBack = NULL; playStop = NULL; playFwd = NULL; } configureMode(); wxColour palette[2]; int w, h; GetClientSize(&w, &h); w -= 2*display_cnvborder; h -= 2*display_cnvborder + totalCtrlHeight; pcanv = new pixmapCanvas(this, display_cnvborder, display_cnvborder + totalCtrlHeight, w, h); scrollx = -1; scrolly = -1; pixWidth = -1; pixHeight = -1; pixPitch = -1; pixPad = 0; pixDepth = 0; virtualPitch = -1; if (initMode() == NULL) { objectInitializedOK = FALSE; return -1; } pcanv->Clear(); if (rviewImageTypes[baseType] == RVIEW_IMGTYPE_MONO) { palette[0] = wxColour(0,0,0); palette[1] = wxColour(255,255,255); } pixmap = new wxPixmap((wxWindow*)pcanv, pixWidth, pixHeight, pixDepth, pixPad, imgData, getPixmapFlags(), ((rviewImageTypes[baseType] == RVIEW_IMGTYPE_MONO) ? palette : NULL)); pcanv->setPixmap(pixmap); return 0; } void rviewImage::openViewerEpilogue(rviewFrameType ft) { // Only do something if this was called from the top level image class, i.e. the // one that overloads getFrameType(). Otherwise NOP. if (ft == getFrameType()) { int w, h; initPhaseFinished = TRUE; RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "openViewerEpilogue() from top level " << getFrameName() ); label(); setMinimumViewerSize(image_minwidth, image_minheight); GetSize(&w, &h); OnSize(w, h); OnSize(w, h); Show(TRUE); } } int rviewImage::freeDimsFromProjection(int &dim1, int &dim2, r_Point *map) { // Apply the projection string if (rviewParseProjection(getVirtualDomain(), pt1, pt2, projString, &freeDims, map) != dimMDD) { rviewErrorbox::reportError(lman->lookup("errorProjection"), rviewImage::getFrameName(), "freeDimsFromProjection"); return -1; } // Check whether there are more or less than 2 free dimensions. for (dim1=0; dim1= dimMDD) || (dim2 >= dimMDD)) { rviewErrorbox::reportError(lman->lookup("errorProjectFree"), rviewImage::getFrameName(), "freeDimsFromProjection"); return -1; } if (map != NULL) { dim1 = (*map)[dim1]; dim2 = (*map)[dim2]; } return 0; } void rviewImage::projectObjectHook(void) { } const char *rviewImage::getFrameName(void) const { return "rviewImage"; } rviewFrameType rviewImage::getFrameType(void) const { return rviewFrameTypeImage; } int rviewImage::fileMenuInitHook(wxMenu *menu) { menu->Append(MENU_DISP_DATA_SAVETIFF, ""); return 1; } bool rviewImage::modeNeedsCspace(rviewBaseType bt) const { return ((bt == rbt_float) || (bt == rbt_double)); } void rviewImage::configureCspace(bool state) { mBar->Enable(MENU_IMAGE_SETUP_CSPACE, state); // Bug (feature?) in WinNT version: menu having submenu can't be disabled. mBar->Enable(MENU_IMAGE_CSPACE_ON, state); mBar->Enable(MENU_IMAGE_CSPACE_FULL, state); mBar->Enable(MENU_IMAGE_CSPACE_PROJ, state); mBar->Enable(MENU_IMAGE_CSPACE_EDIT, state); } int rviewImage::configMenuInitHook(wxMenu *menu) { return 0; } bool rviewImage::cspaceRangeHook(bool suggest) { return suggest; } void rviewImage::configureMode(void) { bool csranges; if (modeNeedsCspace(baseType)) doValToCspace = TRUE; csranges = cspaceRangeHook((cspaceForType && doValToCspace)); if (doValToCspace) { mBar->Enable(MENU_IMAGE_CSPACE_ON, doValToCspace); mBar->Enable(MENU_IMAGE_CSPACE_EDIT, doValToCspace); } mBar->Enable(MENU_IMAGE_CSPACE_FULL, csranges); mBar->Enable(MENU_IMAGE_CSPACE_PROJ, csranges); mBar->Check(MENU_IMAGE_CSPACE_ON, doValToCspace); } void rviewImage::setCspaceProjMode(bool pm) { if (pm) { int i=0; r_Minterval tempInterv(dimMDD); if(!csInterv) csInterv = new r_Minterval(dimMDD); for (i=0; iSetLabel(lman->lookup("textScale")); mBar->SetLabelTop(fixedNumberOfMenus, lman->lookup("menImgSetup")); mBar->SetLabel(MENU_IMAGE_SETUP_CSPACE, lman->lookup("menCspaceTitle")); mBar->SetLabel(MENU_IMAGE_CSPACE_ON, lman->lookup("menCspaceOn")); mBar->SetLabel(MENU_IMAGE_CSPACE_FULL, lman->lookup("menCspaceFull")); mBar->SetLabel(MENU_IMAGE_CSPACE_PROJ, lman->lookup("menCspaceProj")); mBar->SetLabel(MENU_IMAGE_CSPACE_EDIT, lman->lookup("menCspaceEdit")); if (moviePossible()) { mBar->SetLabel(MENU_IMAGE_SETUP_MOVIE, lman->lookup("menImgSetupMovie")); mBar->SetLabel(MENU_IMAGE_MOVIE_ONCE, lman->lookup("menImgMovieOnce")); mBar->SetLabel(MENU_IMAGE_MOVIE_START, lman->lookup("menImgMovieStart")); mBar->SetLabel(MENU_IMAGE_MOVIE_SWITCH, lman->lookup("menImgMovieSwitch")); } mBar->SetLabel(MENU_DISP_DATA_SAVETIFF, lman->lookup("menDispDataSaveTIFF")); rviewDisplay::label(); } char *rviewImage::movieNewFrame(void) { return NULL; } int rviewImage::process(wxObject &obj, wxEvent &evt) { RMDBGENTER(3, RMDebug::module_applications, "rviewImage", "process()"); int type = evt.GetEventType(); if (rviewDisplay::process(obj, evt) != 0) { return 1; } if (type == wxEVENT_TYPE_BUTTON_COMMAND) { if (moviePossible()) { int oldDirection = playDirection; if (&obj == (wxObject*)playStop) { RMDBGMIDDLE(3, RMDebug::module_applications, "rviewImage", "process() Playback stop" ); playDirection = 0; return 1; } if (&obj == (wxObject*)playBack) playDirection = -1; else if (&obj == (wxObject*)playFwd) playDirection = 1; // Only enter the loop if we didn't have playback before to avoid reentrancy. if ((oldDirection == 0) && (playDirection != 0)) { char *data, *lastData; RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "process() Playback start " << playDirection ); do { while (advanceProjection(playDirection) != 0) { lastData = imgData; data = movieNewFrame(); if (data == NULL) { playDirection = 0; return 0; } updatePixmap(lastData, data); ::wxYield(); // Order is _vitally _ important here. Check _after_ the call to ::wxYield()! if (playDirection == 0) break; } // Allow for one NULL cycle after playback (ensures no infinite loops if playback // dimension is only 1 element wide. ::wxYield(); if (playDirection != 0) { if (mBar->Checked(MENU_IMAGE_MOVIE_ONCE)) playDirection = 0; else if (mBar->Checked(MENU_IMAGE_MOVIE_START)) { advanceProjection(-playDirection, display_advmode_reset); } else playDirection = -playDirection; } } while (playDirection != 0); } return 1; } } return 0; } bool rviewImage::moviePossible(void) const { return FALSE; } bool rviewImage::canRotateObject(void) const { return FALSE; } bool rviewImage::showScaleSlider(void) const { return TRUE; } void rviewImage::rotateObject(wxMouseEvent &mevt) { } void rviewImage::processMouseEvent(wxMouseEvent &mevt) { RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "processMouseEvent()" ); int newbut=0; if (mevt.ControlDown()) newbut = MOUSE_CONTROL; else if (!canRotateObject()) {mousebut = 0; return;} if (mevt.leftDown) newbut |= MOUSE_LEFT; if (mevt.middleDown) newbut |= MOUSE_MIDDLE; if (mevt.rightDown) newbut |= MOUSE_RIGHT; if (((newbut & MOUSE_CONTROL) == 0) && canRotateObject()) { rotateObject(mevt); } else { // Drag a box if ((newbut & MOUSE_LEFT) != 0) { if ((mousebut & MOUSE_LEFT) == 0) { pcanv->SetDragBox(mevt.x, mevt.y, mevt.x, mevt.y); } else { pcanv->UpdateDragBox(mevt.x, mevt.y); } } else if ((newbut & MOUSE_RIGHT) != 0) { if ((mousebut & MOUSE_RIGHT) == 0) { pcanv->AdjustDragBox(mevt.x, mevt.y); } else { pcanv->UpdateDragBox(mevt.x, mevt.y); } } } mousebut = newbut; mousex = mevt.x; mousey = mevt.y; } void rviewImage::updatePixmap(char *oldData, char *newData) { RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "updatePixmap()" ); if (pixmap == NULL) return; if (oldData != newData) { pixmap->newPixmap((wxWindow*)pcanv, pixWidth, pixHeight, pixDepth, pixPad, imgData, getPixmapFlags() | WX_PIXFLAG_SAMEPALETTE); pcanv->setPixmap(pixmap); } pcanv->updateDisplay((oldData != newData)); } int rviewImage::getPixmapFlags(void) { int pixflags = WX_PIXFLAG_TRANSLATE; if (prefs->imgDither) { if (prefs->ditherBest) pixflags |= WX_PIXFLAG_DITHER; else pixflags |= WX_PIXFLAG_FASTDITHER; } return pixflags; } void rviewImage::OnSize(int w, int h) { int x, y, pos; bool resize=false; RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "OnSize " << w << ", " << h ); // fully initialized yet? if (initPhaseFinished) { GetClientSize(&x, &y); if ((frameWidth == w) && (frameHeight == h)) return; frameWidth = w; frameHeight = h; x -= 2*display_cnvborder; y -= 2*display_cnvborder + totalCtrlHeight; pcanv->SetSize(display_cnvborder, display_cnvborder + totalCtrlHeight, x, y); // Ctrl panel items if (scaleSlider != NULL) scaleSlider->SetSize(display_border, image_totaly - image_sheight, x, image_sheight); pos = x - 3*image_pbwidth - display_border + 2*display_cnvborder; // Buttons might not be present if (playBack != NULL) playBack->SetSize(pos, display_cheight, image_pbwidth, image_pbheight); if (playStop != NULL) playStop->SetSize(pos + image_pbwidth, display_cheight, image_pbwidth, image_pbheight); if (playFwd != NULL) playFwd->SetSize(pos + 2*image_pbwidth, display_cheight, image_pbwidth, image_pbheight); } rviewDisplay::OnSize(w, h); } void rviewImage::OnMenuCommand(int id) { RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "OnMenuCommand()" ); switch (id) { case MENU_DISP_DATA_SAVETIFF: { char *file; char *prefDir = (char*)(prefs->filePath.ptr()); file = ::wxFileSelector(lman->lookup("saveTIFF"), (::wxDirExists(prefDir)) ? prefDir : NULL, NULL, NULL, "*", 0, this); if (file != NULL) { ::wxBeginBusyCursor(); rviewIO::PixmapToTIFF(pixmap, file, prefs->vffParams.ptr()); prefs->filePath = ::wxPathOnly(file); ::wxEndBusyCursor(); } } break; case MENU_IMAGE_CSPACE_EDIT: if (csmap != NULL) { csmap->openEditor(); } break; case MENU_IMAGE_MOVIE_ONCE: case MENU_IMAGE_MOVIE_START: case MENU_IMAGE_MOVIE_SWITCH: if (moviePossible()) { mBar->Check(lastMovieMode, FALSE); mBar->Check(id, TRUE); lastMovieMode = id; } break; case MENU_IMAGE_CSPACE_ON: case MENU_IMAGE_CSPACE_FULL: case MENU_IMAGE_CSPACE_PROJ: { if (id == MENU_IMAGE_CSPACE_ON) { // You're not allowed to leave cspace mode for these type/mode combinations if (modeNeedsCspace(baseType)) { mBar->Check(MENU_IMAGE_CSPACE_ON, TRUE); } else { doValToCspace = mBar->Checked(MENU_IMAGE_CSPACE_ON); mBar->Enable(MENU_IMAGE_CSPACE_FULL, doValToCspace); mBar->Enable(MENU_IMAGE_CSPACE_PROJ, doValToCspace); mBar->Enable(MENU_IMAGE_CSPACE_EDIT, doValToCspace); } } else if (id == MENU_IMAGE_CSPACE_FULL) { doFullRangeCspace = mBar->Checked(MENU_IMAGE_CSPACE_FULL); if (csmap != NULL) { csmap->processRange((doFullRangeCspace) ? CSPACE_RANGE_FULL : CSPACE_RANGE_ACTUAL); } } else if (id == MENU_IMAGE_CSPACE_PROJ) { setCspaceProjMode(mBar->Checked(MENU_IMAGE_CSPACE_PROJ)); if (csmap != NULL) { csmap->updateProjection(csInterv); } } newProjection(); } break; default: rviewDisplay::OnMenuCommand(id); break; } } // Refuse to be killed if animation is in progress bool rviewImage::OnClose(void) { if (playDirection != 0) return FALSE; return TRUE; } int rviewImage::userEvent(const user_event &ue) { RMDBGONCE(3, RMDebug::module_applications, "rviewImage", "userEvent()" ); if ((ue.type == usr_cspace_changed) && (ue.data == (void*)csmap) && (doValToCspace)) { // The csmapper has already updated the tables and internal information newProjection(); return 1; } // Don't intercept unknown messages! return rviewDisplay::userEvent(ue); } void rviewImage::prepareToDie(void) { // Stop movie-playback immediately. playDirection = 0; ::wxYield(); } int rviewImage::requestQuit(int level) { playDirection = 0; return rviewFrame::requestQuit(level); } void rviewImage::resizeImage(void) { int x, y, sx, sy; if (scrollx >= 0) scrollx = pcanv->GetScrollPos(wxHORIZONTAL); else scrollx = 0; if (scrolly >= 0) scrolly = pcanv->GetScrollPos(wxVERTICAL); else scrolly = 0; pcanv->GetVirtualSize(&x, &y); sx = (pixWidth + display_scrstep - 1) / display_scrstep; sy = (pixHeight + display_scrstep - 1) / display_scrstep; // Only update the canvas size if this is absolutely necessary to avoid flicker. if ((x != display_scrstep*sx) || (y != display_scrstep*sy)) { pcanv->SetScrollbars(display_scrstep, display_scrstep, sx, sy, display_pgstep, display_pgstep, scrollx, scrolly); } } void rviewImage::ensureViewCspace(void) { if (cspar == NULL) { cspar = new colourspace_params; memset(cspar, 0, sizeof(colourspace_params)); } } void rviewImage::deleteViewCspace(void) { if (cspar != NULL) { delete cspar; cspar = NULL; } } int rviewImage::saveView(FILE *fp) { int status = rviewDisplay::saveView(fp); long spos[2]; spos[0] = (long)scrollx; spos[1] = (long)scrolly; writeViewParam(fp, view_ScrollPos, 2, spos); writeViewParam(fp, view_UseCspace, (long)doValToCspace); writeViewParam(fp, view_CspaceFull, (long)doFullRangeCspace); writeViewParam(fp, view_CspaceProj, (long)doProjRangeCspace); writeViewParam(fp, view_ScaleValue, scaleValue / 100.0); if (csmap != NULL) { colourspace_params par; double cvals[3]; csmap->getParameters(&par); cvals[0] = par.peak_red; cvals[1] = par.peak_green; cvals[2] = par.peak_blue; writeViewParam(fp, view_CspaceMeans, 3, cvals); cvals[0] = par.sigm_red; cvals[1] = par.sigm_green; cvals[2] = par.sigm_blue; writeViewParam(fp, view_CspaceSigmas, 3, cvals); cvals[0] = par.minVal; cvals[1] = par.maxVal; writeViewParam(fp, view_CspaceRange, 2, cvals); writeViewParam(fp, view_CspaceType, (long)par.type); } return status; } int rviewImage::readView(const char *key, const char *value) { int status = rviewDisplay::readView(key, value); if (status == 0) { if (strcmp(key, view_ScrollPos) == 0) { long spos[2]; if (readVector(value, 2, spos) == 0) { scrollx = (int)spos[0]; scrolly = (int)spos[1]; } return 1; } else if (strcmp(key, view_UseCspace) == 0) { doValToCspace = (bool)atoi(value); return 1; } else if (strcmp(key, view_CspaceFull) == 0) { doFullRangeCspace = (bool)atoi(value); return 1; } else if (strcmp(key, view_CspaceProj) == 0) { doProjRangeCspace = (bool)atoi(value); return 1; } else if (strcmp(key, view_CspaceMeans) == 0) { double mean[3]; ensureViewCspace(); if (readVector(value, 3, mean) == 0) { cspar->peak_red = mean[0]; cspar->peak_green = mean[1]; cspar->peak_blue = mean[2]; } return 1; } else if (strcmp(key, view_CspaceSigmas) == 0) { double sigm[3]; ensureViewCspace(); if (readVector(value, 3, sigm) == 0) { cspar->sigm_red = sigm[0]; cspar->sigm_green = sigm[1]; cspar->sigm_blue = sigm[2]; } return 1; } else if (strcmp(key, view_CspaceRange) == 0) { ensureViewCspace(); double crange[2]; if (readVector(value, 2, crange) == 0) { cspar->minVal = crange[0]; cspar->maxVal = crange[1]; } return 1; } else if (strcmp(key, view_CspaceType) == 0) { ensureViewCspace(); cspar->type = (cspaceType)atoi(value); return 1; } else if (strcmp(key, view_ScaleValue) == 0) { scaleValue = 100*atof(value); return 1; } return 0; } return status; } void rviewImage::loadViewFinished(void) { rviewDisplay::loadViewFinished(); pcanv->SetScrollPos(wxHORIZONTAL, scrollx); pcanv->SetScrollPos(wxVERTICAL, scrolly); if (scaleSlider != NULL) scaleSlider->SetValue((int)scaleValue); mBar->Check(MENU_IMAGE_CSPACE_ON, doValToCspace); mBar->Check(MENU_IMAGE_CSPACE_FULL, doFullRangeCspace); mBar->Check(MENU_IMAGE_CSPACE_PROJ, doProjRangeCspace); mBar->Enable(MENU_IMAGE_CSPACE_ON, doValToCspace); mBar->Enable(MENU_IMAGE_CSPACE_FULL, doValToCspace); mBar->Enable(MENU_IMAGE_CSPACE_PROJ, doValToCspace); mBar->Enable(MENU_IMAGE_CSPACE_EDIT, doValToCspace); } /* * Flat image base class members */ rviewFlatBaseImage::rviewFlatBaseImage(mdd_frame *mf, int es, unsigned int flags) : rviewImage(mf, es, flags) { RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "rviewFlatImage()" ); } rviewFlatBaseImage::~rviewFlatBaseImage(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "~rviewFlatBaseImage()" ); } int rviewFlatBaseImage::openViewer(void) { if (dimMDD < 2) { rviewErrorbox::reportError(lman->lookup("errorModeDim"), rviewFlatBaseImage::getFrameName(), "openViewer"); objectInitializedOK = FALSE; return -1; } return rviewImage::openViewer(); } const char *rviewFlatBaseImage::getFrameName(void) const { return "rviewFlatBaseImage"; } rviewFrameType rviewFlatBaseImage::getFrameType(void) const { return rviewFrameTypeFltBsImage; } int rviewFlatBaseImage::newProjection(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "newProjection()" ); char *data, *lastData = imgData; if ((data = projectImage()) == NULL) return -1; updatePixmap(lastData, data); return 0; } char *rviewFlatBaseImage::initMode(void) { int i=0, j=0, w=0, h=0; char *data=0; RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "initMode()" ); // Initialise the projection string. Use a static default for now, later on use the // last value used. data = projString; data += sprintf(data, "*:*, *:*"); for (i=2; iSetValue(projString); // This returns a pointer to the projected MDD data, ready for display by wxPixmap. // It will also set the variables pixWidth, pixHeight. data = projectImage(); // Calculate the size of the whole window to display the entire image by // first examining the difference between the frame's size and the canvas' // client size (i.e. without the scrollbars) GetSize(&i, &j); pcanv->GetClientSize(&w, &h); w = pixWidth + (i-w); h = pixHeight + (j-h); // Limit the size of the window to the values specified in prefs. if (w > prefs->maxDWidth) w = prefs->maxDWidth; if (h > prefs->maxDHeight) h = prefs->maxDHeight; // ... then set the window size. SetSize(-1, -1, w, h); setModeDimension(2); return data; } char *rviewFlatBaseImage::projectImage(void) { int dim1, dim2; RMDBGONCE(3, RMDebug::module_applications, "rviewFlatBaseImage", "projectImage()" ); mapIndex = r_Point(dimMDD); if (freeDimsFromProjection(dim1, dim2, &mapIndex) != 0) return NULL; projectObjectHook(); rviewFlatProjEnv penv; penv.mddPtr = mddObj.ptr(); penv.pt1 = pt1; penv.pt2 = pt2; penv.dim1 = dim1; penv.dim2 = dim2; penv.bt = baseType; penv.doCspace = doValToCspace; penv.scale = scaleValue / 100; if (penv.scale <= 0) penv.scale = 0.01; if (rviewPrepareFlatProjection(penv) != 0) return NULL; if (doValToCspace) { // init if necessary setCspaceProjMode(doProjRangeCspace); // No need for the virtual pitch here, as the image buffer won't be filled with data of the base type penv.cspaceState = rviewCheckInitCspace(baseType, &csmap, mddObj, doFullRangeCspace, csInterv, penv.width, &penv.pitch, &penv.depth, &penv.pad, NULL, cspar); if (csmap != NULL) { mBar->Enable(MENU_IMAGE_CSPACE_EDIT, TRUE); if (doProjRangeCspace) { setCspaceProjMode(doProjRangeCspace); csmap->updateProjection(csInterv); } } deleteViewCspace(); } else penv.cspaceState = 0; penv.csmap = csmap; // Only allocate a new array if it's the first time or the size has changed. if ((penv.width != pixWidth) || (penv.height != pixHeight) || (pixPad != penv.pad) || (pixDepth != penv.depth) || (penv.pitch != virtualPitch)) { pixWidth = penv.width; pixHeight = penv.height; pixPad = penv.pad; pixPitch = penv.pitch; pixDepth = penv.depth; virtualPitch = penv.pitch; if ((imgData = (char*)malloc(penv.pitch * pixHeight)) == NULL) { rviewErrorbox::reportError(lman->lookup("errorMemory"), rviewFlatBaseImage::getFrameName(), "projectImage"); return NULL; } } if (rviewPerformFlatProjection(penv, imgData) != 0) return NULL; resizeImage(); return imgData; } /* * Standard flat images */ rviewFlatImage::rviewFlatImage(mdd_frame *mf, unsigned int flags) : rviewFlatBaseImage(mf, 0, flags) { RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "rviewFlatImage()" ); } rviewFlatImage::~rviewFlatImage(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "~rviewFlatImage()" ); closeViewer(); } void rviewFlatImage::OnSize(int w, int h) { RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "OnSize()"); if (initPhaseFinished) { int x, y, step, posx, posy; GetClientSize(&x, &y); if(x < 6*image_bwidth) { x= 6*image_bwidth; frameWidth=x; frameHeight=y; SetClientSize(x, y); return; } } rviewFlatBaseImage::OnSize(w, h); } int rviewFlatImage::openViewer(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "openViewer()" ); if (rviewFlatBaseImage::openViewer() == 0) { openViewerEpilogue(rviewFlatImage::getFrameType()); return 0; } return -1; } const char *rviewFlatImage::getFrameName(void) const { return "rviewFlatImage"; } rviewFrameType rviewFlatImage::getFrameType(void) const { return rviewFrameTypeFlatImage; } int rviewFlatImage::getViewerType(void) const { return RVIEW_RESDISP_IMGFLAT; } bool rviewFlatImage::moviePossible(void) const { return (dimMDD >= 3); } char *rviewFlatImage::movieNewFrame(void) { return projectImage(); } void rviewFlatImage::label(void) { setDisplayTitle(lman->lookup("titleImageFlat")); rviewFlatBaseImage::label(); } int rviewFlatImage::process(wxObject &obj, wxEvent &evt) { RMDBGONCE(3, RMDebug::module_applications, "rviewFlatImage", "process()" ); int type = evt.GetEventType(); if (type == wxEVENT_TYPE_SLIDER_COMMAND) { scaleValue = (double)(scaleSlider->GetValue()); newProjection(); return 1; } return rviewImage::process(obj, evt); } char *rviewFlatImage::initMode(void) { if (playBack != NULL) playBack->Enable(TRUE); if (playFwd != NULL) playFwd->Enable(TRUE); return rviewFlatBaseImage::initMode(); } /* * Rendered image class members */ const char *rviewRenderImage::view_ZProject = "zProject"; const char *rviewRenderImage::view_ZClip = "zClip"; const char *rviewRenderImage::view_PixThreshLow = "pixThreshLow"; const char *rviewRenderImage::view_PixThreshHigh = "pixThreshHigh"; const char *rviewRenderImage::view_WeightThresh = "weightThresh"; const char *rviewRenderImage::view_WeightQuant = "weightQuant"; const char *rviewRenderImage::view_UseRGBBright = "useRgbBright"; const char *rviewRenderImage::view_UseLighting = "useLighting"; const char *rviewRenderImage::view_LightAmbient = "lightAmbient"; const char *rviewRenderImage::view_LightGain = "lightGain"; const char *rviewRenderImage::view_LightAngle = "lightAngle"; const char *rviewRenderImage::view_LightScint = "lightScintAngle"; const char *rviewRenderImage::view_LightDir = "lightDirection"; const char *rviewRenderImage::view_LightDist = "lightDistance"; const char *rviewRenderImage::view_KernelSize = "kernelSize"; const char *rviewRenderImage::view_KernelType = "kernelType"; const char *rviewRenderImage::view_UseVoxColour = "useVoxColour"; const char *rviewRenderImage::view_VoxColour = "voxColour"; const char *rviewRenderImage::view_GridSize = "gridSize"; const char *rviewRenderImage::view_ScaleHeight = "scaleHeight"; const char *rviewRenderImage::view_Rotation = "rotation"; const char *rviewRenderImage::view_ZOffset = "zOffset"; rviewRenderImage::rviewRenderImage(mdd_frame *mf, int es, unsigned int flags) : rviewImage(mf, es, flags) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "rviewRenderImage()" ); // make destructor-safe first setupWindow = NULL; rcontrol = NULL; rcurview = NULL; geomData = NULL; geomUse = NULL; rot = NULL; graphEnv = NULL; // Default renderer parameters setup.zpro = prefs->imgZpro; setup.clipz = prefs->imgClipz; drx = 0.0; dry = 0.0; drz = 0.0; // Default voxel parameters. Try to use halfway sensible defaults. Values of -1 // saved in the preferences object are substituted by default-values setup.useRgbBrightness = prefs->imgRgbBrightness; setup.weightQuantisation = 4; setup.pixelThresholdLow = prefs->imgPixThreshLow; setup.pixelThresholdHigh = prefs->imgPixThreshHigh; setup.weightThreshold = prefs->imgWgtThresh; // Light defaults setup.useLights = prefs->imgLight; setup.lightsAngle = prefs->imgLightAngle; setup.lightsScintAngle = prefs->imgLightScintAngle; setup.lightsAmbient = prefs->imgLightAmbient; setup.lightsGain = prefs->imgLightGain; setup.lightsDir = rviewImageSetup::parseLightDirection(prefs->imgLightDir); setup.lightsDist = prefs->imgLightDist; setup.kernelSize = prefs->imgKernSize; setup.kernelType = prefs->imgKernType + 1; setup.useVoxCol = prefs->imgUseVCol; setup.voxColour = prefs->imgVoxColour; // Height field defaults setup.gridSize = prefs->imgHeightGrid; setup.scaleHeight = prefs->imgHeightScale; rendererPlayback = 0; geomData = new vertex_fp[4]; geomUse = new vertex_fp[4]; rot = new vertex_fp[3]; graphEnv = new graph_env; } rviewRenderImage::~rviewRenderImage(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "~rviewRenderImage()" ); if (setupWindow != NULL) { setupWindow->unlinkParent(); setupWindow->Close(TRUE); } if (rcontrol != NULL) { rcontrol->unlinkParent(); rcontrol->Close(TRUE); } if (rcurview != NULL) { rcurview->unlinkParent(); rcurview->Close(TRUE); } if(geomData) { delete [] geomData; geomData=0; } if(geomUse) { delete [] geomUse; geomUse=0; } if(rot) { delete [] rot; rot=0; } if(graphEnv) { delete graphEnv; graphEnv=0; } } const char *rviewRenderImage::getFrameName(void) const { return "rviewRenderImage"; } rviewFrameType rviewRenderImage::getFrameType(void) const { return rviewFrameTypeRndImage; } int rviewRenderImage::configMenuInitHook(wxMenu *menu) { menu->Append(MENU_IMAGE_SETUP_RENDER, ""); menu->Append(MENU_IMAGE_SETUP_RCONTROL, ""); menu->AppendSeparator(); return 3; } int rviewRenderImage::viewMenuInitHook(wxMenu *menu) { menu->Append(MENU_DISP_VIEW_SHOW, ""); return 1; } void rviewRenderImage::label(void) { mBar->SetLabel(MENU_IMAGE_SETUP_RENDER, lman->lookup("menImgSetupRender")); mBar->SetLabel(MENU_IMAGE_SETUP_RCONTROL, lman->lookup("menImgSetupRctrl")); mBar->SetLabel(MENU_DISP_VIEW_SHOW, lman->lookup("menDispViewShow")); rviewImage::label(); } int rviewRenderImage::newProjection(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "newProjection()" ); char *data, *lastData = imgData; if ((data = setupGraphEnv()) == NULL) return -1; fillBuffer(); updatePixmap(lastData, data); return 0; } void rviewRenderImage::updateCurrentView(void) { if (rcurview != NULL) { vertex_fp angles; matrixToAngles(angles); rcurview->updateView(angles, zoff, cubeScale); } } int rviewRenderImage::process(wxObject &obj, wxEvent &evt) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "process()" ); int type = evt.GetEventType(); if (type == wxEVENT_TYPE_SLIDER_COMMAND) { scaleValue = (double)(scaleSlider->GetValue()); cubeScale = scaleValue / 100.0; if (cubeScale < 0.01) cubeScale = 0.01; fillBuffer(); pcanv->updateDisplay(TRUE); updateCurrentView(); return 1; } if (type == wxEVENT_TYPE_BUTTON_COMMAND) { if (&obj == (wxObject*)playStop) { rendererPlayback = 0; if (rcontrol != NULL) rcontrol->setActiveMode(0); return 1; } } return rviewImage::process(obj, evt); } bool rviewRenderImage::canRotateObject(void) const { return TRUE; } void rviewRenderImage::rotateObject(wxMouseEvent &mevt) { float pos; // Rotate / translate 3D object if (mevt.leftDown) { pos = mevt.x - mousex; rotateCube(1, pos / 100); pos = mevt.y - mousey; rotateCube(0, pos / 100); fillBuffer(); pcanv->updateDisplay(); updateCurrentView(); } if (mevt.rightDown) { pos = mevt.y - mousey; zoff += (long)pos; fillBuffer(); pcanv->updateDisplay(); updateCurrentView(); } } void rviewRenderImage::OnSize(int w, int h) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "OnSize()" ); int oldwidth = frameWidth; int oldheight = frameHeight; rviewImage::OnSize(w, h); // Fully initialized yet? if ((initPhaseFinished) && ((oldwidth != frameWidth) || (oldheight != frameHeight))) { char *data, *lastData = imgData; if ((data = setupGraphEnv()) != NULL) { fillBuffer(); updatePixmap(lastData, data); } } } void rviewRenderImage::OnMenuCommand(int id) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "OnMenuCommand()" ); switch (id) { case MENU_IMAGE_SETUP_RENDER: if (setupWindow == NULL) { setupWindow = new rviewImageSetup(&setup, this); } break; case MENU_IMAGE_SETUP_RCONTROL: if (rcontrol == NULL) { rcontrol = new rendererControl(drx, dry, drz, rendererPlayback, this); } break; case MENU_DISP_VIEW_SHOW: if (rcurview == NULL) { vertex_fp angles; matrixToAngles(angles); rcurview = new rendererCurrentView(angles, zoff, cubeScale, this); } break; default: rviewImage::OnMenuCommand(id); break; } } void rviewRenderImage::closeEditor(bool newSetup) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "closeEditor()" ); if (newSetup) { updateSettings(FALSE); } setupWindow->Close(TRUE); setupWindow = NULL; } void rviewRenderImage::redrawSettingsChanged(void) { fillBuffer(); pcanv->updateDisplay(); } void rviewRenderImage::updateSettings(int setFlags) { bool doUpt = FALSE; if (setFlags == 0) doUpt = TRUE; else doUpt = doUpdate(setFlags); if (doUpt) { redrawSettingsChanged(); } } bool rviewRenderImage::OnClose(void) { if (rendererPlayback != 0) return FALSE; return rviewImage::OnClose(); } int rviewRenderImage::userEvent(const user_event &ue) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "userEvent()" ); if (ue.type == usr_child_closed) { if (ue.data == (void*)setupWindow) { setupWindow = NULL; return 1; } else if (ue.data == (void*)rcontrol) { rcontrol = NULL; return 1; } else if (ue.data == (void*)rcurview) { rcurview = NULL; return 1; } } return rviewImage::userEvent(ue); } void rviewRenderImage::closeRendererControls(void) { if (rcontrol != NULL) { rcontrol->Close(TRUE); rcontrol = NULL; } } void rviewRenderImage::prepareToDie(void) { rendererPlayback = 0; rviewImage::prepareToDie(); } int rviewRenderImage::requestQuit(int level) { rendererPlayback = 0; return rviewImage::requestQuit(level); } void rviewRenderImage::setAutoRotation(float rx, float ry, float rz) { //cout << "rotate " << rx << ", " << ry << ", " << rz << endl; if (rx >= 100.0) { rendererPlayback = 0; return; } drx = rx; dry = ry; drz = rz; // No re-entrancy if (rendererPlayback != 0) return; rendererPlayback = 1; while (rendererPlayback != 0) { rotateCube(0, M_PI*drx/10); rotateCube(1, M_PI*dry/10); rotateCube(2, M_PI*drz/10); updateCurrentView(); newProjection(); ::wxYield(); } } void rviewRenderImage::setCurrentView(const vertex_fp &angles, long off, double scale) { anglesToMatrix(angles); zoff = off; cubeScale = scale; scaleSlider->SetValue((int)(100*cubeScale)); newProjection(); } char *rviewRenderImage::initMode(void) { int i; char *data; RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "initMode()" ); // Scaling factor for the data cube. cubeScale = scaleValue / 100.0; if (cubeScale < 0.01) cubeScale = 0.01; // Init rotation matrix for (i=0; i<3; i++) { rot[i].x = 0.0; rot[i].y = 0.0; rot[i].z = 0.0; } rot[0].x = 1.0; rot[1].y = 1.0; rot[2].z = 1.0; zoff = 0; data = setupGraphEnv(); if (initPhaseFinished) fillBuffer(); // Do not update the pixmap here! That's done by the calling procedure, if necessary resizeImage(); return data; } char *rviewRenderImage::setupGraphEnv(void) { int w, h; RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "setupGraphEnv()" ); if (rviewParseProjection(getVirtualDomain(), pt1, pt2, projString, &freeDims) != dimMDD) { rviewErrorbox::reportError(lman->lookup("errorProjection"), rviewRenderImage::getFrameName(), "setupGraphEnv"); return NULL; } pcanv->GetClientSize(&w, &h); setupEnvironment(w, h); graphEnv->zpro = setup.zpro; graphEnv->clipz = setup.clipz; graphEnv->clipl = -pixWidth/2; graphEnv->clipr = graphEnv->clipl + pixWidth - 1; graphEnv->clipd = -pixHeight/2; graphEnv->clipu = graphEnv->clipd + pixHeight - 1; graphEnv->midx = -graphEnv->clipl; graphEnv->midy = graphEnv->clipu; /* lineadd set in one of the modules above */ graphEnv->dest = (void*)imgData; return imgData; } void rviewRenderImage::rotateCube(int axis, float angle, vertex_fp *matrix) { real_t c, s; vertex_fp h; int i, j; c = cos(angle); s = sin(angle); switch (axis) { case 0: i = 1; j = 2; break; case 1: i = 2; j = 0; break; case 2: i = 0; j = 1; break; default: cerr << "Bad rotation axis " << axis; return; } h.x = c * matrix[i].x + s * matrix[j].x; h.y = c * matrix[i].y + s * matrix[j].y; h.z = c * matrix[i].z + s * matrix[j].z; matrix[j].x = c * matrix[j].x - s * matrix[i].x; matrix[j].y = c * matrix[j].y - s * matrix[i].y; matrix[j].z = c * matrix[j].z - s * matrix[i].z; matrix[i].x = h.x; matrix[i].y = h.y; matrix[i].z = h.z; /*for (i=0; i<3; i++) { cout << '[' << matrix[i].x << ',' << matrix[i].y << ',' << matrix[i].z << ']'; } cout << endl;*/ } void rviewRenderImage::rotateCube(int axis, float angle) { rotateCube(axis, angle, rot); } void rviewRenderImage::getLightPos(vertex_fp *lpos) { lpos->x = 0; lpos->y = 0; lpos->z = 0; if ((setup.lightsDir & RVIEW_LIGHTDIR_LEFT) != 0) lpos->x = -1.0; else if ((setup.lightsDir & RVIEW_LIGHTDIR_RIGHT) != 0) lpos->x = 1.0; if ((setup.lightsDir & RVIEW_LIGHTDIR_DOWN) != 0) lpos->y = -1.0; else if ((setup.lightsDir & RVIEW_LIGHTDIR_UP) != 0) lpos->y = 1.0; if ((setup.lightsDir & RVIEW_LIGHTDIR_FRONT) != 0) lpos->z = -1.0; else if ((setup.lightsDir & RVIEW_LIGHTDIR_BACK) != 0) lpos->z = 1.0; if (setup.lightsDir != 0) { double h; h = ((double) setup.lightsDist) /sqrt((lpos->x * lpos->x) + (lpos->y * lpos->y) + (lpos->z * lpos->z)); lpos->x *= h; lpos->y *= h; lpos->z *= h; } lpos->z += graphEnv->zpro; } // not correct for x==0, but I don't need that case #define SIGN(x) ((x > 0) ? 1 : -1) #define PRINT_MATRIX(mat) { \ for (unsigned int i=0; i<3; i++) \ cout << i << ": " << (mat)[i].x << ", " << (mat)[i].y << ", " << (mat)[i].z << endl; \ } void rviewRenderImage::matrixToAngles(vertex_fp &angles) const { vertex_fp matrix[3]; // make copy of rotation matrix for working memcpy(&matrix, rot, 3*sizeof(vertex_fp)); // Successively rotate it back to identity. Getting this right is a major headache; // one must bear in mind that rot[] are row-vectors and that atan() only returns // values in -pi/2 to pi/2, so the result may have to be shifted by pi. if (matrix[1].x == 0.0) { angles.z = 0.0; } else { angles.z = -((matrix[0].x == 0.0) ? SIGN(matrix[1].x) * M_PI/2 : atan(matrix[1].x / matrix[0].x)); } if (matrix[0].x < 0) angles.z += M_PI; if (angles.z != 0.0) { rotateCube(2, -angles.z, matrix); //cout << "ROTz" << endl; PRINT_MATRIX(matrix); } if (matrix[2].x == 0.0) { angles.y = 0.0; } else { angles.y = -((matrix[0].x == 0.0) ? -SIGN(matrix[2].x) * M_PI/2 : -atan(matrix[2].x / matrix[0].x)); rotateCube(1, -angles.y, matrix); //cout << "ROTy" << endl; PRINT_MATRIX(matrix); } if (matrix[2].y == 0.0) { angles.x = 0.0; } else { angles.x = -((matrix[1].y == 0.0) ? SIGN(matrix[2].y) * M_PI/2 : atan(matrix[2].y / matrix[1].y)); } if (matrix[1].y < 0) angles.x += M_PI; if (angles.x != 0.0) { rotateCube(0, -angles.x, matrix); //cout << "ROTx" << endl; PRINT_MATRIX(matrix); } #if 0 rotateCube(0, angles.x, matrix); rotateCube(1, angles.y, matrix); rotateCube(2, angles.z, matrix); unsigned int i; double res; for (i=0, res=0.0; i<3; i++) { cout << "REC " << i << ": " << matrix[i].x << ", " << matrix[i].y << ", " << matrix[i].z << " vs. " << rot[i].x << ", " << rot[i].y << ", " << rot[i].z << endl; res += (matrix[i].x - rot[i].x) * (matrix[i].x - rot[i].x) + (matrix[i].y - rot[i].y) * (matrix[i].y - rot[i].y) + (matrix[i].z - rot[i].z) * (matrix[i].z - rot[i].z); } cout << "Residuum " << res << endl; #endif } void rviewRenderImage::anglesToMatrix(const vertex_fp &angles) { unsigned int i; for (i=0; i<3; i++) { rot[i].x = 0.0; rot[i].y = 0.0; rot[i].z = 0.0; } rot[0].x = 1.0; rot[1].y = 1.0; rot[2].z = 1.0; rotateCube(0, angles.x); rotateCube(1, angles.y); rotateCube(2, angles.z); } int rviewRenderImage::saveView(FILE *fp) { int status = rviewImage::saveView(fp); writeViewParam(fp, view_ZProject, (long)setup.zpro); writeViewParam(fp, view_ZClip, (long)setup.clipz); writeViewParam(fp, view_PixThreshLow, setup.pixelThresholdLow); writeViewParam(fp, view_PixThreshHigh, setup.pixelThresholdHigh); writeViewParam(fp, view_WeightThresh, setup.weightThreshold); writeViewParam(fp, view_WeightQuant, (long)setup.weightQuantisation); writeViewParam(fp, view_UseRGBBright, (long)setup.useRgbBrightness); writeViewParam(fp, view_UseLighting, (long)setup.useLights); writeViewParam(fp, view_LightAmbient, setup.lightsAmbient); writeViewParam(fp, view_LightGain, setup.lightsGain); writeViewParam(fp, view_LightAngle, setup.lightsAngle); writeViewParam(fp, view_LightScint, setup.lightsScintAngle); writeViewParam(fp, view_LightDir, (long)setup.lightsDir); writeViewParam(fp, view_LightDist, (long)setup.lightsDist); writeViewParam(fp, view_KernelSize, (long)setup.kernelSize); writeViewParam(fp, view_KernelType, (long)setup.kernelType); writeViewParam(fp, view_UseVoxColour, (long)setup.useVoxCol); writeViewParam(fp, view_VoxColour, setup.voxColour); writeViewParam(fp, view_GridSize, (long)setup.gridSize); writeViewParam(fp, view_ScaleHeight, setup.scaleHeight); vertex_fp angles; double avals[3]; matrixToAngles(angles); avals[0] = angles.x; avals[1] = angles.y; avals[2] = angles.z; writeViewParam(fp, view_Rotation, 3, avals); writeViewParam(fp, view_ZOffset, zoff); return status; } int rviewRenderImage::readView(const char *key, const char *value) { int status = rviewImage::readView(key, value); if (status == 0) { if (strcmp(key, view_ZProject) == 0) { setup.zpro = (unsigned long)atol(value); return 1; } else if (strcmp(key, view_ZClip) == 0) { setup.clipz = (unsigned long)atol(value); return 1; } else if (strcmp(key, view_PixThreshLow) == 0) { setup.pixelThresholdLow = atof(value); return 1; } else if (strcmp(key, view_PixThreshHigh) == 0) { setup.pixelThresholdHigh = atof(value); return 1; } else if (strcmp(key, view_WeightThresh) == 0) { setup.weightThreshold = atof(value); return 1; } else if (strcmp(key, view_WeightQuant) == 0) { setup.weightQuantisation = atoi(value); return 1; } else if (strcmp(key, view_UseRGBBright) == 0) { setup.useRgbBrightness = (bool)atoi(value); return 1; } else if (strcmp(key, view_UseLighting) == 0) { setup.useLights = (bool)atoi(value); return 1; } else if (strcmp(key, view_LightAmbient) == 0) { setup.lightsAmbient = atof(value); return 1; } else if (strcmp(key, view_LightGain) == 0) { setup.lightsGain = atof(value); return 1; } else if (strcmp(key, view_LightAngle) == 0) { setup.lightsAngle = atof(value); return 1; } else if (strcmp(key, view_LightScint) == 0) { setup.lightsScintAngle = atof(value); return 1; } else if (strcmp(key, view_LightDir) == 0) { setup.lightsDir = atoi(value); return 1; } else if (strcmp(key, view_LightDist) == 0) { setup.lightsDist = atoi(value); return 1; } else if (strcmp(key, view_KernelSize) == 0) { setup.kernelSize = atoi(value); return 1; } else if (strcmp(key, view_KernelType) == 0) { setup.kernelType = atoi(value); return 1; } else if (strcmp(key, view_UseVoxColour) == 0) { setup.useVoxCol = (bool)atoi(value); return 1; } else if (strcmp(key, view_VoxColour) == 0) { setup.voxColour = atof(value); return 1; } else if (strcmp(key, view_GridSize) == 0) { setup.gridSize = atoi(value); return 1; } else if (strcmp(key, view_ScaleHeight) == 0) { setup.scaleHeight = atof(value); return 1; } else if (strcmp(key, view_Rotation) == 0) { double avals[3]; if (readVector(value, 3, avals) == 0) { vertex_fp angles; angles.x = avals[0]; angles.y = avals[1]; angles.z = avals[2]; anglesToMatrix(angles); } return 1; } else if (strcmp(key, view_ZOffset) == 0) { zoff = atol(value); return 1; } return 0; } return status; } void rviewRenderImage::loadViewFinished(void) { rviewImage::loadViewFinished(); if (setupWindow != NULL) setupWindow->updateSettings(setup); if (rcurview != NULL) { vertex_fp angles; matrixToAngles(angles); rcurview->updateView(angles, zoff, cubeScale); } cubeScale = scaleValue / 100.0; } /* * Handling the renderer buffer */ #define FILL_BACKGROUND_CORE(type) \ type value, *imgSrcPtr; \ int fbcx, fbcy; \ imgSrcPtr = (type*)(graphEnv->dest); value = (type)minVal; \ for (fbcy=0; fbcy < pixHeight; fbcy++) \ { \ for (fbcx=0; fbcx < pixWidth; fbcx++) \ { \ imgSrcPtr[fbcx] = value; \ } \ imgSrcPtr = (type*)(((char*)imgSrcPtr) + virtualPitch); \ } void rviewRenderImage::fillBackgroundCore(rviewBaseType bt, double minVal) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "fillBackgroundCore()" ); switch (bt) { case rbt_char: { FILL_BACKGROUND_CORE(r_Char); } break; case rbt_uchar: { FILL_BACKGROUND_CORE(r_Octet); } break; case rbt_short: { FILL_BACKGROUND_CORE(r_Short); } break; case rbt_ushort: { FILL_BACKGROUND_CORE(r_UShort); } break; case rbt_long: { FILL_BACKGROUND_CORE(r_Long); } break; case rbt_ulong: { FILL_BACKGROUND_CORE(r_ULong); } break; case rbt_float: { FILL_BACKGROUND_CORE(r_Float); } break; case rbt_double: { FILL_BACKGROUND_CORE(r_Double); } break; default: break; } } void rviewRenderImage::fillBufferBackground(bool doCspace, bool &cspaceOK, r_Ref &obj, colourspaceMapper **csm, r_Minterval *csdom, rviewBaseType bt, bool fullRange, double *useMinVal) { RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "fillBufferBackground()" ); // In case of colourspace mapping and rendering don't fill the background with 0 but // rather with the currently configured minimum value! if (doCspace) { cspaceOK = FALSE; if (rviewCheckInitCspace(bt, csm, obj, fullRange, csdom) != 0) { double minVal; cspaceOK = TRUE; minVal = (useMinVal == NULL) ? (*csm)->getMinVal() : *useMinVal; fillBackgroundCore(bt, minVal); } } else { memset(graphEnv->dest, 0, pixPitch * pixHeight); } } // Macro for colourspace translation from/to various basetypes // Fill in inverse order because source type may be smaller than destination type #define TRANSLATE_TO_COLOURSPACE15(type) \ type *imgSrcPtr; \ long value; \ for (j=0; j maxValL) value = maxValL; \ value -= minValL; if (value < 0) value = 0; \ *imgPtrS = IntToRGBTab15[value]; \ } \ } // Fill in ascending order here because the destination type may be smaller than the source type #define TRANSLATE_TO_COLOURSPACE32(type, minval, maxval, scale) \ type value, *imgSrcPtr; \ char *imgSrcBase = (char*)imgLine; \ if (IntToRGBTab24 == NULL) \ { \ for (j=0; jValToCS24((double)(*imgSrcPtr) - minVal); \ } \ } \ } \ else \ { \ for (j=0; j maxval) value = maxval; \ value -= minval; if (value < 0) value = 0; \ *imgPtrL = IntToRGBTab24[(unsigned long)(value * scale)]; \ } \ } \ } void rviewRenderImage::translateBufferToCspace(rviewBaseType bt, double *useMinVal, double *useMaxVal) { double minVal; unsigned char *imgLine; unsigned short *IntToRGBTab15, *imgPtrS; unsigned long *IntToRGBTab24, *imgPtrL; double maxVal, scalingFactor; long minValL, maxValL; int i, j; RMDBGONCE(3, RMDebug::module_applications, "rviewRenderImage", "translateBufferToCspace()" ); // If bounding boxes are drawn there might be pixels out of range here, so trap those! minVal = (useMinVal == NULL) ? csmap->getMinVal() : *useMinVal; maxVal = (useMaxVal == NULL) ? csmap->getMaxVal() : *useMaxVal; minValL = (long)minVal; maxValL = (long)maxVal; scalingFactor = csmap->getScalingFactor(); imgLine = (unsigned char*)(graphEnv->dest); IntToRGBTab15 = csmap->getCSTab15(); IntToRGBTab24 = csmap->getCSTab24(); switch (bt) { case rbt_char: { TRANSLATE_TO_COLOURSPACE15(r_Char); } break; case rbt_uchar: { TRANSLATE_TO_COLOURSPACE15(r_Octet); } break; case rbt_short: { TRANSLATE_TO_COLOURSPACE15(r_Short); } break; case rbt_ushort: { TRANSLATE_TO_COLOURSPACE15(r_UShort); } break; case rbt_long: { TRANSLATE_TO_COLOURSPACE32(r_Long, minValL, maxValL, 1); } break; case rbt_ulong: { TRANSLATE_TO_COLOURSPACE32(r_ULong, (r_ULong)minValL, (r_ULong)maxValL, 1); } break; case rbt_float: { TRANSLATE_TO_COLOURSPACE32(r_Float, minVal, maxVal, scalingFactor); } break; case rbt_double: { TRANSLATE_TO_COLOURSPACE32(r_Double, minVal, maxVal, scalingFactor); } break; default: { rviewErrorbox::reportError(lman->lookup("errorBaseType"), rviewRenderImage::getFrameName(), "translateBufferToCspace"); return; } } } int rviewRenderImage::setupEnvBase(int w, int h, r_Ref &mdd, colourspaceMapper **csm, r_Minterval *csdom) { int needDepth, newPitch, newPad, newVirtPitch; needDepth = 8*baseSize; if ((rviewImageTypes[baseType] == RVIEW_IMGTYPE_NONE) && (doValToCspace)) needDepth = 32; if (rviewImageTypes[baseType] == RVIEW_IMGTYPE_HIGH) needDepth = 15; if (rviewImageTypes[baseType] == RVIEW_IMGTYPE_GREY12) needDepth = 12; newPad = 64; newPitch = (w * baseSize + 7) & ~7; newVirtPitch = newPitch; if (doValToCspace) { // Init if necessary setCspaceProjMode(doProjRangeCspace); rviewCheckInitCspace(baseType, csm, mdd, doFullRangeCspace, csdom, w, &newPitch, &needDepth, &newPad, &newVirtPitch, cspar); if (*csm != NULL) { mBar->Enable(MENU_IMAGE_CSPACE_EDIT, TRUE); if (doProjRangeCspace) { setCspaceProjMode(doProjRangeCspace); (*csm)->updateProjection(csdom); } } deleteViewCspace(); } if ((w != pixWidth) || (h != pixHeight) || (pixPad != newPad) || (pixDepth != needDepth) || (newPitch != pixPitch) || (newVirtPitch != virtualPitch)) { pixWidth = w; pixHeight = h; pixDepth = needDepth; pixPitch = newPitch; pixPad = newPad; virtualPitch = newVirtPitch; if ((imgData = (char*)malloc(virtualPitch * pixHeight)) == NULL) { rviewErrorbox::reportError(lman->lookup("errorMemory"), getFrameName(), "setupEnvironment"); return -1; } } graphEnv->lineadd = virtualPitch; return 0; } /* * Volume image renderer members */ const char *rviewVolumeImage::view_VolumeMode = "volumeMode"; const char *rviewVolumeImage::view_UseBBox = "useBBox"; rviewVolumeImage::rviewVolumeImage(mdd_frame *mf, unsigned int flags) : rviewRenderImage(mf, 0, flags) { RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "rviewVolumeImage()" ); // make destructor safe texDesc = NULL; voxDesc = NULL; initVoxParams = FALSE; // Mode defaults imode = prefs->imgMode; if ((imode != rim_surf) && (imode != rim_voxel)) imode = rim_surf; if (prefs->imgVoxForType != 0) { initVoxParams = TRUE; switch (baseSize) { case 1: setup.pixelThresholdLow = 4.0; setup.pixelThresholdHigh = 1e6; setup.weightThreshold = 64.0; setup.voxColour = 0xff; break; case 2: setup.pixelThresholdLow = 256.0; setup.pixelThresholdHigh = 65535.0; setup.weightThreshold = 64.0; setup.voxColour = 0xffff; break; case 3: setup.pixelThresholdLow = 4.0; setup.pixelThresholdHigh = 1e6; setup.weightThreshold = 64.0; setup.voxColour = 0xffffff; break; case 4: setup.pixelThresholdLow = 16384.0; setup.pixelThresholdHigh = 1e6; setup.weightThreshold = 64.0; setup.voxColour = 0xffffffff; break; case 8: setup.pixelThresholdLow = 0.0; setup.pixelThresholdHigh = 1e12; setup.weightThreshold = 64.0; setup.voxColour = 1e12; default: break; } } // Align bbox with projection's OK-button boundingBox = new rviewCheckBox(ctrlPanel); // Preferences doBoundingBox = prefs->imgBBox; boundingBox->SetValue(doBoundingBox); texDesc = new tex_desc; voxDesc = new voxel_desc; texDesc->floatType = ((baseType == rbt_float) || (baseType == rbt_double)) ? 1 : 0; } int rviewVolumeImage::openViewer(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "openViewer()" ); if (dimMDD != 3) { rviewErrorbox::reportError(lman->lookup("errorModeDim"), rviewVolumeImage::getFrameName(), "openViewer"); objectInitializedOK = FALSE; return -1; } if (rviewRenderImage::openViewer() == 0) { // first add the menus of the parent class int madd = rviewRenderImage::menuBarInitHook(); // then add my own wxMenu *modes; char buffer[STRINGSIZE]; modes = new wxMenu; modes->Append(MENU_IMAGE_MODE_SURF, "", NULL, TRUE); modes->Append(MENU_IMAGE_MODE_VOXEL, "", NULL, TRUE); sprintf(buffer, "&%s", lman->lookup("menImgMode")); mBar->Append(modes, buffer); switch (imode) { case rim_surf: lastMode = MENU_IMAGE_MODE_SURF; break; case rim_voxel: lastMode = MENU_IMAGE_MODE_VOXEL; break; default: break; } modes->Check(lastMode, TRUE); openViewerEpilogue(rviewVolumeImage::getFrameType()); return 0; } return -1; } rviewVolumeImage::~rviewVolumeImage(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage" ,"~rviewVolumeImage()" ); closeViewer(); delete texDesc; delete voxDesc; } const char *rviewVolumeImage::getFrameName(void) const { return "rviewVolumeImage"; } rviewFrameType rviewVolumeImage::getFrameType(void) const { return rviewFrameTypeVolImage; } int rviewVolumeImage::getViewerType(void) const { return RVIEW_RESDISP_IMGVOLM; } void rviewVolumeImage::label(void) { setDisplayTitle(lman->lookup("titleImageVolume")); boundingBox->SetLabel(lman->lookup("textBBox")); mBar->SetLabel(MENU_IMAGE_MODE_SURF, lman->lookup("menImgModeSurf")); mBar->SetLabel(MENU_IMAGE_MODE_VOXEL, lman->lookup("menImgModeVoxel")); mBar->SetLabelTop(fixedNumberOfMenus + 1, lman->lookup("menImgMode")); rviewRenderImage::label(); } int rviewVolumeImage::process(wxObject &obj, wxEvent &evt) { RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "process()" ); int type = evt.GetEventType(); if (type == wxEVENT_TYPE_CHECKBOX_COMMAND) { if (&obj == (wxObject*)boundingBox) { doBoundingBox = boundingBox->GetValue(); fillBuffer(); pcanv->updateDisplay(); return 1; } } return rviewRenderImage::process(obj, evt); } void rviewVolumeImage::OnMenuCommand(int id) { RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "OnMenuCommand()" ); rviewImageMode newMode = rim_none; switch (id) { case MENU_IMAGE_MODE_SURF: newMode = rim_surf; break; case MENU_IMAGE_MODE_VOXEL: newMode = rim_voxel; break; default: rviewRenderImage::OnMenuCommand(id); break; } if (newMode != rim_none) { configureMode(); // We have to do this in any case or the menus get screwed mBar->Check(lastMode, FALSE); mBar->Check(id, TRUE); lastMode = id; if (newMode != imode) { imode = newMode; fillBuffer(); updatePixmap(imgData, imgData); } } } void rviewVolumeImage::OnSize(int w, int h) { RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "OnSize()" ); rviewRenderImage::OnSize(w, h); if (boundingBox != NULL) boundingBox->SetSize(w + 2*display_cnvborder - 3*display_border - 4*display_pbwidth, display_border, image_bbwidth, image_bbheight); } bool rviewVolumeImage::doUpdate(int flags) { if (((flags & RVIEW_IFLAG_VOXEL) != 0) && (imode == rim_voxel)) return TRUE; if (((flags & RVIEW_IFLAG_LIGHT) != 0) && setup.useLights) return TRUE; return FALSE; } char *rviewVolumeImage::initMode(void) { RMDBGENTER(3, RMDebug::module_applications, "rviewVolumeImage", "initMode()" ); // Initialise the projection string. Use a static default for now, later on use the // last value used. sprintf(projString, "*:*, *:*, *:*"); project->SetValue(projString); setModeDimension(3); if (boundingBox != NULL) boundingBox->Enable(TRUE); texDesc->dimx = interv[0].high() - interv[0].low() + 1; texDesc->dimy = interv[1].high() - interv[1].low() + 1; texDesc->dimz = interv[2].high() - interv[2].low() + 1; texDesc->baseSize = baseSize; RMDBGEXIT(3, RMDebug::module_applications, "rviewVolumeImage", "initMode() tx=" << texDesc->dimx << ", ty=" << texDesc->dimy << ", tz=" << texDesc->dimz << ", tbase=" << texDesc->baseSize ); return rviewRenderImage::initMode(); } char *rviewVolumeImage::setupEnvironment(int w, int h) { RMDBGENTER(3, RMDebug::module_applications, "rviewVolumeImage", "setupEnvironment()" ); int i, offset; if (setupEnvBase(w, h, mddObj, &csmap, csInterv) != 0) return NULL; // These values change for each projection texDesc->widthx = pt2[0] - pt1[0] + 1; texDesc->widthy = pt2[1] - pt1[1] + 1; texDesc->widthz = pt2[2] - pt1[2] + 1; r_Ref > tempMdd = (r_Ref >) mddObj; // Do it like this to avoid having to check all base types r_Point paux = r_Point(dimMDD); for (i=0; idata = (void*)((char*)(tempMdd->get_array()) + offset); for (i=0; i<4; i++) { geomData[i].x = 0; geomData[i].y = 0; geomData[i].z = 0; } geomData[1].x = (real_t)(pt2[0] - pt1[0] + 1); geomData[2].y = (real_t)(pt2[1] - pt1[1] + 1); geomData[3].z = (real_t)(pt2[2] - pt1[2] + 1); RMDBGMIDDLE(3, RMDebug::module_applications, "rviewVolumeImage", "w=" << pixWidth << ", h=" << pixHeight << ", p=" << pixPitch << ", cl=" << graphEnv->clipl << ", cr=" << graphEnv->clipr << ", cd=" << graphEnv->clipd << ", cu=" << graphEnv->clipu << ", mx=" << graphEnv->midx << ", my=" << graphEnv->midy << ", img=" << graphEnv->dest ); RMDBGMIDDLE(3, RMDebug::module_applications, "rviewVolumeImage", "twx=" << texDesc->widthx << ", twy=" << texDesc->widthy << ", twz=" << texDesc->widthz << ", offset=" << (int)((char*)(texDesc->data) - mddObj->get_array()) << ", base size " << texDesc->baseSize << ", dest=" << (void*)imgData ); RMDBGEXIT(3, RMDebug::module_applications, "rviewVolumeImage", "setupEnvironment()"); return imgData; } void rviewVolumeImage::fillBuffer(void) { int i; vertex_fp v; bool cspaceOK; RMDBGONCE(3, RMDebug::module_applications, "rviewVolumeImage", "fillBuffer()" ); // Plot bounding box or not? graphEnv->bbox_colour = (doBoundingBox) ? 0xffffff : 0xffffffff; // Update z-rendering parameters graphEnv->zpro = setup.zpro; graphEnv->clipz = setup.clipz; for (i=1; i<4; i++) { // Make sure we don't get zero length vectors // (only a problem with strongly deformed ``cubes'', like planes) v.x = cubeScale * (geomData[i].x * rot[0].x + geomData[i].y * rot[0].y + geomData[i].z * rot[0].z); v.y = cubeScale * (geomData[i].x * rot[1].x + geomData[i].y * rot[1].y + geomData[i].z * rot[1].z); v.z = cubeScale * (geomData[i].x * rot[2].x + geomData[i].y * rot[2].y + geomData[i].z * rot[2].z); geomUse[i].x = v.x; geomUse[i].y = v.y; geomUse[i].z = v.z; } // Rotate around middle of cube geomUse[0].x = -(geomUse[1].x + geomUse[2].x + geomUse[3].x) / 2; geomUse[0].y = -(geomUse[1].y + geomUse[2].y + geomUse[3].y) / 2; geomUse[0].z = -(geomUse[1].z + geomUse[2].z + geomUse[3].z) / 2 + geomData[3].z / 2 + graphEnv->zpro + zoff; /*for (i=0; i<4; i++) { cout << i << ": " << geomUse[i].x << ", " << geomUse[i].y << ", " << geomUse[i].z << endl; }*/ fillBufferBackground(doValToCspace, cspaceOK, mddObj, &csmap, csInterv, baseType, doFullRangeCspace); if ((texDesc->floatType != 0) && (csmap != NULL)) { texDesc->minVal = csmap->getMinVal(); texDesc->maxVal = csmap->getMaxVal(); } if (imode == rim_surf) { RenderCubeSurf(geomUse, graphEnv, texDesc); } else { if (initVoxParams) { if (csmap != NULL) { setup.pixelThresholdLow = csmap->getMinVal(); setup.pixelThresholdHigh = csmap->getMaxVal(); setup.weightThreshold = (setup.pixelThresholdHigh - setup.pixelThresholdLow) / 4; setup.voxColour = csmap->getMaxVal(); if (setupWindow != NULL) setupWindow->updateSettings(setup); } initVoxParams = FALSE; } voxDesc->pixelThresholdLow = setup.pixelThresholdLow; voxDesc->pixelThresholdHigh = setup.pixelThresholdHigh; voxDesc->weightThreshold = setup.weightThreshold; voxDesc->weightQuantisation = setup.weightQuantisation; voxDesc->useRgbBrightness = setup.useRgbBrightness; voxDesc->light.ambient = (setup.useLights) ? setup.lightsAmbient : -1.0; voxDesc->light.gain = setup.lightsGain; voxDesc->light.cosine = cos((M_PI * setup.lightsAngle) / 180); voxDesc->light.scintCos = cos((M_PI * setup.lightsScintAngle) / 180); getLightPos(&(voxDesc->light.lights)); voxDesc->kernSize = setup.kernelSize; voxDesc->kernType = setup.kernelType; if (setup.useVoxCol) { switch (baseType) { case rbt_float: voxColour.f = (float)setup.voxColour; break; case rbt_double: voxColour.d = (double)setup.voxColour; break; default: voxColour.l = (unsigned long)setup.voxColour; break; } voxDesc->voxColour = (void*)&voxColour; } else { voxDesc->voxColour = NULL; } ::wxBeginBusyCursor(wxHOURGLASS_CURSOR); RenderCubeVoxel(geomUse, graphEnv, texDesc, voxDesc); ::wxEndBusyCursor(); } if (doValToCspace && cspaceOK) { translateBufferToCspace(baseType); } } int rviewVolumeImage::saveView(FILE *fp) { int status = rviewRenderImage::saveView(fp); writeViewParam(fp, view_VolumeMode, (long)imode); writeViewParam(fp, view_UseBBox, (long)doBoundingBox); return status; } int rviewVolumeImage::readView(const char *key, const char *value) { int status = rviewRenderImage::readView(key, value); if (status == 0) { if (strcmp(key, view_VolumeMode) == 0) { imode = (rviewImageMode)atoi(value); return 1; } else if (strcmp(key, view_UseBBox) == 0) { doBoundingBox = (bool)atoi(value); return 1; } return 0; } return status; } void rviewVolumeImage::loadViewFinished(void) { rviewRenderImage::loadViewFinished(); mBar->Check(MENU_IMAGE_MODE_SURF, (imode == rim_surf)); mBar->Check(MENU_IMAGE_MODE_VOXEL, (imode == rim_voxel)); lastMode = imode; boundingBox->SetValue(doBoundingBox); // if we're in voxel mode, the parameters loaded are OK, don't overwrite them in fillBuffer()! if (imode == rim_voxel) initVoxParams = FALSE; } /* * Height field rendered images members */ rviewHeightImage::rviewHeightImage(mdd_frame *mf, unsigned int flags) : rviewRenderImage(mf, 0, flags) { RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "rviewHeightImage()" ); // make destructor safe mddDesc = NULL; meshDesc = NULL; mddDesc = NULL; // create dummy MDD object r_Minterval dummyInterv(2); dummyInterv << r_Sinterval((r_Range)0, (r_Range)1) << r_Sinterval((r_Range)0, (r_Range)1); dummyMDD = (r_Ref)(new r_Marray(dummyInterv)); meshDesc = new mesh_desc; memset(meshDesc, 0, sizeof(mesh_desc)); mddDesc = new mdd_desc; mddDesc->numDims = dimMDD; mddDesc->dims = new int[dimMDD]; mddDesc->widths = new int[dimMDD]; mddDesc->floatType = ((baseType == rbt_float) || (baseType == rbt_double)) ? 1 : 0; } rviewHeightImage::~rviewHeightImage(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "~rviewHeightImage()" ); closeViewer(); dummyMDD.destroy(); if (meshDesc != NULL) { RenderHeightFreeMesh(meshDesc); delete meshDesc; } if (mddDesc != NULL) { delete [] mddDesc->dims; delete [] mddDesc->widths; delete mddDesc; } } int rviewHeightImage::openViewer(void) { if (dimMDD < 2) { rviewErrorbox::reportError(lman->lookup("errorModeDim"), rviewHeightImage::getFrameName(), "openViewer"); objectInitializedOK = FALSE; return -1; } if (baseType == rbt_rgb) { rviewErrorbox::reportError(lman->lookup("errorModeBase"), rviewHeightImage::getFrameName(), "openViewer"); objectInitializedOK = FALSE; return -1; } if (rviewRenderImage::openViewer() == 0) { openViewerEpilogue(rviewHeightImage::getFrameType()); return 0; } return -1; } const char *rviewHeightImage::getFrameName(void) const { return "rviewHeightImage"; } rviewFrameType rviewHeightImage::getFrameType(void) const { return rviewFrameTypeHghtImage; } int rviewHeightImage::getViewerType(void) const { return RVIEW_RESDISP_IMGHGHT; } bool rviewHeightImage::cspaceRangeHook(bool suggest) { return FALSE; } bool rviewHeightImage::modeNeedsCspace(rviewBaseType bt) const { return FALSE; } int rviewHeightImage::newProjection(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "newProjection()" ); char *data, *lastData = imgData; meshDesc->srcData = NULL; if ((data = setupGraphEnv()) == NULL) return -1; fillBuffer(); updatePixmap(lastData, data); return 0; } bool rviewHeightImage::moviePossible(void) const { return (dimMDD >= 3); } char *rviewHeightImage::movieNewFrame(void) { char *data; if ((data = setupGraphEnv()) != NULL) fillBuffer(); return data; } bool rviewHeightImage::doUpdate(int flags) { if ((flags & RVIEW_IFLAG_LIGHT) != 0) return TRUE; if ((flags & RVIEW_IFLAG_HEIGHT) != 0) return TRUE; return FALSE; } void rviewHeightImage::redrawSettingsChanged(void) { if (depthForHeightfield() != pixDepth) { char *data = NULL, *lastData = imgData; data = setupGraphEnv(); fillBuffer(); updatePixmap(lastData, data); } else rviewRenderImage::redrawSettingsChanged(); } void rviewHeightImage::label(void) { setDisplayTitle(lman->lookup("titleImageHeight")); rviewRenderImage::label(); } int rviewHeightImage::process(wxObject &obj, wxEvent &evt) { RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "process()" ); int type = evt.GetEventType(); if (type == wxEVENT_TYPE_BUTTON_COMMAND) { if (&obj == (wxObject*)playStop) playDirection = 0; // do not intercept the call (return 1), however, because the renderer // might also rotate the object, which'll be handled on rviewRenderImage // level. } return rviewRenderImage::process(obj, evt); } void rviewHeightImage::prepareToDie(void) { playDirection = 0; rviewRenderImage::prepareToDie(); } int rviewHeightImage::requestQuit(int level) { playDirection = 0; return rviewRenderImage::requestQuit(level); } char *rviewHeightImage::initMode(void) { int i; char *b; RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "initMode()" ); b = projString; b += sprintf(b, "*:*, *:*"); for (i=2; iSetValue(projString); setModeDimension(2); for (i=0; idims[i] = interv[i].high() - interv[i].low() + 1; mddDesc->widths[i] = mddDesc->dims[i]; } mddDesc->baseSize = baseSize; return rviewRenderImage::initMode(); } int rviewHeightImage::depthForHeightfield(void) const { return (setup.voxColour >= 256) ? 24 : 8; } char *rviewHeightImage::setupEnvironment(int w, int h) { int i, needDepth, newPitch, newPad, offset, newVirtPitch; RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "setupEnvironment()" ); needDepth = depthForHeightfield(); newPad = 32; newPitch = (w * (needDepth >> 3) + 3) & ~3; newVirtPitch = newPitch; if ((doValToCspace) && (needDepth == 8)) { setCspaceProjMode(FALSE); rviewCheckInitCspace(rbt_char, &csmap, dummyMDD, TRUE, csInterv, w, &newPitch, &needDepth, &newPad, &newVirtPitch, cspar); if (csmap != NULL) { mBar->Enable(MENU_IMAGE_CSPACE_EDIT, TRUE); } deleteViewCspace(); } if ((w != pixWidth) || (h != pixHeight) || (pixPad != newPad) || (pixDepth != needDepth) || (newPitch != pixPitch) || (newVirtPitch != virtualPitch)) { pixWidth = w; pixHeight = h; pixDepth = needDepth; pixPitch = newPitch; pixPad = newPad; virtualPitch = newVirtPitch; if ((imgData = (char*)malloc(virtualPitch * pixHeight)) == NULL) { rviewErrorbox::reportError(lman->lookup("errorMemory"), rviewHeightImage::getFrameName(), "setupEnvironment"); return NULL; } } graphEnv->lineadd = virtualPitch; for (i=0; iwidths[i] = pt2[i] - pt1[i] + 1; } r_Ref > tempMdd = (r_Ref >) mddObj; r_Point paux(dimMDD); for (i=0; idata = (void*)((char*)(tempMdd->get_array()) + offset); return imgData; } void rviewHeightImage::fillBackgroundCore(rviewBaseType bt, double minVal) { RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "fillBackgroundCore()" ); memset(graphEnv->dest, 0, pixPitch * pixHeight); } void rviewHeightImage::fillBuffer(void) { real_t gridScale, scaleHeight; light_desc light; bool useCspace, cspaceOK; RMDBGONCE(3, RMDebug::module_applications, "rviewHeightImage", "fillBuffer()" ); gridScale = cubeScale * setup.gridSize; scaleHeight = cubeScale * setup.scaleHeight; graphEnv->zpro = setup.zpro; graphEnv->clipz = setup.clipz; memcpy(geomUse+1, rot, 3*sizeof(vertex_fp)); // Calculate the coordinates of the center point of the base diagonal for // centering the rotation int dimx, dimz; if (RenderHeightGetDomain(mddDesc, &dimx, &dimz, NULL, NULL) != 0) return; geomUse[0].x = -0.5 * gridScale * (dimx * rot[0].x + dimz * rot[0].z); geomUse[0].y = 0.0; geomUse[0].z = -0.5 * gridScale * (dimx * rot[2].x + dimz * rot[2].z) + graphEnv->zpro + zoff; useCspace = doValToCspace; light.ambient = (setup.useLights) ? setup.lightsAmbient : -1.0; light.gain = setup.lightsGain; light.cosine = cos((M_PI * setup.lightsAngle) / 180); light.scintCos = cos((M_PI * setup.lightsScintAngle) / 180); getLightPos(&(light.lights)); meshDesc->scaleGrid = gridScale; meshDesc->scaleHeight = scaleHeight; meshDesc->colour = (unsigned int)(setup.voxColour); if (meshDesc->colour >= 256) { meshDesc->colour |= 0xff000000; // mark as RGB useCspace = FALSE; } // Colourspace mapping in the height renderer always means a source type of // 8bpp. Besides there's no correlation between the rendered colours and the // MDD values, therefore the colourspace is always set to [0,255] here. double useMinVal = 0; fillBufferBackground(useCspace, cspaceOK, dummyMDD, &csmap, csInterv, rbt_char, true, &useMinVal); ::wxBeginBusyCursor(wxHOURGLASS_CURSOR); RenderHeightField(meshDesc, geomUse, graphEnv, mddDesc, &light); if (useCspace && cspaceOK) { double useMaxVal=255; translateBufferToCspace(rbt_char, &useMinVal, &useMaxVal); } ::wxEndBusyCursor(); } /* * Prescaled image class */ const double rviewScaledImage::scaleStep = 2.0; const char *rviewScaledImage::view_CurrentBox = "currentBox"; const char *rviewScaledImage::view_BoxScale = "boxScale"; rviewScaledImage::rviewScaledImage(collection_desc *cd, r_Fast_Base_Scale *scaler, unsigned int flags) : rviewFlatBaseImage(cd->mddObjs, 0, flags) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "rviewScaledImage()" ); int i; scaleObject = scaler; fullDomain = scaleObject->get_full_domain(); initialScale = scaler->get_last_scale(); thisView.scale = initialScale; thisView.dim1 = 0; thisView.dim2 = 1; thisView.low = r_Point(dimMDD); thisView.high = r_Point(dimMDD); for (i=0; iEnable((viewHistory.getNumber() != 0)); boxState = pcanv->HasDragBox(); zoomBoxBut->Enable(boxState); mBar->Enable(MENU_DISP_DATA_INSERT, FALSE); mBar->Enable(MENU_DISP_DATA_INSERTPRO, FALSE); openViewerEpilogue(rviewScaledImage::getFrameType()); dontLoad = FALSE; return 0; } return -1; } void rviewScaledImage::label(void) { if (initPhaseFinished) { setDisplayTitle(lman->lookup("titleImageScaled")); scaleString->SetLabel(lman->lookup("textScaleFactor")); zoomBoxBut->SetLabel(lman->lookup("textZoomBox")); lastZoomBut->SetLabel(lman->lookup("textLastZoom")); zoomInBut->SetLabel(lman->lookup("textZoomIn")); zoomOutBut->SetLabel(lman->lookup("textZoomOut")); } rviewFlatBaseImage::label(); } void rviewScaledImage::OnSize(int w, int h) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "OnSize()"); if (initPhaseFinished) { int x, y, step, posx, posy; GetClientSize(&x, &y); if(x < 6*image_bwidth) { x= 6*image_bwidth; frameWidth=x; frameHeight=y; SetClientSize(x, y); return; } x -= 2*display_border; scaleString->SetSize(display_border, image_totaly - image_theight, image_twidth, image_theight); step = (x - image_twidth - 4*image_bwidth) / 4; posx = image_twidth + display_border + step/2; posy = image_totaly - image_bheight; zoomBoxBut->SetSize(posx, posy, image_bwidth, image_bheight); posx += step + image_bwidth; lastZoomBut->SetSize(posx, posy, image_bwidth, image_bheight); posx += step + image_bwidth; zoomInBut->SetSize(posx, posy, image_bwidth, image_bheight); posx += step + image_bwidth; zoomOutBut->SetSize(posx, posy, image_bwidth, image_bheight); } rviewFlatBaseImage::OnSize(w, h); if (initPhaseFinished) { int w, h, vw, vh; pcanv->GetClientSize(&w, &h); pcanv->SetAspectRatio(((double)h) / w); w = (int)(w / thisView.scale); h = (int)(h / thisView.scale); vw = (int)(thisView.high[thisView.dim1] - thisView.low[thisView.dim1]); vh = (int)(thisView.high[thisView.dim2] - thisView.low[thisView.dim2]); if ((vw < w) || (vh < h)) { if (vw < w) thisView.high[thisView.dim1] = (r_Range)(thisView.low[thisView.dim1] + w); if (vh < h) thisView.high[thisView.dim2] = (r_Range)(thisView.low[thisView.dim2] + h); newView(); } } } double rviewScaledImage::getLastScale(void) const { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "getLastScale()"); view_desc_t lastView; if (viewHistory.peek(lastView) == 0) return lastView.scale; else return initialScale; } void rviewScaledImage::scaleViewBy(double scale) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "scaleViewBy()"); thisView.high[thisView.dim1] = thisView.low[thisView.dim1] + (r_Range)((thisView.high[thisView.dim1] - thisView.low[thisView.dim1]) / scale); thisView.high[thisView.dim2] = thisView.low[thisView.dim2] + (r_Range)((thisView.high[thisView.dim2] - thisView.low[thisView.dim2]) / scale); thisView.scale *= scale; // If we magnify, check whether we can increase the view box if (scale > 1.0) { int w, h; pcanv->GetClientSize(&w, &h); w = (int)(w / thisView.scale); h = (int)(h / thisView.scale); // extend the viewbox to the maximum size of the canvas if (thisView.high[thisView.dim1] - thisView.low[thisView.dim1] < w) thisView.high[thisView.dim1] = (r_Range)(thisView.low[thisView.dim1] + w); if (thisView.high[thisView.dim2] - thisView.low[thisView.dim2] < h) thisView.high[thisView.dim2] = (r_Range)(thisView.low[thisView.dim2] + h); // no clipping necessary here, will be done in newView() } } int rviewScaledImage::process(wxObject &obj, wxEvent &evt) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "process()"); int type = evt.GetEventType(); if (type == wxEVENT_TYPE_BUTTON_COMMAND) { if (&obj == (wxObject*)lastZoomBut) { if (viewHistory.pop(thisView) == 0) { newView(); } if (viewHistory.getNumber() == 0) lastZoomBut->Enable(FALSE); return 1; } else if (&obj == (wxObject*)zoomInBut) { viewHistory.push(thisView); lastZoomBut->Enable(TRUE); scaleViewBy(scaleStep); newView(); return 1; } else if (&obj == (wxObject*)zoomOutBut) { viewHistory.push(thisView); lastZoomBut->Enable(TRUE); scaleViewBy(1/scaleStep); newView(); return 1; } else if (&obj == (wxObject*)zoomBoxBut) { if (pcanv->HasDragBox()) { int x0, y0, x1, y1; double relScale; viewHistory.push(thisView); lastZoomBut->Enable(TRUE); pcanv->GetDragBox(x0, y0, x1, y1); relScale = (thisView.high[thisView.dim1] - thisView.low[thisView.dim1]) / ((double)(pixmap->getWidth())); thisView.high[thisView.dim1] = thisView.low[thisView.dim1] + (r_Range)(x1*relScale); thisView.low[thisView.dim1] += (r_Range)(x0 * relScale); thisView.high[thisView.dim2] = thisView.low[thisView.dim2] + (r_Range)(y1*relScale); thisView.low[thisView.dim2] += (r_Range)(y0 * relScale); thisView.scale *= ((double)(pixmap->getWidth())) / (x1 - x0); newView(); } return 1; } } else if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND) { if (&obj == (wxObject*)scaleString) { double newScale = atof(scaleString->GetValue()); if (newScale != thisView.scale) { viewHistory.push(thisView); lastZoomBut->Enable(TRUE); scaleViewBy(newScale / thisView.scale); newView(); } return 1; } } return rviewFlatBaseImage::process(obj, evt); } // Intercept the mouse event. void rviewScaledImage::processMouseEvent(wxMouseEvent &mevt) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "processMouseEvent()"); int newbut = 0; bool newBoxState; if (mevt.leftDown) newbut |= MOUSE_LEFT; if (mevt.middleDown) newbut |= MOUSE_MIDDLE; if (mevt.rightDown) newbut |= MOUSE_RIGHT; // Drag a box if ((newbut & MOUSE_LEFT) != 0) { if ((mousebut & MOUSE_LEFT) == 0) { pcanv->SetDragBox(mevt.x, mevt.y, mevt.x, mevt.y); } else { pcanv->UpdateDragBox(mevt.x, mevt.y); } } else if ((newbut & MOUSE_RIGHT) != 0) { if ((mousebut & MOUSE_RIGHT) == 0) { pcanv->AdjustDragBox(mevt.x, mevt.y); } else { pcanv->UpdateDragBox(mevt.x, mevt.y); } } mousebut = newbut; mousex = mevt.x; mousey = mevt.y; newBoxState = pcanv->HasDragBox(); if (newBoxState != boxState) { zoomBoxBut->Enable(newBoxState); boxState = newBoxState; } } const char *rviewScaledImage::getFrameName(void) const { return "rviewPrescaledFrame"; } rviewFrameType rviewScaledImage::getFrameType(void) const { return rviewFrameTypeScaledImage; } int rviewScaledImage::getViewerType(void) const { return RVIEW_RESDISP_IMGSCLD; } bool rviewScaledImage::showScaleSlider(void) const { return FALSE; } void rviewScaledImage::projectionStringForView(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "projectionStringView()"); int i; char *b = projString; for (i=0; iget_scaled_domain(projFull, projScaled, thisView.scale) != 0) { //cout << projFull << ", " << projScaled << ", " << interv << endl; // for now just make sure we're not outside the range... for (i=0; i interv[i].high()) pt1[i] = interv[i].high(); pt2[i] = projScaled[i].high() + offset; if (pt2[i] < interv[i].low()) pt2[i] = interv[i].low(); if (pt2[i] > interv[i].high()) pt2[i] = interv[i].high(); } //cout << "Translated " << pt1 << ", " << pt2 << endl; } else { rviewErrorbox::reportError(lman->lookup("errorScaledObjSize")); } } char *rviewScaledImage::projectImage(void) { return rviewFlatBaseImage::projectImage(); } bool rviewScaledImage::compareViews(const view_desc_t &v1, const view_desc_t &v2) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "compareViews()"); if ((v1.scale == v2.scale) && (v1.dim1 == v2.dim1) && (v1.dim2 == v2.dim2) && (v1.low == v2.low) && (v1.high == v2.high)) return TRUE; return FALSE; } int rviewScaledImage::newProjection(void) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "newProjection()"); int status; view_desc_t lastView = thisView; if ((status = rviewFlatBaseImage::newProjection()) == 0) { if (!compareViews(thisView, lastView)) { viewHistory.push(lastView); lastZoomBut->Enable(TRUE); } } return status; } void rviewScaledImage::newView(bool loadImage) { RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "newView()"); int i; // Remove drag boxes pcanv->SetDragBox(-1, -1, -1, -1); boxState = FALSE; zoomBoxBut->Enable(boxState); // Clip rectangle to actual domain. Ratio already ensured by canvas for (i=0; i<(int)dimMDD; i++) { if (thisView.low[i] < fullDomain[i].low()) thisView.low[i] = fullDomain[i].low(); if (thisView.high[i] > fullDomain[i].high()) thisView.high[i] = fullDomain[i].high(); } if (!dontLoad) // or loadImage? { r_Minterval orgIv(dimMDD); r_Minterval scaledDom; int i; for (i=0; i<(int)dimMDD; i++) { orgIv << r_Sinterval(thisView.low[i], thisView.high[i]); } collDesc->mddObjs[0].mdd.destroy(); ::wxBeginBusyCursor(wxHOURGLASS_CURSOR); collDesc->mddObjs[0].mdd = rviewDatabase::getScaledObject(scaleObject, orgIv, thisView.scale); ::wxEndBusyCursor(); if (collDesc->mddObjs[0].mdd.is_null()) { Close(TRUE); return; } mddObj = collDesc->mddObjs[0].mdd; interv = mddObj->spatial_domain(); } projectionStringForView(); project->SetValue(projString); scaleString->SetValue(thisView.scale); scaleValue = 100; rviewFlatBaseImage::newProjection(); } int rviewScaledImage::saveView(FILE *fp) { int status = rviewFlatBaseImage::saveView(fp); long *boxdesc = new long[2*dimMDD + 2]; boxdesc[0] = (long)(thisView.dim1); boxdesc[1] = (long)(thisView.dim2); for (unsigned int i=0; idim1 = (int)(boxdesc[0]); loadedView->dim2 = (int)(boxdesc[1]); // why do I always forget these !*&@^$()&^ dim constructors...??? loadedView->low = r_Point(dimMDD); loadedView->high = r_Point(dimMDD); for (unsigned int i=0; ilow[i] = (r_Range)(boxdesc[2+i]); loadedView->high[i] = (r_Range)(boxdesc[2+i+dimMDD]); } } delete [] boxdesc; return 1; } else if (strcmp(key, view_BoxScale) == 0) { ensureLoadedView(); loadedView->scale = atof(value); return 1; } return 0; } return status; } void rviewScaledImage::loadViewFinished(void) { rviewFlatBaseImage::loadViewFinished(); viewHistory.push(thisView); lastZoomBut->Enable(TRUE); thisView.scale = loadedView->scale; thisView.low = loadedView->low; thisView.high = loadedView->high; thisView.dim1 = loadedView->dim1; thisView.dim2 = loadedView->dim2; delete loadedView; loadedView = NULL; newView(TRUE); } void rviewScaledImage::ensureLoadedView(void) { if (loadedView == NULL) { loadedView = new view_desc_t; memset(loadedView, 0, sizeof(view_desc_t)); } } /* * Functions performing the actual translation of MDD into a scaled * image. Code shared between rviewFlatImage and rviewThumb. */ // Number of fractional fixpoint bits #define IMAGE_FIXPREC 16 // A macro for recurring code in projectImage #define PROJECT_HEADER(type) \ if (penv.pt1[penv.dim1] == penv.pt2[penv.dim1]) stepx=0; \ else \ { \ prun[penv.dim1]=penv.pt1[penv.dim1]+1; \ prun[penv.dim2]=penv.pt1[penv.dim2]; \ stepx = &((*mddPtr)[prun]) - &((*mddPtr)[penv.pt1]); \ } \ if (penv.pt1[penv.dim2] == penv.pt2[penv.dim2]) stepy=0; \ else \ { \ prun[penv.dim1]=penv.pt1[penv.dim1]; \ prun[penv.dim2]=penv.pt1[penv.dim2]+1; \ stepy = &((*mddPtr)[prun]) - &((*mddPtr)[penv.pt1]); \ } \ scalestepx = stepx * (int)(1 / penv.scale); \ scalestepy = stepy * (int)(1 / penv.scale); \ fracstepx = ((int)((1<= (1<= (1< *mddPtr = (r_Marray*) (penv.mddPtr); \ type *imgLine, *imgPtr; \ PROJECT_HEADER(type); \ for (h=0; hgetCSTab24()) == NULL) \ { \ PROJECT_IMAGE_START(type) \ { \ *destPtr.l++ = penv.csmap->ValToCS24((double)(*imgPtr) - minVal); \ PROJECT_IMAGE_INCREMENTX; \ } \ PROJECT_IMAGE_INCREMENTY; \ } \ } \ else \ { \ PROJECT_IMAGE_START(type) \ { \ type value; \ value = *imgPtr; \ if (value > maxval) value = maxval; value -= minval; if (value < 0) value = 0;\ *destPtr.l++ = IntToRGBTab24[(unsigned long)(value * scale)]; \ PROJECT_IMAGE_INCREMENTX; \ } \ PROJECT_IMAGE_INCREMENTY; \ } \ } int rviewPrepareFlatProjection(rviewFlatProjEnv &penv) { int baseSize = penv.mddPtr->get_type_length(); penv.width = (int)((penv.pt2[penv.dim1] - penv.pt1[penv.dim1] + 1) * penv.scale); penv.height = (int)((penv.pt2[penv.dim2] - penv.pt1[penv.dim2] + 1) * penv.scale); switch (rviewImageTypes[penv.bt]) { case RVIEW_IMGTYPE_NONE: { if (penv.doCspace) { penv.pitch = penv.width * 4; penv.pad = 32; penv.depth = 32; } else { rviewErrorbox::reportError(lman->lookup("errorUnknownBase"), "rviewPrepareFlatProjection"); return -1; } } break; case RVIEW_IMGTYPE_MONO: penv.pitch = (penv.width + 7) >> 3; penv.pad = 8; penv.depth = 1; break; case RVIEW_IMGTYPE_HIGH: penv.pitch = (penv.width * 2 + 3) & ~3; penv.pad = 32; penv.depth = 15; break; case RVIEW_IMGTYPE_GREY12: // unsigned short = 12bpp grey, gets transformed to 8bpp grey penv.pitch = (penv.width + 3) & ~3; penv.pad = 32; penv.depth = 8; break; default: penv.pitch = (penv.width * baseSize + 3) & ~3; penv.pad = 32; penv.depth = 8*baseSize; break; } #ifdef wx_msw if (penv.bt == rbt_rgb) { penv.pitch = (penv.width * baseSize); penv.pad = 8; } #endif return 0; } int rviewPerformFlatProjection(rviewFlatProjEnv &penv, char *data) { int stepx, stepy, scalestepx, scalestepy; int fracstepx, fracstepy, fracx, fracy; union {char *c; short *s; RGBPixel *r; long *l;} destPtr, destLine; r_Point prun; int w, h; destLine.c = data; prun = penv.pt1; fracy = 0; // Do a colourspace mapping? if (penv.cspaceState != 0) { double minVal, maxVal; long minValL, maxValL; double scalingFactor; unsigned short *IntToRGBTab15; unsigned long *IntToRGBTab24; minVal = penv.csmap->getMinVal(); minValL = (long)minVal; maxVal = penv.csmap->getMaxVal(); maxValL = (long)maxVal; scalingFactor = penv.csmap->getScalingFactor(); IntToRGBTab15 = penv.csmap->getCSTab15(); switch (penv.bt) { #define PROJECT_IMAGE_TRANSFER_PIXEL(type) long value = (long)(*imgPtr); if (value > maxValL) value = maxValL; value -= minValL; if (value < 0) value = 0; *destPtr.s++ = IntToRGBTab15[value] case rbt_char: { PROJECT_IMAGE_BASE(r_Char); } break; case rbt_uchar: { PROJECT_IMAGE_BASE(r_Octet); } break; case rbt_short: { PROJECT_IMAGE_BASE(r_Short); } break; case rbt_ushort: { PROJECT_IMAGE_BASE(r_UShort); } break; case rbt_long: { PROJECT_COLOURSPACE32(r_Long, minValL, maxValL, 1); } break; case rbt_ulong: { PROJECT_COLOURSPACE32(r_ULong, (r_ULong)minValL, (r_ULong)maxValL, 1); } break; case rbt_float: { PROJECT_COLOURSPACE32(r_Float, minVal, maxVal, scalingFactor); } break; case rbt_double: { PROJECT_COLOURSPACE32(r_Double, minVal, maxVal, scalingFactor); } break; default: { rviewErrorbox::reportError(lman->lookup("errorBaseType"), "rviewPerformFlatProjectionCmap"); return -1; } break; } } // No, use actual source data with no transformations. else { switch (rviewImageTypes[penv.bt]) { case RVIEW_IMGTYPE_MONO: { r_Marray *mddPtr = (r_Marray *)(penv.mddPtr); r_Boolean *imgLine, *imgPtr; char val; int mask; PROJECT_HEADER(r_Boolean); for (h=0; h>= 1; if (mask == 0) {*destPtr.c++ = val; val = 0; mask = 0x80;} #endif PROJECT_IMAGE_INCREMENTX; } #if (WX_PIXMAP_SRC_BITORDER == 0) if (mask != 1) #else if (mask != 0x80) #endif *destPtr.c++ = val; PROJECT_IMAGE_INCREMENTY; } } break; #undef PROJECT_IMAGE_TRANSFER_PIXEL #define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.c++ = *imgPtr case RVIEW_IMGTYPE_GREY: { PROJECT_IMAGE_BASE(r_Char) } break; #undef PROJECT_IMAGE_TRANSFER_PIXEL #define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.s++ = *imgPtr case RVIEW_IMGTYPE_HIGH: { PROJECT_IMAGE_BASE(r_Short) } break; #undef PROJECT_IMAGE_TRANSFER_PIXEL #define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.c++ = (char)((*imgPtr) >> 4) case RVIEW_IMGTYPE_GREY12: { PROJECT_IMAGE_BASE(r_UShort) } break; #undef PROJECT_IMAGE_TRANSFER_PIXEL #define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.l++ = *imgPtr case RVIEW_IMGTYPE_TRUE32: { PROJECT_IMAGE_BASE(r_Long) } break; #undef PROJECT_IMAGE_TRANSFER_PIXEL #define PROJECT_IMAGE_TRANSFER_PIXEL(type) *destPtr.r++ = *imgPtr case RVIEW_IMGTYPE_TRUE24: { PROJECT_IMAGE_BASE(RGBPixel) } break; default: { rviewErrorbox::reportError(lman->lookup("errorBaseType"), "rviewPerformFlatProjection"); return -1; } break; } } return 0; }