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]solver
parent
28d1bc67bc
commit
d74b1e7ece
51
draw.cpp
51
draw.cpp
|
@ -479,9 +479,58 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
ForceTextWindowShown();
|
||||
}
|
||||
|
||||
glClearDepth(1.0);
|
||||
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
|
||||
// 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
|
||||
|
|
11
mouse.cpp
11
mouse.cpp
|
@ -79,6 +79,13 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
if(GraphicsEditControlIsVisible()) 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) {
|
||||
middleDown = true;
|
||||
shiftDown = !shiftDown;
|
||||
|
@ -703,6 +710,8 @@ bool GraphicsWindow::ConstrainPointByHovered(hEntity pt) {
|
|||
}
|
||||
|
||||
void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||
orig.mouseDown = true;
|
||||
|
||||
if(GraphicsEditControlIsVisible()) return;
|
||||
HideTextEditControl();
|
||||
|
||||
|
@ -974,6 +983,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
}
|
||||
|
||||
void GraphicsWindow::MouseLeftUp(double mx, double my) {
|
||||
orig.mouseDown = false;
|
||||
|
||||
switch(pending.operation) {
|
||||
case DRAGGING_POINTS:
|
||||
case DRAGGING_CONSTRAINT:
|
||||
|
|
|
@ -669,11 +669,20 @@ public:
|
|||
VectorFileWriter *out);
|
||||
|
||||
static void MenuAnalyze(int id);
|
||||
|
||||
// Additional display stuff
|
||||
struct {
|
||||
SContour path;
|
||||
hEntity point;
|
||||
} traced;
|
||||
SEdgeList nakedEdges;
|
||||
struct {
|
||||
BYTE *fromFile;
|
||||
int w, h;
|
||||
int rw, rh;
|
||||
double scale; // pixels per mm
|
||||
Vector origin;
|
||||
} bgImage;
|
||||
|
||||
void MarkGroupDirty(hGroup hg);
|
||||
void MarkGroupDirtyByEntity(hEntity he);
|
||||
|
|
122
style.cpp
122
style.cpp
|
@ -1,4 +1,5 @@
|
|||
#include "solvespace.h"
|
||||
#include <png.h>
|
||||
|
||||
#define clamp01(x) (max(0, min(1, (x))))
|
||||
|
||||
|
@ -108,6 +109,8 @@ void Style::LoadFactoryDefaults(void) {
|
|||
s->name.strcpy(CnfPrefixToName(d->cnfPrefix));
|
||||
}
|
||||
SS.backgroundColor = RGB(0, 0, 0);
|
||||
if(SS.bgImage.fromFile) MemFree(SS.bgImage.fromFile);
|
||||
SS.bgImage.fromFile = NULL;
|
||||
}
|
||||
|
||||
void Style::FreezeDefaultStyles(void) {
|
||||
|
@ -327,6 +330,87 @@ void TextWindow::ScreenChangeBackgroundColor(int link, DWORD v) {
|
|||
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) {
|
||||
Printf(true, "%Ft color style-name");
|
||||
|
||||
|
@ -354,6 +438,28 @@ void TextWindow::ShowListOfStyles(void) {
|
|||
REDf(rgb), GREENf(rgb), BLUEf(rgb),
|
||||
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, " %Fl%Ll%fload factory defaults%E",
|
||||
&ScreenLoadFactoryDefaultStyles);
|
||||
|
@ -575,6 +681,22 @@ bool TextWindow::EditControlDoneForStyles(char *str) {
|
|||
}
|
||||
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;
|
||||
}
|
||||
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_NAME = 55;
|
||||
static const int EDIT_BACKGROUND_COLOR = 56;
|
||||
static const int EDIT_BACKGROUND_IMG_SCALE = 57;
|
||||
struct {
|
||||
int meaning;
|
||||
int i;
|
||||
|
@ -160,6 +161,7 @@ public:
|
|||
static void ScreenCreateCustomStyle(int link, DWORD v);
|
||||
static void ScreenLoadFactoryDefaultStyles(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 ScreenGoToWebsite(int link, DWORD v);
|
||||
|
@ -195,6 +197,7 @@ public:
|
|||
static void ScreenChangeStyleTextAngle(int link, DWORD v);
|
||||
static void ScreenChangeStyleColor(int link, DWORD v);
|
||||
static void ScreenChangeBackgroundColor(int link, DWORD v);
|
||||
static void ScreenChangeBackgroundImageScale(int link, DWORD v);
|
||||
|
||||
bool EditControlDoneForStyles(char *s);
|
||||
bool EditControlDoneForConfiguration(char *s);
|
||||
|
@ -322,6 +325,7 @@ public:
|
|||
Vector projUp;
|
||||
double scale;
|
||||
struct {
|
||||
bool mouseDown;
|
||||
Vector offset;
|
||||
Vector projRight;
|
||||
Vector projUp;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
copy and paste
|
||||
background image
|
||||
associative entities from solid model, as a special group
|
||||
n*log(n) intersection finding
|
||||
|
||||
|
|
Loading…
Reference in New Issue