Add ability to set a background image. I import a png with libpng,
load it as a texture, and show it instead of a flat-color background. Includes user interface to specify scale and translation of image, but the rotation is always aligned to the view. [git-p4: depot-paths = "//depot/solvespace/": change = 2071]
This commit is contained in:
parent
28d1bc67bc
commit
d74b1e7ece
51
draw.cpp
51
draw.cpp
|
@ -479,9 +479,58 @@ void GraphicsWindow::Paint(int w, int h) {
|
||||||
ForceTextWindowShown();
|
ForceTextWindowShown();
|
||||||
}
|
}
|
||||||
|
|
||||||
glClearDepth(1.0);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
if(SS.bgImage.fromFile) {
|
||||||
|
// If a background image is loaded, then we draw it now as a texture.
|
||||||
|
// This handles the resizing for us nicely.
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 10);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
|
||||||
|
SS.bgImage.rw, SS.bgImage.rh,
|
||||||
|
0,
|
||||||
|
GL_RGB, GL_UNSIGNED_BYTE,
|
||||||
|
SS.bgImage.fromFile);
|
||||||
|
|
||||||
|
double tw = ((double)SS.bgImage.w) / SS.bgImage.rw,
|
||||||
|
th = ((double)SS.bgImage.h) / SS.bgImage.rh;
|
||||||
|
|
||||||
|
double mmw = SS.bgImage.w / SS.bgImage.scale,
|
||||||
|
mmh = SS.bgImage.h / SS.bgImage.scale;
|
||||||
|
|
||||||
|
Vector origin = SS.bgImage.origin;
|
||||||
|
origin = origin.DotInToCsys(projRight, projUp, n);
|
||||||
|
// Place the depth of our origin at the point that corresponds to
|
||||||
|
// w = 1, so that it's unaffected by perspective.
|
||||||
|
origin.z = (offset.ScaledBy(-1)).Dot(n);
|
||||||
|
origin = origin.ScaleOutOfCsys(projRight, projUp, n);
|
||||||
|
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glTexCoord2d(0, 0);
|
||||||
|
glxVertex3v(origin);
|
||||||
|
|
||||||
|
glTexCoord2d(0, th);
|
||||||
|
glxVertex3v(origin.Plus(projUp.ScaledBy(mmh)));
|
||||||
|
|
||||||
|
glTexCoord2d(tw, th);
|
||||||
|
glxVertex3v(origin.Plus(projRight.ScaledBy(mmw).Plus(
|
||||||
|
projUp. ScaledBy(mmh))));
|
||||||
|
|
||||||
|
glTexCoord2d(tw, 0);
|
||||||
|
glxVertex3v(origin.Plus(projRight.ScaledBy(mmw)));
|
||||||
|
glEnd();
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now clear the depth; so the background color and image are both at
|
||||||
|
// the very back of everything.
|
||||||
|
glClearDepth(1.0);
|
||||||
|
|
||||||
// Nasty case when we're reloading the imported files; could be that
|
// Nasty case when we're reloading the imported files; could be that
|
||||||
// we get an error, so a dialog pops up, and a message loop starts, and
|
// we get an error, so a dialog pops up, and a message loop starts, and
|
||||||
// we have to get called to paint ourselves. If the sketch is screwed
|
// we have to get called to paint ourselves. If the sketch is screwed
|
||||||
|
|
11
mouse.cpp
11
mouse.cpp
|
@ -79,6 +79,13 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
||||||
if(GraphicsEditControlIsVisible()) return;
|
if(GraphicsEditControlIsVisible()) return;
|
||||||
if(context.active) return;
|
if(context.active) return;
|
||||||
|
|
||||||
|
if(!orig.mouseDown) {
|
||||||
|
// If someone drags the mouse into our window with the left button
|
||||||
|
// already depressed, then we don't have our starting point; so
|
||||||
|
// don't try.
|
||||||
|
leftDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
if(rightDown) {
|
if(rightDown) {
|
||||||
middleDown = true;
|
middleDown = true;
|
||||||
shiftDown = !shiftDown;
|
shiftDown = !shiftDown;
|
||||||
|
@ -703,6 +710,8 @@ bool GraphicsWindow::ConstrainPointByHovered(hEntity pt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
|
orig.mouseDown = true;
|
||||||
|
|
||||||
if(GraphicsEditControlIsVisible()) return;
|
if(GraphicsEditControlIsVisible()) return;
|
||||||
HideTextEditControl();
|
HideTextEditControl();
|
||||||
|
|
||||||
|
@ -974,6 +983,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsWindow::MouseLeftUp(double mx, double my) {
|
void GraphicsWindow::MouseLeftUp(double mx, double my) {
|
||||||
|
orig.mouseDown = false;
|
||||||
|
|
||||||
switch(pending.operation) {
|
switch(pending.operation) {
|
||||||
case DRAGGING_POINTS:
|
case DRAGGING_POINTS:
|
||||||
case DRAGGING_CONSTRAINT:
|
case DRAGGING_CONSTRAINT:
|
||||||
|
|
|
@ -669,11 +669,20 @@ public:
|
||||||
VectorFileWriter *out);
|
VectorFileWriter *out);
|
||||||
|
|
||||||
static void MenuAnalyze(int id);
|
static void MenuAnalyze(int id);
|
||||||
|
|
||||||
|
// Additional display stuff
|
||||||
struct {
|
struct {
|
||||||
SContour path;
|
SContour path;
|
||||||
hEntity point;
|
hEntity point;
|
||||||
} traced;
|
} traced;
|
||||||
SEdgeList nakedEdges;
|
SEdgeList nakedEdges;
|
||||||
|
struct {
|
||||||
|
BYTE *fromFile;
|
||||||
|
int w, h;
|
||||||
|
int rw, rh;
|
||||||
|
double scale; // pixels per mm
|
||||||
|
Vector origin;
|
||||||
|
} bgImage;
|
||||||
|
|
||||||
void MarkGroupDirty(hGroup hg);
|
void MarkGroupDirty(hGroup hg);
|
||||||
void MarkGroupDirtyByEntity(hEntity he);
|
void MarkGroupDirtyByEntity(hEntity he);
|
||||||
|
|
122
style.cpp
122
style.cpp
|
@ -1,4 +1,5 @@
|
||||||
#include "solvespace.h"
|
#include "solvespace.h"
|
||||||
|
#include <png.h>
|
||||||
|
|
||||||
#define clamp01(x) (max(0, min(1, (x))))
|
#define clamp01(x) (max(0, min(1, (x))))
|
||||||
|
|
||||||
|
@ -108,6 +109,8 @@ void Style::LoadFactoryDefaults(void) {
|
||||||
s->name.strcpy(CnfPrefixToName(d->cnfPrefix));
|
s->name.strcpy(CnfPrefixToName(d->cnfPrefix));
|
||||||
}
|
}
|
||||||
SS.backgroundColor = RGB(0, 0, 0);
|
SS.backgroundColor = RGB(0, 0, 0);
|
||||||
|
if(SS.bgImage.fromFile) MemFree(SS.bgImage.fromFile);
|
||||||
|
SS.bgImage.fromFile = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Style::FreezeDefaultStyles(void) {
|
void Style::FreezeDefaultStyles(void) {
|
||||||
|
@ -327,6 +330,87 @@ void TextWindow::ScreenChangeBackgroundColor(int link, DWORD v) {
|
||||||
SS.TW.edit.meaning = EDIT_BACKGROUND_COLOR;
|
SS.TW.edit.meaning = EDIT_BACKGROUND_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int RoundUpToPowerOfTwo(int v)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 31; i++) {
|
||||||
|
int vt = (1 << i);
|
||||||
|
if(vt >= v) {
|
||||||
|
return vt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextWindow::ScreenBackgroundImage(int link, DWORD v) {
|
||||||
|
if(SS.bgImage.fromFile) MemFree(SS.bgImage.fromFile);
|
||||||
|
SS.bgImage.fromFile = NULL;
|
||||||
|
|
||||||
|
if(link == 'l') {
|
||||||
|
FILE *f = NULL;
|
||||||
|
png_struct *png_ptr = NULL;
|
||||||
|
png_info *info_ptr = NULL;
|
||||||
|
|
||||||
|
char importFile[MAX_PATH] = "";
|
||||||
|
if(!GetOpenFile(importFile, PNG_EXT, PNG_PATTERN)) goto err;
|
||||||
|
f = fopen(importFile, "rb");
|
||||||
|
if(!f) goto err;
|
||||||
|
|
||||||
|
BYTE header[8];
|
||||||
|
fread(header, 1, 8, f);
|
||||||
|
if(png_sig_cmp(header, 0, 8)) goto err;
|
||||||
|
|
||||||
|
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
if(!png_ptr) goto err;
|
||||||
|
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if(!info_ptr) goto err;
|
||||||
|
|
||||||
|
if(setjmp(png_jmpbuf(png_ptr))) goto err;
|
||||||
|
|
||||||
|
png_init_io(png_ptr, f);
|
||||||
|
png_set_sig_bytes(png_ptr, 8);
|
||||||
|
|
||||||
|
png_read_png(png_ptr, info_ptr,
|
||||||
|
PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA, NULL);
|
||||||
|
|
||||||
|
int w = info_ptr->width,
|
||||||
|
h = info_ptr->height;
|
||||||
|
BYTE **rows = png_get_rows(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
// Round to next-highest powers of two, since the textures require
|
||||||
|
// that. And round up to 4, to guarantee DWORD alignment.
|
||||||
|
int rw = max(4, RoundUpToPowerOfTwo(w)),
|
||||||
|
rh = max(4, RoundUpToPowerOfTwo(h));
|
||||||
|
|
||||||
|
SS.bgImage.fromFile = (BYTE *)MemAlloc(rw*rh*3);
|
||||||
|
for(int i = 0; i < h; i++) {
|
||||||
|
memcpy(SS.bgImage.fromFile + ((h - 1) - i)*(rw*3), rows[i], w*3);
|
||||||
|
}
|
||||||
|
SS.bgImage.w = w;
|
||||||
|
SS.bgImage.h = h;
|
||||||
|
SS.bgImage.rw = rw;
|
||||||
|
SS.bgImage.rh = rh;
|
||||||
|
SS.bgImage.scale = SS.GW.scale;
|
||||||
|
SS.bgImage.origin = SS.GW.offset.ScaledBy(-1);
|
||||||
|
|
||||||
|
err:
|
||||||
|
if(png_ptr) png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
if(f) fclose(f);
|
||||||
|
}
|
||||||
|
SS.later.showTW = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextWindow::ScreenChangeBackgroundImageScale(int link, DWORD v) {
|
||||||
|
char str[300];
|
||||||
|
sprintf(str, "%.3f",
|
||||||
|
(SS.viewUnits == SolveSpace::UNIT_MM) ? SS.bgImage.scale :
|
||||||
|
SS.bgImage.scale * 25.4);
|
||||||
|
SS.TW.edit.meaning = EDIT_BACKGROUND_IMG_SCALE;
|
||||||
|
ShowTextEditControl(v, 10, str);
|
||||||
|
}
|
||||||
|
|
||||||
void TextWindow::ShowListOfStyles(void) {
|
void TextWindow::ShowListOfStyles(void) {
|
||||||
Printf(true, "%Ft color style-name");
|
Printf(true, "%Ft color style-name");
|
||||||
|
|
||||||
|
@ -354,6 +438,28 @@ void TextWindow::ShowListOfStyles(void) {
|
||||||
REDf(rgb), GREENf(rgb), BLUEf(rgb),
|
REDf(rgb), GREENf(rgb), BLUEf(rgb),
|
||||||
top[rows-1] + 2, &ScreenChangeBackgroundColor);
|
top[rows-1] + 2, &ScreenChangeBackgroundColor);
|
||||||
|
|
||||||
|
Printf(false, "");
|
||||||
|
Printf(false, "%Ft background bitmap image%E");
|
||||||
|
if(SS.bgImage.fromFile) {
|
||||||
|
Printf(false, "%Ba %Ftwidth:%E %dpx %Ftheight:%E %dpx",
|
||||||
|
SS.bgImage.w, SS.bgImage.h);
|
||||||
|
if(SS.viewUnits == SolveSpace::UNIT_MM) {
|
||||||
|
Printf(false, " %Ftscale:%E %# px/mm %Fl%Ll%f%D[change]%E",
|
||||||
|
SS.bgImage.scale,
|
||||||
|
&ScreenChangeBackgroundImageScale, top[rows-1] + 2);
|
||||||
|
} else {
|
||||||
|
Printf(false, " %Ftscale:%E %# px/inch %Fl%Ll%f%D[change]%E",
|
||||||
|
SS.bgImage.scale*25.4,
|
||||||
|
&ScreenChangeBackgroundImageScale, top[rows-1] + 2);
|
||||||
|
}
|
||||||
|
Printf(false, "%Ba %Fl%Lc%fclear background image%E",
|
||||||
|
&ScreenBackgroundImage);
|
||||||
|
} else {
|
||||||
|
Printf(false, "%Ba none - %Fl%Ll%fload background image%E",
|
||||||
|
&ScreenBackgroundImage);
|
||||||
|
Printf(false, " (bottom left will be center of view)");
|
||||||
|
}
|
||||||
|
|
||||||
Printf(false, "");
|
Printf(false, "");
|
||||||
Printf(false, " %Fl%Ll%fload factory defaults%E",
|
Printf(false, " %Fl%Ll%fload factory defaults%E",
|
||||||
&ScreenLoadFactoryDefaultStyles);
|
&ScreenLoadFactoryDefaultStyles);
|
||||||
|
@ -575,6 +681,22 @@ bool TextWindow::EditControlDoneForStyles(char *str) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EDIT_BACKGROUND_IMG_SCALE: {
|
||||||
|
Expr *e = Expr::From(str);
|
||||||
|
if(e) {
|
||||||
|
double ev = e->Eval();
|
||||||
|
if(ev < 0.001 || isnan(ev)) {
|
||||||
|
Error("Scale must not be zero or negative!");
|
||||||
|
} else {
|
||||||
|
SS.bgImage.scale =
|
||||||
|
(SS.viewUnits == SolveSpace::UNIT_MM) ? ev :
|
||||||
|
ev / 25.4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("Not a valid number or expression: '%s'", str);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
4
ui.h
4
ui.h
|
@ -101,6 +101,7 @@ public:
|
||||||
static const int EDIT_STYLE_FILL_COLOR = 54;
|
static const int EDIT_STYLE_FILL_COLOR = 54;
|
||||||
static const int EDIT_STYLE_NAME = 55;
|
static const int EDIT_STYLE_NAME = 55;
|
||||||
static const int EDIT_BACKGROUND_COLOR = 56;
|
static const int EDIT_BACKGROUND_COLOR = 56;
|
||||||
|
static const int EDIT_BACKGROUND_IMG_SCALE = 57;
|
||||||
struct {
|
struct {
|
||||||
int meaning;
|
int meaning;
|
||||||
int i;
|
int i;
|
||||||
|
@ -160,6 +161,7 @@ public:
|
||||||
static void ScreenCreateCustomStyle(int link, DWORD v);
|
static void ScreenCreateCustomStyle(int link, DWORD v);
|
||||||
static void ScreenLoadFactoryDefaultStyles(int link, DWORD v);
|
static void ScreenLoadFactoryDefaultStyles(int link, DWORD v);
|
||||||
static void ScreenAssignSelectionToStyle(int link, DWORD v);
|
static void ScreenAssignSelectionToStyle(int link, DWORD v);
|
||||||
|
static void ScreenBackgroundImage(int link, DWORD v);
|
||||||
|
|
||||||
static void ScreenShowConfiguration(int link, DWORD v);
|
static void ScreenShowConfiguration(int link, DWORD v);
|
||||||
static void ScreenGoToWebsite(int link, DWORD v);
|
static void ScreenGoToWebsite(int link, DWORD v);
|
||||||
|
@ -195,6 +197,7 @@ public:
|
||||||
static void ScreenChangeStyleTextAngle(int link, DWORD v);
|
static void ScreenChangeStyleTextAngle(int link, DWORD v);
|
||||||
static void ScreenChangeStyleColor(int link, DWORD v);
|
static void ScreenChangeStyleColor(int link, DWORD v);
|
||||||
static void ScreenChangeBackgroundColor(int link, DWORD v);
|
static void ScreenChangeBackgroundColor(int link, DWORD v);
|
||||||
|
static void ScreenChangeBackgroundImageScale(int link, DWORD v);
|
||||||
|
|
||||||
bool EditControlDoneForStyles(char *s);
|
bool EditControlDoneForStyles(char *s);
|
||||||
bool EditControlDoneForConfiguration(char *s);
|
bool EditControlDoneForConfiguration(char *s);
|
||||||
|
@ -322,6 +325,7 @@ public:
|
||||||
Vector projUp;
|
Vector projUp;
|
||||||
double scale;
|
double scale;
|
||||||
struct {
|
struct {
|
||||||
|
bool mouseDown;
|
||||||
Vector offset;
|
Vector offset;
|
||||||
Vector projRight;
|
Vector projRight;
|
||||||
Vector projUp;
|
Vector projUp;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
|
|
||||||
copy and paste
|
copy and paste
|
||||||
background image
|
|
||||||
associative entities from solid model, as a special group
|
associative entities from solid model, as a special group
|
||||||
n*log(n) intersection finding
|
n*log(n) intersection finding
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user