summaryrefslogtreecommitdiffstats
path: root/applications/rview/rviewImage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'applications/rview/rviewImage.cpp')
-rw-r--r--applications/rview/rviewImage.cpp5230
1 files changed, 5230 insertions, 0 deletions
diff --git a/applications/rview/rviewImage.cpp b/applications/rview/rviewImage.cpp
new file mode 100644
index 0000000..bdc6e2f
--- /dev/null
+++ b/applications/rview/rviewImage.cpp
@@ -0,0 +1,5230 @@
+/*
+* 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 <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+
+/**
+ * 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 <wx/wx_prec.h>
+
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <iostream.h>
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+
+
+// 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<r_GMarray> mddPtr;
+ r_Minterval newInterv(dimMDD);
+ //for (i=0; i<dimMDD; i++) newInterv << r_Sinterval(4*mddObj->spatial_domain()[i].low(), 4*mddObj->spatial_domain()[i].high());
+ //mdd_objectScaleInter(mddObj, mddPtr, newInterv, baseType);
+ for (i=0; i<dimMDD; i++) newInterv << r_Sinterval((r_Range)(0.5*mddObj->spatial_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; dim1++) if ((freeDims & (1<<dim1)) != 0) break;
+ for (dim2=dim1+1; dim2<dimMDD; dim2++) if ((freeDims & (1<<dim2)) != 0) break;
+ if ((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; i<dimMDD; i++)
+ {
+ tempInterv << r_Sinterval((r_Range)pt1[i], (r_Range)pt2[i]);
+ }
+
+ *csInterv=tempInterv;
+ }
+
+ doProjRangeCspace = pm;
+}
+
+
+void rviewImage::label(void)
+{
+ if (scaleSlider != NULL)
+ scaleSlider->SetLabel(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; i<dimMDD; i++)
+ {
+ data += sprintf(data, ", %ld", interv[i].low());
+ }
+ project->SetValue(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<r_GMarray> &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<pixHeight; j++, imgLine+=pixPitch) \
+ { \
+ imgPtrS = ((unsigned short*)imgLine) + pixWidth-1; imgSrcPtr = ((type*)imgLine) + pixWidth-1; \
+ for (i=0; i<pixWidth; i++, imgPtrS--, imgSrcPtr--) \
+ { \
+ value = (long)(*imgSrcPtr); if (value > 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; j<pixHeight; j++, imgLine+=pixPitch, imgSrcBase+=virtualPitch) \
+ { \
+ imgPtrL = (unsigned long*)imgLine; imgSrcPtr = (type*)imgSrcBase; \
+ for (i=0; i<pixWidth; i++, imgPtrL++, imgSrcPtr++) \
+ { \
+ *imgPtrL = csmap->ValToCS24((double)(*imgSrcPtr) - minVal); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ for (j=0; j<pixHeight; j++, imgLine+=pixPitch, imgSrcBase+=virtualPitch) \
+ { \
+ imgPtrL = (unsigned long*)imgLine; imgSrcPtr = (type*)imgSrcBase; \
+ for (i=0; i<pixWidth; i++, imgPtrL++, imgSrcPtr++) \
+ { \
+ value = *imgSrcPtr; if (value > 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<r_GMarray> &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<r_Marray<r_Char> > tempMdd = (r_Ref<r_Marray<r_Char> >) mddObj;
+ // Do it like this to avoid having to check all base types
+ r_Point paux = r_Point(dimMDD);
+ for (i=0; i<dimMDD; i++)
+ {
+ paux[i] = interv[i].low();
+ }
+ offset = ((int)(&((*tempMdd)[pt1]) - &((*tempMdd)[paux]))) * baseSize;
+
+ texDesc->data = (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<r_GMarray>)(new r_Marray<r_Char>(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; i<dimMDD; i++)
+ {
+ b += sprintf(b, ", %ld", interv[i].low());
+ }
+
+ project->SetValue(projString);
+ setModeDimension(2);
+
+ for (i=0; i<dimMDD; i++)
+ {
+ mddDesc->dims[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; i<dimMDD; i++)
+ {
+ mddDesc->widths[i] = pt2[i] - pt1[i] + 1;
+ }
+
+ r_Ref<r_Marray<r_Char> > tempMdd = (r_Ref<r_Marray<r_Char> >) mddObj;
+ r_Point paux(dimMDD);
+ for (i=0; i<dimMDD; i++)
+ {
+ paux[i] = interv[i].low();
+ }
+
+ offset = ((int)(&((*tempMdd)[pt1]) - &((*tempMdd)[paux]))) * baseSize;
+
+ mddDesc->data = (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; i<dimMDD; i++)
+ {
+ thisView.low[i] = fullDomain[i].low();
+ thisView.high[i] = fullDomain[i].high();
+ }
+
+ dontLoad = TRUE;
+ loadedView = NULL;
+
+ collDesc = cd;
+}
+
+
+rviewScaledImage::~rviewScaledImage(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "~rviewScaledImage()" );
+ closeViewer();
+ rviewDeleteCollection(collDesc);
+ // I own the scaler object!
+ delete scaleObject;
+ if (loadedView != NULL)
+ delete loadedView;
+}
+
+
+int rviewScaledImage::openViewer(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "openViewer()" );
+
+ if (rviewFlatBaseImage::openViewer() == 0)
+ {
+ zoomInBut = new rviewButton(ctrlPanel);
+ zoomOutBut = new rviewButton(ctrlPanel);
+ lastZoomBut = new rviewButton(ctrlPanel);
+ zoomBoxBut = new rviewButton(ctrlPanel);
+ scaleString = new rviewText(ctrlPanel, thisView.scale);
+
+ lastZoomBut->Enable((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; i<thisView.dim1; i++)
+ {
+ b += sprintf(b, "%ld, ", thisView.low[i]);
+ }
+ b += sprintf(b, "%ld:%ld, ", thisView.low[i], thisView.high[i]);
+ i++;
+ for (; i<thisView.dim2; i++)
+ {
+ b += sprintf(b, "%ld, ", thisView.low[i]);
+ }
+ b += sprintf(b, "%ld:%ld, ", thisView.low[i], thisView.high[i]);
+ i++;
+ for (; i<dimMDD; i++)
+ {
+ b += sprintf(b, "%ld, ", thisView.low[i]);
+ }
+ if (b != projString)
+ b[-2] = '\0';
+}
+
+
+char *rviewScaledImage::initMode(void)
+{
+ return rviewFlatBaseImage::initMode();
+}
+
+
+const r_Minterval &rviewScaledImage::getVirtualDomain(void) const
+{
+
+ return fullDomain;
+}
+
+
+void rviewScaledImage::projectObjectHook(void)
+{
+ RMDBGONCE(3, RMDebug::module_applications, "rviewScaledImage", "projectObjectHook()");
+ int i, j;
+
+ for (i=0; i<(int)dimMDD; i++)
+ {
+ thisView.low[i] = pt1[i];
+ thisView.high[i] = pt2[i];
+ }
+ for (i=0, j=0; i<(int)dimMDD; i++)
+ {
+ if ((freeDims & (1<<i)) != 0)
+ {
+ if (j == 0)
+ {
+ thisView.dim1 = i; j++;
+ }
+ else
+ thisView.dim2 = i;
+ }
+ }
+
+ r_Minterval projFull(dimMDD);
+ r_Minterval projScaled;
+
+ for (i=0; i<dimMDD; i++)
+ {
+ // shift point into full domain's origin...
+ projFull << r_Sinterval(fullDomain[i].low(), fullDomain[i].low() + (pt2[i] - pt1[i]));
+ }
+ // now adapt the values to the actual MDD object
+ if (scaleObject->get_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<dimMDD; i++)
+ {
+ r_Range offset = pt1[i] - fullDomain[i].low();
+ pt1[i] = projScaled[i].low() + offset;
+ if (pt1[i] < interv[i].low()) pt1[i] = interv[i].low();
+ if (pt1[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; i<dimMDD; i++)
+ {
+ boxdesc[2+i] = (long)(thisView.low[i]);
+ boxdesc[2+i+dimMDD] = (long)(thisView.high[i]);
+ }
+ writeViewParam(fp, view_CurrentBox, 2*dimMDD + 2, boxdesc);
+ writeViewParam(fp, view_BoxScale, thisView.scale);
+
+ delete [] boxdesc;
+
+ return status;
+}
+
+
+int rviewScaledImage::readView(const char *key, const char *value)
+{
+ int status = rviewFlatBaseImage::readView(key, value);
+
+ if (status == 0)
+ {
+ if (strcmp(key, view_CurrentBox) == 0)
+ {
+ long *boxdesc = new long[2*dimMDD + 2];
+
+ if (readVector(value, 2*dimMDD + 2, boxdesc) == 0)
+ {
+ ensureLoadedView();
+
+ loadedView->dim1 = (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; i<dimMDD; i++)
+ {
+ loadedView->low[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<<IMAGE_FIXPREC) / penv.scale)) & ((1<<IMAGE_FIXPREC)-1); \
+ fracstepy = ((int)((1<<IMAGE_FIXPREC) / penv.scale)) & ((1<<IMAGE_FIXPREC)-1); \
+ imgLine = (type*)(&((*mddPtr)[penv.pt1]));
+
+#define PROJECT_IMAGE_INCREMENTX \
+ imgPtr += scalestepx; fracx += fracstepx; \
+ if (fracx >= (1<<IMAGE_FIXPREC)) \
+ { \
+ imgPtr += stepx; fracx &= ((1<<IMAGE_FIXPREC)-1); \
+ }
+
+#define PROJECT_IMAGE_INCREMENTY \
+ imgLine += scalestepy; fracy += fracstepy; \
+ if (fracy >= (1<<IMAGE_FIXPREC)) \
+ { \
+ imgLine += stepy; fracy &= ((1<<IMAGE_FIXPREC)-1); \
+ }
+
+// A macro for colourspace translators
+// Do not terminate this macro with a semicolon when using it!
+#define PROJECT_IMAGE_START(type) \
+ r_Marray<type> *mddPtr = (r_Marray<type>*) (penv.mddPtr); \
+ type *imgLine, *imgPtr; \
+ PROJECT_HEADER(type); \
+ for (h=0; h<penv.height; h++, destLine.c+=penv.pitch) \
+ { \
+ for (w=0, imgPtr=imgLine, destPtr.c=destLine.c, fracx=0; w<penv.width; w++)
+
+#define PROJECT_IMAGE_BASE(type) \
+ PROJECT_IMAGE_START(type) \
+ { \
+ PROJECT_IMAGE_TRANSFER_PIXEL(type); \
+ PROJECT_IMAGE_INCREMENTX; \
+ } \
+ PROJECT_IMAGE_INCREMENTY; \
+ }
+
+#define PROJECT_COLOURSPACE32(type, minval, maxval, scale) \
+ if ((IntToRGBTab24 = penv.csmap->getCSTab24()) == 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<r_Boolean> *mddPtr = (r_Marray<r_Boolean> *)(penv.mddPtr);
+ r_Boolean *imgLine, *imgPtr;
+ char val;
+ int mask;
+
+ PROJECT_HEADER(r_Boolean);
+ for (h=0; h<penv.height; h++, destLine.c+=penv.pitch)
+ {
+#if (WX_PIXMAP_SRC_BITORDER == 0)
+ mask = 1;
+#else
+ mask = 0x80;
+#endif
+ val = 0;
+ for (w=0, imgPtr=imgLine, destPtr.c=destLine.c, fracx=0; w<penv.width; w++)
+ {
+ if (*imgPtr) val |= mask;
+#if (WX_PIXMAP_SRC_BITORDER == 0)
+ mask <<= 1; if (mask == 0x100) {*destPtr.c++ = val; val = 0; mask = 1;}
+#else
+ mask >>= 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;
+}