Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Revised Win32 Frambuffer further and fixed bugs

New features:
- Ability to view individual channels (RGBA)
  Hotkeys: C - Color (all of RGB[A])
           R - Red, G - Green, B - Blue, A - Alpha
- Press CTRL-{R,G,B} to toggle those channels on or off
  (can view combination of {R,G,B} channels)
- Pan cursor while dragging.
- Caption bar reflects the channels being viewed.
- HOME key centers the image to window while preserving zoom factor.
- Refactored much code.

Bug fixes:
- Fixed crash while closing framebuffer window due to core renderer unloading
  display driver DLL immediately followed by other threads attempting to access
  its code.
  (We now issue an abort request and unload the module when it's safe to do so).
- Fixed bug in platform-independent part of framebuffer where the Window class
  would be destructed multiple times due to `delete` being called in
 `displayData` function.
- Fixed parts of drawing code to redraw parts of the window correctly.
  • Loading branch information...
commit 1bb31d5c59fc6217fec694b23d70b68274fb19d5 1 parent 166c170
@scorpion007 authored
View
387 src/framebuffer/fbw.cpp
@@ -31,14 +31,19 @@
#include "framebuffer.h"
#include "fbw.h"
+#include "resource.h"
+
#include <windowsx.h>
#include <math.h>
#include <tchar.h>
using namespace Gdiplus;
+static HINSTANCE hInst; // Our DLL's instance.
+
// Foward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+void GenCheckerboard(unsigned int *buf, int w, int h);
#define color(r,g,b,a) ((a << 24) | (r << 16) | (g << 8) | b)
#define get_a(col) ((col) >> 24)
@@ -46,7 +51,14 @@ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
#define get_g(col) (((col) >> 8) & 255)
#define get_b(col) ((col) & 255)
-#define ARRAY_COUNT(x) sizeof(x)/sizeof((x)[0])
+#define ARRAY_COUNT(x) (sizeof(x)/sizeof((x)[0]))
+
+// Channel manipulation macros.
+#define TEST_CHANNEL(x, channel) ((x) & (1 << (channel)))
+#define SET_CHANNEL(x, channel) ((x) |= (1 << (channel)))
+#define UNSET_CHANNEL(x, channel) ((x) &= ~(1 << (channel)))
+#define TOGGLE_CHANNEL(x, channel) ((x) ^= (1 << (channel)))
+#define EXTRACT_CHANNEL(x, channel) (((x) >> (16 - 8 * (channel))) & 0xFF)
// Amount we zoom by each increment.
static const float ZOOM_INCREMENT = .1f;
@@ -82,10 +94,12 @@ CWinDisplay::CWinDisplay(const char *name,
int height,
int numSamples):
CDisplay(name, samples, width, height, numSamples),
-mouseDown(false), mag_fac(1), hInst(NULL), hWnd(NULL) {
- int i,j;
+mouseDown(false), mag_fac(1), hWnd(NULL), m_channels(0),
+m_alpha(false) {
DWORD threadID;
+ memset(m_channelsPresent, 0, sizeof(m_channelsPresent));
+
// Initialize GDI+.
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
@@ -94,22 +108,27 @@ mouseDown(false), mag_fac(1), hInst(NULL), hWnd(NULL) {
lastPos.x = 0;
lastPos.y = 0;
- imageData = new unsigned int[width*height];
+ // Default to RGB
+ SetRGBA();
- // Create a checkerboard pattern
- for (i=0;i<height;i++) {
- for (j=0;j<width;j++) {
- unsigned char d = 255;
- int t = 0;
+ imageData = new unsigned int[width*height];
- if ((i & 63) < 32) t ^= 1;
- if ((j & 63) < 32) t ^= 1;
+ int nchannels = min(numSamples, MAX_CHANNELS);
- if (t) d = 128;
+ // Allocate storage for channel data.
+ for (int i = 0; i < nchannels; ++i) {
+ m_channelData[i] = new float[width*height];
+ memset(m_channelData[i], 0, width*height*sizeof(float));
+ m_channelsPresent[i] = true;
+ }
- imageData[i*width+j] = color(d,d,d,d);
- }
- }
+ if (m_channelsPresent[CHAN_ALPHA]) {
+ // Create a checkerboard pattern
+ GenCheckerboard(imageData, width, height);
+ } else {
+ // Fill with black.
+ memset(imageData, 0, width*height * sizeof(*imageData));
+ }
active = TRUE;
willRedraw = FALSE;
@@ -126,6 +145,11 @@ mouseDown(false), mag_fac(1), hInst(NULL), hWnd(NULL) {
// Comments :
CWinDisplay::~CWinDisplay() {
delete [] imageData;
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ if (m_channelsPresent[i]) {
+ delete [] m_channelData[i];
+ }
+ }
GdiplusShutdown(gdiplusToken);
}
@@ -152,18 +176,109 @@ TCHAR *basename(TCHAR *path) {
// cch - count of characters available in buf.
// file_name - Name of image we're displaying.
// mag_fac - magnification factor.
-void MakeWindowTitle(TCHAR *buf, size_t cch, TCHAR *file_name, float mag_fac) {
+void MakeWindowTitle(TCHAR *buf, size_t cch, TCHAR *file_name, float mag_fac,
+ DWORD channels, bool alphaOnly) {
TCHAR *szBasename = basename(file_name);
- _sntprintf(buf, cch-1, "%s [%d%%] - Pixie", szBasename,
- (int)(round(mag_fac * 100)));
+ _sntprintf(buf, cch-1, "%s [%d%%] [%c%c%c%c] - Pixie", szBasename,
+ (int)(round(mag_fac * 100)),
+ TEST_CHANNEL(channels, CHAN_RED) && !alphaOnly ? 'R' : '-',
+ TEST_CHANNEL(channels, CHAN_GREEN) && !alphaOnly ? 'G' : '-',
+ TEST_CHANNEL(channels, CHAN_BLUE) && !alphaOnly ? 'B' : '-',
+ TEST_CHANNEL(channels, CHAN_ALPHA) || alphaOnly ? 'A' : '-'
+ );
buf[cch-1] = 0; // Null-terminate it.
}
void CWinDisplay::UpdateWinTitle() {
- MakeWindowTitle(wndTitle, ARRAY_COUNT(wndTitle), name, mag_fac);
+ DWORD channels = m_channels;
+ if (m_channelsPresent[CHAN_ALPHA]) {
+ SET_CHANNEL(channels, CHAN_ALPHA);
+ }
+ MakeWindowTitle(wndTitle, ARRAY_COUNT(wndTitle), name, mag_fac, channels,
+ m_alpha);
SetWindowText(hWnd, wndTitle);
}
+// Generates a checkerboard pattern.
+void GenCheckerboard(unsigned int *buf, int w, int h) {
+ for (int i=0; i<h; i++) {
+ for (int j=0; j<w; j++) {
+ unsigned char d = 255;
+ int t = 0;
+
+ if ((i & 63) < 32) t ^= 1;
+ if ((j & 63) < 32) t ^= 1;
+
+ if (t) d = 128;
+
+ buf[i*w+j] = color(d,d,d,d);
+ }
+ }
+}
+
+// The alpha channel is special and requires different processing.
+void CWinDisplay::QuantizeAlpha() {
+ assert(m_alpha);
+ if (!m_channelsPresent[CHAN_ALPHA]) {
+ // Fill with black
+ memset(imageData, 0, width*height*sizeof(*imageData));
+ } else {
+ for (int i = 0; i < height; ++i) {
+ for (int j = 0; j < width; ++j) {
+ int idx = j + i*width;
+ imageData[idx] = ComputeDisplayPixel(0, j, i);
+ }
+ }
+ }
+}
+
+void CWinDisplay::ShowAlpha() {
+ m_alpha = true;
+ QuantizeAlpha();
+ UpdateWinTitle();
+ InvalidateRect(hWnd, NULL, FALSE);
+}
+
+DWORD CWinDisplay::ComputeDisplayPixel(DWORD channels, int x, int y) {
+ int idx = x + y*width;
+
+ if (m_alpha || (!channels && m_channelsPresent[CHAN_ALPHA])) {
+ BYTE alpha = m_channelsPresent[CHAN_ALPHA] ?
+ m_channelData[CHAN_ALPHA][idx] * 255 : 0;
+ return color(alpha, alpha, alpha, 0);
+ } else {
+ float alpha = m_channelsPresent[CHAN_ALPHA] ?
+ m_channelData[CHAN_ALPHA][idx] : 1;
+
+ BYTE rgb[3] = {0};
+
+ // Blend the sample with the background to achieve transparency
+ // (for display).
+ for (int ch = 0; ch < 3; ++ch) {
+ if (TEST_CHANNEL(channels, ch) && m_channelsPresent[ch]) {
+ rgb[ch] = alpha * m_channelData[ch][idx] * 255 + (1-alpha) *
+ EXTRACT_CHANNEL(imageData[idx], ch);
+ }
+ }
+
+ return color(rgb[0], rgb[1], rgb[2], 0);
+ }
+}
+
+// Quantize several color channels for display and cache the results.
+// channels - bitfield of channels to display
+void CWinDisplay::QuantizeChannels(DWORD channels) {
+ // Make the background (in case it's transparent).
+ GenCheckerboard(imageData, width, height);
+
+ for (int i = 0; i < height; ++i) {
+ for (int j = 0; j < width; ++j) {
+ int idx = j + i*width;
+ imageData[idx] = ComputeDisplayPixel(channels, j, i);
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////
// Class : CWinDisplay
// Method : main
@@ -175,7 +290,7 @@ void CWinDisplay::main() {
MSG msg;
const char *szPixieWndClass = "PixieWinDisplay";
- hInst = (HINSTANCE) GetModuleHandle(NULL);
+ curPan = LoadCursor(hInst, MAKEINTRESOURCE(IDC_PAN));
wcex.cbSize = sizeof(WNDCLASSEX);
@@ -185,7 +300,7 @@ void CWinDisplay::main() {
wcex.cbWndExtra = 0;
wcex.hInstance = hInst;
wcex.hIcon = LoadIcon(NULL,IDI_APPLICATION);
- wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szPixieWndClass;
@@ -203,7 +318,8 @@ void CWinDisplay::main() {
AdjustWindowRect(&rc, dwStyle, FALSE);
// Create the initial title for the window.
- MakeWindowTitle(wndTitle, ARRAY_COUNT(wndTitle), name, mag_fac);
+ MakeWindowTitle(wndTitle, ARRAY_COUNT(wndTitle), name, mag_fac, m_channels,
+ m_alpha);
// Create the window (non-resizable).
hWnd = CreateWindow(szPixieWndClass, wndTitle,
@@ -222,7 +338,7 @@ void CWinDisplay::main() {
// Show the window
ShowWindow(hWnd,SW_SHOW);
- UpdateWindow(hWnd);
+ InvalidateRect(hWnd, NULL, FALSE);
// Set up the bitmap
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
@@ -237,9 +353,6 @@ void CWinDisplay::main() {
info.bmiHeader.biClrUsed = 0;
info.bmiHeader.biClrImportant = 0;
- // Display the checkerboard
- redraw();
-
// Main message loop:
while (GetMessage(&msg, NULL, 0,0)) {
TranslateMessage(&msg);
@@ -256,6 +369,7 @@ void CWinDisplay::OnMouseDown(int x, int y) {
InvalidateRect(hWnd, NULL, TRUE);
SetCapture(hWnd);
+ SetCursor(curPan);
}
void CWinDisplay::OnSize(int cx, int cy) {
@@ -329,6 +443,8 @@ void CWinDisplay::CenterImage() {
zoomOrigin.x = ((rc.right - rc.left) - width*mag_fac)/2;
zoomOrigin.y = ((rc.bottom - rc.top) - height*mag_fac)/2;
+
+ InvalidateRect(hWnd, NULL, FALSE);
}
void CWinDisplay::ActualPixels() {
@@ -356,11 +472,7 @@ void CWinDisplay::ZoomImage(float mag) {
// Description : Redraw the image
// Return Value : -
// Comments :
-void CWinDisplay::redraw(HDC hdc, RECT *rcUpdate) {
- Graphics graphics(hdc);
- graphics.SetInterpolationMode(InterpolationModeNearestNeighbor);
- Bitmap bm(&info, imageData);
-
+void CWinDisplay::redraw() {
float dstx = zoomOrigin.x;
float dsty = zoomOrigin.y;
@@ -368,24 +480,62 @@ void CWinDisplay::redraw(HDC hdc, RECT *rcUpdate) {
float dsth = height*mag_fac;
// Entire surface.
- RECT rc = { 0, 0, width, height };
-
- ExcludeClipRect(hdc, (int)dstx, (int)dsty,
- (int)(dstx+dstw), (int)(dsty+dsth));
+ RECT rcEntire;
+ GetClientRect(hWnd, &rcEntire);
- FillRect(hdc, rcUpdate ? rcUpdate : &rc, GetStockBrush(GRAY_BRUSH));
- SelectClipRgn(hdc, NULL);
+ Graphics graphics(hWnd);
+ graphics.SetInterpolationMode(InterpolationModeNearestNeighbor);
+ graphics.SetPixelOffsetMode(PixelOffsetModeHalf);
+ Bitmap bm(&info, imageData);
RectF dest(dstx, dsty, dstw, dsth);
+ graphics.ExcludeClip(dest);
+ SolidBrush bgBrush(Color(127, 127, 127));
+ graphics.FillRectangle(&bgBrush,
+ rcEntire.left, rcEntire.top,
+ rcEntire.right-rcEntire.left,
+ rcEntire.bottom-rcEntire.top);
+ graphics.ResetClip();
+
graphics.DrawImage(&bm, dest);
willRedraw = FALSE;
}
-// Helper function to repaint the whole window, out of the WM_PAINT message.
-void CWinDisplay::redraw() {
- HDC hdc = GetDC(hWnd);
- redraw(hdc, NULL); // Repaint the whole window.
- ReleaseDC(hWnd, hdc);
+void CWinDisplay::ToggleChannel(int channel) {
+ TOGGLE_CHANNEL(m_channels, channel);
+ QuantizeChannels(m_channels);
+ UpdateWinTitle();
+ InvalidateRect(hWnd, NULL, FALSE);
+}
+
+void CWinDisplay::ShowChannel(int channel) {
+ m_alpha = false;
+ m_channels = 0;
+ SET_CHANNEL(m_channels, channel);
+ UpdateWinTitle();
+ QuantizeChannels(m_channels);
+ InvalidateRect(hWnd, NULL, FALSE);
+}
+
+void CWinDisplay::SetRGBA() {
+ m_channels = 0;
+ SET_CHANNEL(m_channels, CHAN_RED);
+ SET_CHANNEL(m_channels, CHAN_GREEN);
+ SET_CHANNEL(m_channels, CHAN_BLUE);
+}
+
+void CWinDisplay::ShowRGBA() {
+ m_alpha = false;
+ SetRGBA();
+ UpdateWinTitle();
+ QuantizeChannels(m_channels);
+ InvalidateRect(hWnd, NULL, FALSE);
+}
+
+// Use during keyboard message only!
+BOOL IsKeyDown(int nVirtKey) {
+ // Return the high bit.
+ return GetKeyState(nVirtKey) & 0x8000;
}
void CWinDisplay::OnKeyDown(int vk) {
@@ -393,15 +543,56 @@ void CWinDisplay::OnKeyDown(int vk) {
case VK_NUMPAD0:
ActualPixels(); // Zoom to 100%.
break;
+ case 'C': // Show RGBA color
+ ShowRGBA();
+ break;
+ case 'R':
+ if (IsKeyDown(VK_CONTROL)) {
+ ToggleChannel(CHAN_RED);
+ } else {
+ ShowChannel(CHAN_RED);
+ }
+ break;
+ case 'G':
+ if (IsKeyDown(VK_CONTROL)) {
+ ToggleChannel(CHAN_GREEN);
+ } else {
+ ShowChannel(CHAN_GREEN);
+ }
+ break;
+ case 'B':
+ if (IsKeyDown(VK_CONTROL)) {
+ ToggleChannel(CHAN_BLUE);
+ } else {
+ ShowChannel(CHAN_BLUE);
+ }
+ break;
+ case 'A':
+ ShowAlpha();
+ break;
+ case VK_HOME:
+ CenterImage();
+ break;
+ }
+}
+
+BOOL CWinDisplay::OnSetCursor() {
+ if (mouseDown) {
+ SetCursor(curPan);
+ return TRUE;
+ } else {
+ return FALSE;
}
}
+
///////////////////////////////////////////////////////////////////////
-// Class : CWinDisplay
-// Method : data
-// Description : Draw the data onto the screen
-// Return Value : -
-// Comments :
+// Class : CWinDisplay
+// Method : data
+// Description : Draw the data onto the screen
+// Return Value :
+// Comments : Must be thread safe! Called from multiple threads
+// concurrently.
int CWinDisplay::data(int x,int y,int w,int h,float *d) {
int i,j;
@@ -410,70 +601,55 @@ int CWinDisplay::data(int x,int y,int w,int h,float *d) {
for (i=0;i<h;i++) {
const float *src = &d[i*w*numSamples];
unsigned int *dest = &imageData[((height-(i+y)-1)*width+x)];
+ int offset = (height-1-(i+y))*width + x;
switch(numSamples) {
case 0:
break;
case 1:
for (j=0;j<w;j++) {
- unsigned char d = (unsigned char) (src[0]*255);
+ for (int c = 0; c < numSamples; ++c) {
+ m_channelData[c][offset + j] = src[c];
+ }
- *dest++ = color(d,d,d,d);
+ *dest++ = ComputeDisplayPixel(m_channels, x+j, height-1-(y+i));
src++;
}
break;
case 2:
for (j=0;j<w;j++) {
- const float r = src[0]*src[1]*255 + (1-src[1])*get_r(dest[0]);
- const float a = src[1]*255 + (1-src[1])*get_a(dest[0]);
- unsigned char dr = (unsigned char) r;
- unsigned char da = (unsigned char) a;
-
- *dest++ = color(dr,dr,dr,da);
-
+ for (int c = 0; c < numSamples; ++c) {
+ m_channelData[c][offset + j] = src[c];
+ }
+ *dest++ = ComputeDisplayPixel(m_channels, x+j, height-1-(y+i));
src += 2;
}
break;
case 3:
for (j=0;j<w;j++) {
- unsigned char dr = (unsigned char) (src[0]*255);
- unsigned char dg = (unsigned char) (src[1]*255);
- unsigned char db = (unsigned char) (src[2]*255);
-
- *dest++ = color(dr,dg,db,(unsigned char) 255);
-
+ for (int c = 0; c < numSamples; ++c) {
+ m_channelData[c][offset + j] = src[c];
+ }
+ *dest++ = ComputeDisplayPixel(m_channels, x+j, height-1-(y+i));
src += 3;
}
break;
case 4:
for (j=0;j<w;j++) {
- const float r = src[0]*src[3]*255 + (1-src[3])*get_r(dest[0]);
- const float g = src[1]*src[3]*255 + (1-src[3])*get_g(dest[0]);
- const float b = src[2]*src[3]*255 + (1-src[3])*get_b(dest[0]);
- const float a = src[3]*255 + (1-src[3])*get_a(dest[0]);
- unsigned char dr = (unsigned char) r;
- unsigned char dg = (unsigned char) g;
- unsigned char db = (unsigned char) b;
- unsigned char da = (unsigned char) a;
-
- *dest++ = color(dr,dg,db,da);
-
+ for (int c = 0; c < numSamples; ++c) {
+ m_channelData[c][offset + j] = src[c];
+ }
+ *dest++ = ComputeDisplayPixel(m_channels, x+j, height-1-(y+i));
src += 4;
}
break;
default:
for (j=0;j<w;j++) {
- float r = src[0]*src[3]*255 + (1-src[3])*get_r(*dest);
- float g = src[1]*src[3]*255 + (1-src[3])*get_g(*dest);
- float b = src[2]*src[3]*255 + (1-src[3])*get_b(*dest);
- float a = src[3]*255 + (1-src[3])*get_a(*dest);
- unsigned char dr = (unsigned char) r;
- unsigned char dg = (unsigned char) g;
- unsigned char db = (unsigned char) b;
- unsigned char da = (unsigned char) a;
-
- *dest++ = color(dr,dg,db,da);
-
+ // We only support storing up to 4 channels for now (RGBA)
+ for (int c = 0; c < 4; ++c) {
+ m_channelData[c][offset + j] = src[c];
+ }
+ *dest++ = ComputeDisplayPixel(m_channels, x+j, height-1-(y+i));
src += numSamples;
}
break;
@@ -481,11 +657,10 @@ int CWinDisplay::data(int x,int y,int w,int h,float *d) {
}
if (active) {
- if (willRedraw == FALSE) {
- // Pump messages
- willRedraw = TRUE;
- PostMessage(hWnd,WM_PAINT,(WPARAM) this,0);
- }
+ float dstx = zoomOrigin.x + x;
+ float dsty = zoomOrigin.y + y;
+ RECT rc = { dstx, dsty, dstx + w*mag_fac , dsty + h*mag_fac };
+ InvalidateRect(hWnd, &rc, FALSE);
}
return active;
@@ -498,9 +673,6 @@ int CWinDisplay::data(int x,int y,int w,int h,float *d) {
// Return Value : -
// Comments :
void CWinDisplay::finish() {
- // Pump the redraw message
- redraw();
-
// Wait for the user to close the window
WaitForSingleObject(thread,INFINITE);
}
@@ -513,12 +685,9 @@ void CWinDisplay::finish() {
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
CWinDisplay *dpy = (CWinDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
- switch (message) {
+ switch (message) {
case WM_PAINT: {
- PAINTSTRUCT ps;
- BeginPaint(hWnd, &ps);
- dpy->redraw(ps.hdc, &ps.rcPaint);
- EndPaint(hWnd, &ps);
+ dpy->redraw();
break;
}
case WM_LBUTTONDOWN:
@@ -543,13 +712,23 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_GETMINMAXINFO:
dpy->OnGetMinMaxInfo((MINMAXINFO*)lParam);
break;
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- default:
- return DefWindowProc(hWnd, message, wParam, lParam);
- }
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ case WM_SETCURSOR:
+ if (dpy->OnSetCursor()) {
+ break;
+ }
+ }
- return 0;
+ return DefWindowProc(hWnd, message, wParam, lParam);
}
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ hInst = hinstDLL; // Save our module handle.
+ break;
+ }
+ return TRUE;
+}
View
36 src/framebuffer/fbw.h
@@ -36,6 +36,13 @@
#include "framebuffer.h"
+enum CHANNEL {
+ CHAN_RED,
+ CHAN_GREEN,
+ CHAN_BLUE,
+ CHAN_ALPHA,
+ MAX_CHANNELS
+};
///////////////////////////////////////////////////////////////////////
// Class : CWinDisplay
@@ -53,27 +60,42 @@ class CWinDisplay : public CDisplay {
HANDLE thread;
void redraw();
- void redraw(HDC hdc, RECT *rcUpdate);
void OnMouseDown(int x, int y);
void OnMouseUp(int x, int y);
void OnMouseMove(int x, int y);
void OnMouseWheel(int x, int y, int zDelta);
void OnKeyDown(int vk);
void OnSize(int cx, int cy);
+ BOOL OnSetCursor();
void OnGetMinMaxInfo(MINMAXINFO *mmi);
private:
- HINSTANCE hInst; // current instance
HWND hWnd; // current window
BITMAPINFO info; // bitmap info
- RGBQUAD *bmiColors; // the colors
- unsigned int *imageData;
+
+ unsigned int *imageData; // Cached, quantized color channel for display.
+
+ float *m_channelData[MAX_CHANNELS]; // Original float channel data
+
+ // Tells us whether a channel is present.
+ bool m_channelsPresent[MAX_CHANNELS];
+
int active;
int willRedraw;
+ void QuantizeChannels(DWORD channels);
+ void QuantizeAlpha();
+ DWORD ComputeDisplayPixel(DWORD channels, int x, int y);
+
void UpdateWinTitle();
void ZoomImage(float mag); // Zoom to a fixed factor.
void ZoomDelta(float dmag); // Zoom by some offset
+ void ToggleChannel(int channel);
+ void ShowAlpha();
+ void ShowChannel(int channel);
+ void ShowRGBA();
+ void SetRGBA();
+
// Helper functions for common cases.
void ZoomIn();
void ZoomOut();
@@ -84,12 +106,16 @@ class CWinDisplay : public CDisplay {
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
TCHAR wndTitle[200];
+ DWORD m_channels;
+ bool m_alpha; // Show alpha only (takes precedence over color).
+
// Zoom origin
POINTFLOAT zoomOrigin;
POINTFLOAT lastPos;
float mag_fac;
- POINT vpOrigin; // viewport origin.
bool mouseDown;
+
+ HCURSOR curPan; // Pan cursor.
};
View
26 src/framebuffer/framebuffer.cpp
@@ -95,7 +95,6 @@ void CDisplay::clampData(int w,int h,float *d) {
// Return Value : The handle to the image on success, NULL othervise
// Comments :
void *displayStart(const char *name,int width,int height,int numSamples,const char *samples,TDisplayParameterFunction findParameter) {
-
#ifdef _WINDOWS
CWinDisplay *cWindow = new CWinDisplay(name,samples,width,height,numSamples);
#else
@@ -115,17 +114,13 @@ void *displayStart(const char *name,int width,int height,int numSamples,const ch
// Description : Receive image data
// Return Value : TRUE on success, FALSE otherwise
// Comments :
-int displayData(void *im,int x,int y,int w,int h,float *data) {
- CDisplay *cWindow = (CDisplay *) im;
-
- assert(cWindow != NULL);
+// NOTE: This code needs to be re-entrant, as it will be called from multiple
+// threads at the same time!
- if (cWindow->data(x,y,w,h,data) == FALSE) {
- delete cWindow;
- return FALSE;
- }
- return TRUE;
+int displayData(void *im,int x,int y,int w,int h,float *data) {
+ CDisplay *cWindow = (CDisplay *) im;
+ return cWindow->data(x,y,w,h,data);
}
///////////////////////////////////////////////////////////////////////
@@ -134,13 +129,8 @@ int displayData(void *im,int x,int y,int w,int h,float *data) {
// Return Value : TRUE on success, FALSE othervise
// Comments :
void displayFinish(void *im) {
- CDisplay *cWindow = (CDisplay *) im;
-
- assert(cWindow != NULL);
-
- cWindow->finish();
-
- delete cWindow;
-
+ CDisplay *cWindow = (CDisplay *) im;
+ cWindow->finish();
+ delete cWindow;
}
View
82 src/framebuffer/framebuffer.rc
@@ -0,0 +1,82 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Australia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_PAN CURSOR "D:\\dev\\pixie\\src\\framebuffer\\panCursor.cur"
+#endif // English (Australia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
View
BIN  src/framebuffer/panCursor.cur
Binary file not shown
View
16 src/framebuffer/resource.h
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by framebuffer.rc
+//
+#define IDC_PAN 101
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
View
4 src/ri/renderer.h
@@ -465,10 +465,12 @@ class CRenderer {
class CDisplayData {
public:
CDisplayData(): module(NULL), handle(NULL), start(NULL), data(NULL),
- rawData(NULL), finish(NULL), display(NULL) {}
+ rawData(NULL), finish(NULL), display(NULL), abort(false)
+ {}
void *module; // The module handle for the out device
void *handle; // The handle for the out device
+ bool abort; // Is an abort in progress?
int numSamples; // The number of samples
CDisplayChannel *channels;
int numChannels;
View
41 src/ri/rendererDisplay.cpp
@@ -212,13 +212,15 @@ void CRenderer::endDisplays() {
// Finish the out images
for (i=0;i<numDisplays;i++) {
- // Is the module up ?
- if (datas[i].module != NULL) {
- datas[i].finish(datas[i].handle);
- if (strcmp(datas[i].display->outDevice,RI_SHADOW) == 0) {
- CRenderer::context->RiMakeShadowV(datas[i].displayName,datas[i].displayName,0,NULL,NULL);
- }
- }
+ // Call its cleanup function.
+ datas[i].finish(datas[i].handle);
+
+ // Unload it from memory.
+ osUnloadModule(datas[i].module);
+
+ if (strcmp(datas[i].display->outDevice,RI_SHADOW) == 0) {
+ CRenderer::context->RiMakeShadowV(datas[i].displayName,datas[i].displayName,0,NULL,NULL);
+ }
if (datas[i].displayName != NULL) free(datas[i].displayName);
// Delete the fill array if set
@@ -265,7 +267,7 @@ void CRenderer::dispatch(int left,int top,int width,int height,float *pixels) {
// Send the pixels to the output servers
for (i=0;i<numDisplays;i++) {
- if (datas[i].module != NULL) {
+ if (!datas[i].abort) { // Check for abort requested.
float *dispatchData;
int imageSamples = datas[i].numSamples;
int size = width*height*imageSamples*sizeof(float);
@@ -291,16 +293,19 @@ void CRenderer::dispatch(int left,int top,int width,int height,float *pixels) {
}
}
- if (datas[i].data(datas[i].handle,left,top,width,height,dispatchData) == FALSE) {
- // Lock this piece of code
- osLock(displayKillMutex);
- datas[i].handle = NULL;
- numActiveDisplays--;
- if (numActiveDisplays == 0) hiderFlags |= HIDER_BREAK;
- osUnloadModule(datas[i].module);
- datas[i].module = NULL;
- osUnlock(displayKillMutex);
- }
+ if (datas[i].data(datas[i].handle, left,
+ top, width, height, dispatchData) == FALSE) {
+ // Lock this piece of code
+ osLock(displayKillMutex);
+ datas[i].abort = true; // Abort was requested.
+ numActiveDisplays--;
+ if (numActiveDisplays == 0) hiderFlags |= HIDER_BREAK;
+ // NOTE: It's not safe to unload the module here, since
+ // another thread may be about to enter its data() function above!
+ // We just mark this display as having an abort request and clean it
+ // up at the end, skipping the rest of the buckets.
+ osUnlock(displayKillMutex);
+ }
if (size >= MAX_DISPATCH_SIZE) delete [] dispatchData;
}
View
10 windows/vcnet8/Pixie/framebuffer/framebuffer.vcproj
@@ -408,7 +408,7 @@
>
</File>
<File
- RelativePath=".\resource.h"
+ RelativePath="..\..\..\..\src\framebuffer\resource.h"
>
</File>
</Filter>
@@ -417,6 +417,14 @@
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
+ <File
+ RelativePath="..\..\..\..\src\framebuffer\framebuffer.rc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\..\src\framebuffer\panCursor.cur"
+ >
+ </File>
</Filter>
</Files>
<Globals>
Please sign in to comment.
Something went wrong with that request. Please try again.