Per-stamp sane scaling range enforced. (generally bigger)

This commit is contained in:
Albert Cahalan 2004-11-24 03:00:10 +00:00
parent 41402eca12
commit 34cd0b93cb
2 changed files with 142 additions and 56 deletions

View file

@ -8,6 +8,10 @@ http://www.newbreedsoftware.com/tuxpaint/
2004.November.23 (0.9.15)
* abstracted stamp scaling (prep for large sizes)
Per-stamp sane scaling range enforced. (generally bigger)
Albert Cahalan <albert@users.sf.net>
* simplify strip_trailing_whitespace, now O(n)
Albert Cahalan <albert@users.sf.net>

View file

@ -55,9 +55,45 @@
#define PROMPTOFFSETX (WINDOW_WIDTH - 640) / 2
#define PROMPTOFFSETY (HEIGHTOFFSET / 2)
/////////////////////////////////////////////////////////////////////
// hide all scale-related values here
#define MIN_STAMP_SIZE 25 /* Stamp can only shrink to 25% (1/4) of original */
#define MAX_STAMP_SIZE 400 /* Stamp can only grow to 400% (4 times) original */
typedef struct scaleparams {
unsigned numer, denom;
} scaleparams;
static scaleparams scaletable[] = {
{ 1, 16}, // 0.0625
{ 3, 32}, // 0.09375
{ 1, 8}, // 0.125
{ 3, 16}, // 0.1875
{ 1, 4}, // 0.25
{ 3, 8}, // 0.375
{ 1, 2}, // 0.5
{ 3, 4}, // 0.75
{ 1, 1}, // 1
{ 3, 2}, // 1.5
{ 2, 1}, // 2
{ 3, 1}, // 3
{ 4, 1}, // 4
{ 6, 1}, // 6
{ 8, 1}, // 8
{ 12, 1}, // 12
};
#define HARD_MIN_STAMP_SIZE 0 // bottom of scaletable
#define HARD_MAX_STAMP_SIZE (sizeof scaletable / sizeof scaletable[0] - 1)
#define MIN_STAMP_SIZE (state_stamps[cur_stamp]->min)
#define MAX_STAMP_SIZE (state_stamps[cur_stamp]->max)
#define CAN_USE_HQ4X (scaletable[state_stamps[cur_stamp]->size] == (scaleparams){4,1})
// to scale some offset, in pixels, like the current stamp is scaled
#define SCALE_LIKE_STAMP(x) ( ((x) * scaletable[state_stamps[cur_stamp]->size].numer + scaletable[state_stamps[cur_stamp]->size].denom-1) / scaletable[state_stamps[cur_stamp]->size].denom )
// pixel dimensions of the current stamp, as scaled
#define CUR_STAMP_W SCALE_LIKE_STAMP(img_stamps[cur_stamp]->w)
#define CUR_STAMP_H SCALE_LIKE_STAMP(img_stamps[cur_stamp]->h)
///////////////////////////////////////////////////////////////////////////////
// #define MAX_FILES 2048 /* Max. # of files in a dir. to worry about... */
@ -65,7 +101,6 @@
#define REPEAT_SPEED 300 /* Initial repeat speed for scrollbars */
#define CURSOR_BLINK_SPEED 500 /* Initial repeat speed for cursor */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -467,13 +502,14 @@ typedef struct info_type {
int mirrorable;
int flipable;
int tintgray;
// int min, def, max; // TODO: size range
} info_type;
typedef struct state_type {
int mirrored;
int flipped;
int size;
unsigned min,size,max;
} state_type;
@ -1820,11 +1856,7 @@ static void mainloop(void)
if (state_stamps[cur_stamp]->size > MIN_STAMP_SIZE)
{
state_stamps[cur_stamp]->size =
state_stamps[cur_stamp]->size / 2;
if (state_stamps[cur_stamp]->size < MIN_STAMP_SIZE)
state_stamps[cur_stamp]->size = MIN_STAMP_SIZE;
state_stamps[cur_stamp]->size--;
playsound(0, SND_SHRINK, 0);
draw_stamps();
@ -1840,11 +1872,7 @@ static void mainloop(void)
if (state_stamps[cur_stamp]->size < MAX_STAMP_SIZE)
{
state_stamps[cur_stamp]->size =
state_stamps[cur_stamp]->size * 2;
if (state_stamps[cur_stamp]->size > MAX_STAMP_SIZE)
state_stamps[cur_stamp]->size = MAX_STAMP_SIZE;
state_stamps[cur_stamp]->size++;
playsound(0, SND_GROW, 0);
draw_stamps();
@ -2051,13 +2079,13 @@ static void mainloop(void)
stamp_draw(old_x, old_y);
#ifdef LOW_QUALITY_STAMP_OUTLINE
rect_xor(old_x - ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100),
old_y - ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100),
old_x + ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100),
old_y + ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100));
// the +1 is for rounding, probably needed only one side though
rect_xor(old_x - (CUR_STAMP_W+1)/2,
old_y - (CUR_STAMP_H+1)/2,
old_x + (CUR_STAMP_W+1)/2,
old_y + (CUR_STAMP_H+1)/2);
#else
stamp_xor(old_x - (img_stamps[cur_stamp]->w / 2),
old_y - (img_stamps[cur_stamp]->h / 2));
stamp_xor(old_x, old_y);
#endif
playsound(1, SND_STAMP, 1);
@ -2765,18 +2793,18 @@ static void mainloop(void)
if (cur_tool == TOOL_STAMP)
{
#ifndef LOW_QUALITY_STAMP_OUTLINE
stamp_xor(old_x - w / 2, old_y - h / 2);
stamp_xor(old_x, old_y);
#else
rect_xor(old_x - ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100),
old_y - ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100),
old_x + ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100),
old_y + ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100));
rect_xor(old_x - (CUR_STAMP_W+1)/2,
old_y - (CUR_STAMP_H+1)/2,
old_x + (CUR_STAMP_W+1)/2,
old_y + (CUR_STAMP_H+1)/2);
#endif
update_screen(old_x - ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100) + 96,
old_y - ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100),
old_x + ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100) + 96,
old_y + ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100));
update_screen(old_x - (CUR_STAMP_W+1)/2 + 96,
old_y - (CUR_STAMP_H+1)/2,
old_x + (CUR_STAMP_W+1)/2 + 96,
old_y + (CUR_STAMP_H+1)/2);
}
else
{
@ -2794,18 +2822,18 @@ static void mainloop(void)
if (cur_tool == TOOL_STAMP)
{
#ifndef LOW_QUALITY_STAMP_OUTLINE
stamp_xor(new_x - w / 2, new_y - h / 2);
stamp_xor(new_x, new_y);
#else
rect_xor(new_x - ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100),
new_y - ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100),
new_x + ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100),
new_y + ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100));
rect_xor(old_x - (CUR_STAMP_W+1)/2,
old_y - (CUR_STAMP_H+1)/2,
old_x + (CUR_STAMP_W+1)/2,
old_y + (CUR_STAMP_H+1)/2);
#endif
update_screen(new_x - ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100) + 96,
new_y - ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100),
new_x + ((img_stamps[cur_stamp]->w / 2) * (state_stamps[cur_stamp]->size) / 100) + 96,
new_y + ((img_stamps[cur_stamp]->h / 2) * (state_stamps[cur_stamp]->size) / 100));
update_screen(old_x - (CUR_STAMP_W+1)/2 + 96,
old_y - (CUR_STAMP_H+1)/2,
old_x + (CUR_STAMP_W+1)/2 + 96,
old_y + (CUR_STAMP_H+1)/2);
}
else
{
@ -3145,7 +3173,7 @@ static void stamp_draw(int x, int y)
/* Shrink or grow it! */
#ifdef USE_HQ4X
if (state_stamps[cur_stamp]->size == 400)
if (CAN_USE_HQ4X)
{
/* Use high quality 4x filter! */
@ -3181,19 +3209,14 @@ static void stamp_draw(int x, int y)
else
#endif
{
final_surf = thumbnail(tmp_surf,
(tmp_surf->w *
state_stamps[cur_stamp]->size) / 100,
(tmp_surf->h *
state_stamps[cur_stamp]->size) / 100,
0);
final_surf = thumbnail(tmp_surf, CUR_STAMP_W, CUR_STAMP_H, 0);
}
/* Where it will go? */
base_x = x - (((tmp_surf->w * state_stamps[cur_stamp]->size) / 100) / 2);
base_y = y - (((tmp_surf->h * state_stamps[cur_stamp]->size) / 100) / 2);
base_x = x - (CUR_STAMP_W+1)/2;
base_y = y - (CUR_STAMP_H+1)/2;
/* And blit it! */
@ -3272,10 +3295,10 @@ static void stamp_draw(int x, int y)
}
}
update_canvas(x - (((tmp_surf->w * state_stamps[cur_stamp]->size) / 100) / 2),
y - (((tmp_surf->h * state_stamps[cur_stamp]->size) / 100) / 2),
x + (((tmp_surf->w * state_stamps[cur_stamp]->size) / 100) / 2),
y + (((tmp_surf->h * state_stamps[cur_stamp]->size) / 100) / 2));
update_canvas(x - (CUR_STAMP_W+1)/2,
y - (CUR_STAMP_H+1)/2,
x + (CUR_STAMP_W+1)/2,
y + (CUR_STAMP_H+1)/2);
/* Free the temporary surfaces */
@ -5514,6 +5537,28 @@ static void setup(int argc, char * argv[])
free(homedirdir);
// The original Tux Paint canvas was 608x472. The canvas can be
// other sizes now, but many old stamps are sized for the small
// canvas. So, with larger canvases, we must choose a good scale
// factor to compensate. As the canvas size grows, the user will
// want a balance of "more stamps on the screen" and "stamps not
// getting tiny". This will calculate the needed scale factor.
unsigned default_stamp_size;
{
double old_diag = sqrt(608*608+472*472);
double new_diag = sqrt(canvas->w*canvas->w+canvas->h*canvas->h);
double good_def = sqrt(new_diag/old_diag);
double good_log = log(good_def);
unsigned defsize = HARD_MAX_STAMP_SIZE;
while(defsize>0){
double this_err = good_log - log(scaletable[defsize].numer / (double)scaletable[defsize].denom);
double next_err = good_log - log(scaletable[defsize-1].numer / (double)scaletable[defsize-1].denom);
if( fabs(next_err) > fabs(this_err) ) break;
defsize--;
}
default_stamp_size = defsize;
}
/* Create stamp thumbnails: */
for (i = 0; i < num_stamps; i++)
@ -5561,8 +5606,43 @@ static void setup(int argc, char * argv[])
inf_stamps[i]->mirrorable = 1;
inf_stamps[i]->tintgray = 1;
inf_stamps[i]->flipable = 1;
// inf_stamps[i]->min = 0;
// inf_stamps[i]->def = 0;
// inf_stamps[i]->max = 0;
}
//
// TODO: convert inf_stamps[i]->min and such to usable data
//
{
int upper = HARD_MAX_STAMP_SIZE;
int lower = 0;
do{
scaleparams *s = &scaletable[upper];
int pw, ph; // proposed width and height
pw = (img_stamps[i]->w * s->numer + s->denom - 1) / s->denom;
ph = (img_stamps[i]->h * s->numer + s->denom - 1) / s->denom;
if(pw < canvas->w * 2 && ph < canvas->h * 2) break;
}while(--upper);
do{
scaleparams *s = &scaletable[lower];
int pw, ph; // proposed width and height
pw = (img_stamps[i]->w * s->numer + s->denom - 1) / s->denom;
ph = (img_stamps[i]->h * s->numer + s->denom - 1) / s->denom;
if(pw*ph > 20) break;
}while(++lower < HARD_MAX_STAMP_SIZE);
if(upper<lower){
// this, if it ever happens, is very bad
upper = (upper+lower)/2;
lower = upper;
}
unsigned mid = default_stamp_size;
if(mid > upper) mid = upper;
if(mid < lower) mid = lower;
state_stamps[i]->min = lower;
state_stamps[i]->size = mid;
state_stamps[i]->max = upper;
}
/* If Tux Paint is in mirror-image-by-default mode, mirror, if we can: */
@ -5572,7 +5652,6 @@ static void setup(int argc, char * argv[])
state_stamps[i]->mirrored = 0;
state_stamps[i]->flipped = 0;
state_stamps[i]->size = 100;
show_progress_bar();
}
@ -8390,6 +8469,10 @@ static info_type * loadinfo(const char * const fname)
inf.tintgray = 1;
inf.flipable = 1;
// inf.min = 0; // dummy values
// inf.def = 0;
// inf.max = 0;
/* Load info! */
@ -11519,7 +11602,6 @@ static void stamp_xor(int x, int y)
Uint8 r, g, b, a, olda, abovea;
SDL_Surface * surf_ptr;
/* Use pre-mirrored stamp image, if applicable: */
if (state_stamps[cur_stamp]->mirrored &&
@ -11575,8 +11657,8 @@ static void stamp_xor(int x, int y)
(a < 128 && abovea >= 128) ||
(a >= 128 && abovea < 128))
{
sx = x + 96 + (((xx - (img_stamps[cur_stamp]->w / 2)) * state_stamps[cur_stamp]->size) / 100) + (img_stamps[cur_stamp]->w / 2);
sy = y + (((yy - (img_stamps[cur_stamp]->h / 2)) * state_stamps[cur_stamp]->size) / 100) + (img_stamps[cur_stamp]->h / 2);
sx = x + 96 + SCALE_LIKE_STAMP(xx - img_stamps[cur_stamp]->w / 2);
sy = y + SCALE_LIKE_STAMP(yy - img_stamps[cur_stamp]->h / 2);
clipped_putpixel(screen, sx, sy,
0xFFFFFFFF - getpixel(screen, sx, sy));