Mercurial > hg > aimc
comparison trunk/src/Modules/Output/Graphics/GraphicsView.cc @ 397:7a573750b186
- First add of a lot of graphics code from the old version. Not working yet, not even compiling yet.
author | tomwalters |
---|---|
date | Fri, 15 Oct 2010 05:40:53 +0000 |
parents | |
children | 3ee03a6b95a0 |
comparison
equal
deleted
inserted
replaced
396:06a26f5cdad7 | 397:7a573750b186 |
---|---|
1 // Copyright 2006, Willem van Engen | |
2 // | |
3 // AIM-C: A C++ implementation of the Auditory Image Model | |
4 // http://www.acousticscale.org/AIMC | |
5 // | |
6 // Licensed under the Apache License, Version 2.0 (the "License"); | |
7 // you may not use this file except in compliance with the License. | |
8 // You may obtain a copy of the License at | |
9 // | |
10 // http://www.apache.org/licenses/LICENSE-2.0 | |
11 // | |
12 // Unless required by applicable law or agreed to in writing, software | |
13 // distributed under the License is distributed on an "AS IS" BASIS, | |
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 // See the License for the specific language governing permissions and | |
16 // limitations under the License. | |
17 | |
18 #include "Support/Common.h" | |
19 | |
20 #include "Output/GraphicsView.h" | |
21 #include "Output/GraphicsOutputDevice.h" | |
22 | |
23 GraphicsView::GraphicsView(Parameters *parameters) : Module(parameters) { | |
24 module_description_ = ""; | |
25 module_identifier_ = "graphics"; | |
26 module_type_ = "output"; | |
27 module_version_ = "$Id: $"; | |
28 | |
29 m_pDev = NULL; | |
30 m_bPlotLabels = false; | |
31 m_pAxisX = new GraphAxisSpec(); | |
32 AIM_ASSERT(m_pAxisX); | |
33 m_pAxisY = new GraphAxisSpec(); | |
34 AIM_ASSERT(m_pAxisY); | |
35 m_pAxisFreq = new GraphAxisSpec(); | |
36 AIM_ASSERT(m_pAxisFreq); | |
37 | |
38 m_pAxisY->Initialize(m_pParam, | |
39 _S("graph.y"), | |
40 -1, | |
41 1, | |
42 Scale::SCALE_LINEAR); | |
43 m_fMarginLeft = m_pParam->GetFloat(_S("graph.margin.left")); | |
44 m_fMarginRight = m_pParam->GetFloat(_S("graph.margin.right")); | |
45 m_fMarginTop = m_pParam->GetFloat(_S("graph.margin.top")); | |
46 m_fMarginBottom = m_pParam->GetFloat(_S("graph.margin.bottom")); | |
47 m_bPlotLabels = m_pParam->GetBool(_S("graph.plotlabels")); | |
48 | |
49 const char *sGraphType = m_pParam->GetString(_S("graph.type")); | |
50 if (strcmp(sGraphType, _S("line"))==0) | |
51 m_iGraphType = GraphTypeLine; | |
52 else if (strcmp(sGraphType, _S("colormap"))==0) | |
53 m_iGraphType = GraphTypeColormap; | |
54 else if (strcmp(sGraphType, _S("none"))==0) | |
55 m_iGraphType = GraphTypeNone; | |
56 else { | |
57 ret = false; | |
58 AIM_ERROR(_T("Unrecognized graph type: '%s'"), sGraphType); | |
59 } | |
60 | |
61 if (strcmp(m_pParam->GetString(_S("graph.mindistance")),"auto") == 0) | |
62 // -1 means detect later, based on type and Fire() argument | |
63 m_fMinPlotDistance = -1; | |
64 else | |
65 m_fMinPlotDistance = m_pParam->GetFloat(_S("graph.mindistance")); | |
66 | |
67 } | |
68 | |
69 GraphicsView::~GraphicsView() { | |
70 DELETE_IF_NONNULL(m_pAxisX); | |
71 DELETE_IF_NONNULL(m_pAxisY); | |
72 DELETE_IF_NONNULL(m_pAxisFreq); | |
73 } | |
74 | |
75 bool | |
76 | |
77 bool GraphicsView::InitializeInternal(const SignalBank &bank) { | |
78 if (!m_pDev) { | |
79 LOG_ERROR("Output device not connected"); | |
80 return false; | |
81 } | |
82 | |
83 float y_min = bank.centre_frequency(0); | |
84 float y_max = bank.centre_frequency(bank.channel_count() - 1); | |
85 if (!m_pAxisFreq->Initialize(m_pParam, | |
86 "graph.freq", | |
87 y_min, | |
88 y_max, | |
89 Scale::SCALE_ERB)) { | |
90 LOG_ERROR(""); | |
91 return false; | |
92 } | |
93 | |
94 float x_min = 0.0; | |
95 float x_max = 1000.0 * bank.buffer_length() / bank.sample_rate(); | |
96 if (!m_pAxisX->Initialize(m_pParam, | |
97 "graph.x", | |
98 x_min, | |
99 x_max, | |
100 Scale::SCALE_LINEAR)) { | |
101 LOG_ERROR(""); | |
102 return false; | |
103 } | |
104 | |
105 /* Inform graphics output of maximum number of vertices between | |
106 * gBegin*() and gEnd(), for any type of plot. Colormap needs most. | |
107 */ | |
108 if (!m_pDev->Initialize(MAX(10, bank.buffer_length() * 2 + 2))) { | |
109 LOG_ERROR(""); | |
110 return false; | |
111 } | |
112 } | |
113 | |
114 void GraphicsView::Process(const SignalBank &bank) { | |
115 float height = 1.0 / bank.channel_count(); | |
116 float heightMinMargin = height * (1.0f - m_fMarginBottom - m_fMarginTop); | |
117 float xScaling = 1.0f; | |
118 | |
119 m_pDev->gGrab(); | |
120 PlotAxes(bank); | |
121 m_pDev->gColor3f(1.0f, 1.0f, 0.8f); | |
122 for (int i = 0; i < bank.channel_count(); i++) { | |
123 float yOffs = bank.centre_frequency(i); | |
124 yOffs = m_pAxisFreq->m_pScale->FromLinearScaled(yOffs) + 0.5f; | |
125 /* Don't plot below zero and stop when above 1, since yOffs is | |
126 * monotonically increasing. Because of rounding errors, we need | |
127 * to check for yOffs < -1e-6 instead of yOffs < 0. */ | |
128 if (yOffs < -1e-6) | |
129 continue; | |
130 if (yOffs > 1) | |
131 break; | |
132 | |
133 // Scale to single channel graphing. | |
134 yOffs = yOffs * (1.0f - height) + height / 2.0; | |
135 yOffs = yOffs * (1.0f - m_fMarginTop - m_fMarginBottom) + m_fMarginBottom; | |
136 PlotData(bank[i], yOffs, heightMinMargin, xScaling); | |
137 } | |
138 m_pDev->gRelease(); | |
139 } | |
140 | |
141 void GraphicsView::SetAxisScale(Scale::ScaleType iHori, | |
142 Scale::ScaleType iVert, | |
143 Scale::ScaleType iFreq) { | |
144 AIM_ASSERT(m_pAxisX); | |
145 AIM_ASSERT(m_pAxisY); | |
146 AIM_ASSERT(m_pAxisFreq); | |
147 m_pAxisX->SetDisplayScale(iHori); | |
148 m_pAxisY->SetDisplayScale(iVert); | |
149 m_pAxisFreq->SetDisplayScale(iFreq); | |
150 } | |
151 | |
152 void GraphicsView::BeginDataStrip() { | |
153 m_iPrevValEqual=0; | |
154 m_bFirstPoint=true; | |
155 switch(m_iGraphType) { | |
156 case GraphTypeLine: | |
157 m_pDev->gBeginLineStrip(); | |
158 break; | |
159 case GraphTypeColormap: | |
160 m_pDev->gBeginQuadStrip(); | |
161 break; | |
162 case GraphTypeNone: | |
163 // Nothing: just for testing computation overhead of graphing | |
164 break; | |
165 } | |
166 } | |
167 | |
168 void GraphicsView::PlotDataPoint(float x, | |
169 float y, | |
170 float val, | |
171 float height, | |
172 bool isLast) { | |
173 AIM_ASSERT(m_pDev); | |
174 | |
175 /* Reduce the number of points plotted by eliminating duplicate values: | |
176 * | |
177 * oooo o--o | |
178 * o / o | |
179 * oooo ooo => o--o o--o | |
180 * oooo ooo o--o o-o | |
181 * | |
182 * with 'o' points that are plotted, and '-' by the graphics output | |
183 * device interpolated points. We could be smarter and include | |
184 * first-order interpolation, but we leave that as an exercise for | |
185 * the reader. Please send your patches :) | |
186 * | |
187 * So, we don't draw points that are too close to the previous value. | |
188 * But if the value changes (or it's the last point), we must draw the | |
189 * previous point too. | |
190 */ | |
191 if (!m_bFirstPoint | |
192 && !isLast | |
193 && fabs(m_fPrevVal-val) < m_fMinPlotDistance) { | |
194 m_iPrevValEqual++; | |
195 // Don't set m_fPrevVal to avoid not catching slow changes | |
196 m_fPrevX = x; | |
197 m_fPrevY = y; | |
198 m_fPrevHeight = height; | |
199 return; | |
200 } else { | |
201 if (m_iPrevValEqual > 0) { | |
202 // Draw previous point | |
203 PlotDataPointDirect(m_fPrevX, m_fPrevY, m_fPrevVal, m_fPrevHeight); | |
204 } | |
205 m_iPrevValEqual = 0; | |
206 m_fPrevVal = val; | |
207 m_bFirstPoint = false; | |
208 } | |
209 PlotDataPointDirect(x, y, val, height); | |
210 } | |
211 | |
212 void GraphicsView::PlotDataPointDirect(float x, | |
213 float y, | |
214 float val, | |
215 float height) { | |
216 // Draw it in the right way | |
217 switch(m_iGraphType) { | |
218 case GraphTypeLine: | |
219 m_pDev->gVertex2f(x, y + val * height); | |
220 break; | |
221 case GraphTypeColormap: | |
222 //! \todo make it a real colormap instead of grayscale | |
223 m_pDev->gColor3f(val + 0.5, val + 0.5, val + 0.5); | |
224 m_pDev->gVertex2f(x, y - height / 2); | |
225 m_pDev->gVertex2f(x, y + height / 2); | |
226 break; | |
227 case GraphTypeNone: | |
228 // Nothing: just for testing computation overhead of graphing | |
229 break; | |
230 default: | |
231 // Shouldn't happen | |
232 AIM_ASSERT(0); | |
233 } | |
234 } |