0.53 features

This commit is contained in:
nothings.org 2007-06-26 01:00:05 +00:00
parent a553caff7f
commit e3dc0675b7
8 changed files with 186 additions and 77 deletions

View File

@ -1,5 +0,0 @@
@echo off
call release
call tarball
cd ..
call upload

144
imv.c
View File

@ -20,8 +20,6 @@
#pragma comment(linker, "/FILEALIGN:0x200") #pragma comment(linker, "/FILEALIGN:0x200")
//#pragma comment(linker, "/OPT:NOWIN98") //#pragma comment(linker, "/OPT:NOWIN98")
#define WIN32_MEAN_AND_LEAN
#define WIN32_EXTRA_LEAN
#define _WIN32_WINNT 0x0400 #define _WIN32_WINNT 0x0400
#include <windows.h> #include <windows.h>
#include <stdio.h> #include <stdio.h>
@ -36,8 +34,9 @@
void error(char *str) { MessageBox(NULL, str, "imv(stb) error", MB_OK); } void error(char *str) { MessageBox(NULL, str, "imv(stb) error", MB_OK); }
#ifdef _DEBUG
int do_debug; int do_debug;
void o(char *str, ...) void ods(char *str, ...)
{ {
if (do_debug) { if (do_debug) {
char buffer[1024]; char buffer[1024];
@ -48,6 +47,11 @@ void o(char *str, ...)
OutputDebugString(buffer); OutputDebugString(buffer);
} }
} }
#define o(x) ods x
#else
#define o(x)
#endif
#define FRAME 3 #define FRAME 3
#define FRAME2 (FRAME >> 1) #define FRAME2 (FRAME >> 1)
@ -184,19 +188,22 @@ void *diskload_task(void *p)
DiskCommand dc; DiskCommand dc;
// wait for a command from the main thread // wait for a command from the main thread
o("READ: Waiting for disk request.\n"); o(("READ: Waiting for disk request.\n"));
stb_sem_waitfor(disk_command_queue); stb_sem_waitfor(disk_command_queue);
// grab the command; don't let the command or the cache change while we do it // grab the command; don't let the command or the cache change while we do it
stb_mutex_begin(cache_mutex); stb_mutex_begin(cache_mutex);
{ {
dc = dc_shared; dc = dc_shared;
for (i=0; i < dc.num_files; ++i) for (i=0; i < dc.num_files; ++i) {
dc.files[i]->status = LOAD_reading; dc.files[i]->status = LOAD_reading;
assert(dc.files[i]->filedata == NULL);
}
dc_shared.num_files = 0;
} }
stb_mutex_end(cache_mutex); stb_mutex_end(cache_mutex);
o("READ: Got disk request, %d items.\n", dc.num_files); o(("READ: Got disk request, %d items.\n", dc.num_files));
for (i=0; i < dc.num_files; ++i) { for (i=0; i < dc.num_files; ++i) {
int n; int n;
uint8 *data; uint8 *data;
@ -204,10 +211,11 @@ o("READ: Got disk request, %d items.\n", dc.num_files);
// check if the main thread changed its mind about this // check if the main thread changed its mind about this
if (dc.files[i]->bail) { if (dc.files[i]->bail) {
o("READ: Bailing on disk request\n"); o(("READ: Bailing on disk request\n"));
dc.files[i]->status = LOAD_inactive; dc.files[i]->status = LOAD_inactive;
} else { } else {
o("READ: Loading file %s\n", dc.files[i]->filename); o(("READ: Loading file %s\n", dc.files[i]->filename));
assert(dc.files[i]->filedata == NULL);
data = stb_file(dc.files[i]->filename, &n); data = stb_file(dc.files[i]->filename, &n);
// don't need to mutex these, because we own them via ->status // don't need to mutex these, because we own them via ->status
@ -233,7 +241,7 @@ o("READ: Loading file %s\n", dc.files[i]->filename);
} }
} }
o("READ: Finished command\n"); o(("READ: Finished command\n"));
} }
} }
@ -275,17 +283,17 @@ void *decode_task(void *p)
volatile ImageFile *f; volatile ImageFile *f;
f = decoder_choose(); f = decoder_choose();
if (f == NULL) { if (f == NULL) {
o("DECODE: blocking\n"); o(("DECODE: blocking\n"));
stb_sem_waitfor(decode_queue); stb_sem_waitfor(decode_queue);
o("DECODE: woken\n"); o(("DECODE: woken\n"));
} else { } else {
int x,y,n; int x,y,n;
uint8 *data; uint8 *data;
assert(f->status == LOAD_decoding); assert(f->status == LOAD_decoding);
o("DECIDE: decoding %s\n", f->filename); o(("DECIDE: decoding %s\n", f->filename));
data = stbi_load_from_memory(f->filedata, f->len, &x, &y, &n, BPP); data = stbi_load_from_memory(f->filedata, f->len, &x, &y, &n, BPP);
decoder_idle = TRUE; decoder_idle = TRUE;
o("DECODE: decoded %s\n", f->filename); o(("DECODE: decoded %s\n", f->filename));
free(f->filedata); free(f->filedata);
f->filedata = NULL; f->filedata = NULL;
if (data == NULL) { if (data == NULL) {
@ -390,6 +398,7 @@ Image image_region(Image *p, int x, int y, int w, int h)
static void image_resize(Image *dest, Image *src, ImageFile *cache); static void image_resize(Image *dest, Image *src, ImageFile *cache);
Image *cur; Image *cur;
char *cur_filename;
void display(HWND win, HDC hdc) void display(HWND win, HDC hdc)
{ {
@ -425,6 +434,7 @@ struct
{ {
queued_size size; queued_size size;
Image *image; Image *image;
char *filename;
} pending_resize; } pending_resize;
typedef struct typedef struct
@ -489,6 +499,7 @@ void queue_resize(int w, int h, ImageFile *src_c, int immediate)
if (!immediate) { if (!immediate) {
src_c->status = LOAD_resizing; src_c->status = LOAD_resizing;
pending_resize.image = NULL; pending_resize.image = NULL;
pending_resize.filename = strdup(src_c->filename);
stb_workq(resize_workers, work_resize, &res, &pending_resize.image); stb_workq(resize_workers, work_resize, &res, &pending_resize.image);
} else { } else {
image_resize(&res.dest, src, NULL); image_resize(&res.dest, src, NULL);
@ -513,23 +524,50 @@ void enqueue_resize(int left, int top, int width, int height)
void ideal_window_size(int w, int h, int *w_ideal, int *h_ideal, int *x, int *y); void ideal_window_size(int w, int h, int *w_ideal, int *h_ideal, int *x, int *y);
void update_source(ImageFile *q) enum
{
DISPLAY_actual,
DISPLAY_current,
DISPLAY__num,
};
int display_mode;
void size_to_current(int maximize)
{ {
Image *z = q->image;
int w2,h2; int w2,h2;
int w,h,x,y; int w,h,x,y;
Image *z = source;
source = z;
source_c = q;
w2 = source->x+FRAME*2, h2 = source->y+FRAME*2; w2 = source->x+FRAME*2, h2 = source->y+FRAME*2;
switch (display_mode) {
case DISPLAY_actual:
ideal_window_size(w2,h2, &w,&h, &x,&y); ideal_window_size(w2,h2, &w,&h, &x,&y);
break;
case DISPLAY_current:
if (maximize) {
x = y = -FRAME;
w = GetSystemMetrics(SM_CXSCREEN) + FRAME*2;
h = GetSystemMetrics(SM_CYSCREEN) + FRAME*2;
} else {
RECT rect;
GetWindowRect(win, &rect);
x = rect.left;
y = rect.top;
w = rect.right - rect.left;
h = rect.bottom - rect.top;
}
break;
}
if (w == source->x+FRAME*2 && h == source->y+FRAME*2) { if (w == w2 && h == h2) {
int j; int j;
unsigned char *p = z->pixels; unsigned char *p = z->pixels;
imfree(cur); imfree(cur);
free(cur_filename);
cur = bmp_alloc(z->x + FRAME*2, z->y + FRAME*2); cur = bmp_alloc(z->x + FRAME*2, z->y + FRAME*2);
cur_filename = strdup(source_c->filename);
frame(cur); frame(cur);
{ {
for (j=0; j < z->y; ++j) { for (j=0; j < z->y; ++j) {
@ -548,6 +586,22 @@ void update_source(ImageFile *q)
} }
} }
void update_source(ImageFile *q)
{
Image *z = q->image;
source = z;
source_c = q;
size_to_current(FALSE);
}
void toggle_display(void)
{
display_mode = (display_mode + 1) % DISPLAY__num;
size_to_current(TRUE);
}
char path_to_file[4096], *filename; char path_to_file[4096], *filename;
char **image_files; char **image_files;
int cur_loc = -1; int cur_loc = -1;
@ -648,7 +702,7 @@ void flush_cache(int locked)
} }
if (MAIN_OWNS(&p) && p.status != LOAD_unused) { if (MAIN_OWNS(&p) && p.status != LOAD_unused) {
if (!locked) stb_mutex_end(cache_mutex); if (!locked) stb_mutex_end(cache_mutex);
o("MAIN: freeing cache: %s\n", p.filename); o(("MAIN: freeing cache: %s\n", p.filename));
stb_sdict_remove(file_cache, p.filename, NULL); stb_sdict_remove(file_cache, p.filename, NULL);
--occupied_slots; // occupied slots --occupied_slots; // occupied slots
if (p.status == LOAD_available) if (p.status == LOAD_available)
@ -663,7 +717,7 @@ o("MAIN: freeing cache: %s\n", p.filename);
} }
} }
if (!locked) stb_mutex_end(cache_mutex); if (!locked) stb_mutex_end(cache_mutex);
o("Reduced to %d megabytes\n", total >> 20); o(("Reduced to %d megabytes\n", total >> 20));
} }
} }
@ -702,20 +756,16 @@ void queue_disk_command(DiskCommand *dc, int which, int make_current)
} else { } else {
int i,tried_again=FALSE; int i,tried_again=FALSE;
// find a cache slot // find a cache slot
try_again:
for (i=0; i < MAX_CACHED_IMAGES; ++i) for (i=0; i < MAX_CACHED_IMAGES; ++i)
if (cache[i].status == LOAD_unused) if (cache[i].status == LOAD_unused)
break; break;
if (i == MAX_CACHED_IMAGES) { if (i == MAX_CACHED_IMAGES) {
if (tried_again) {
stb_fatal("Internal logic error: no free cache slots, but flush_cache() should free a few"); stb_fatal("Internal logic error: no free cache slots, but flush_cache() should free a few");
} return;
tried_again = TRUE;
flush_cache(TRUE);
goto try_again;
} }
z = &cache[i]; z = &cache[i];
free(z->filename); free(z->filename);
assert(z->filedata == NULL);
z->filename = strdup(filename); z->filename = strdup(filename);
z->lru = 0; z->lru = 0;
z->status = LOAD_inactive; z->status = LOAD_inactive;
@ -723,6 +773,7 @@ void queue_disk_command(DiskCommand *dc, int which, int make_current)
} }
assert(z->status == LOAD_inactive); assert(z->status == LOAD_inactive);
o(("MAIN: proposing %s\n", z->filename));
z->status = LOAD_inactive; z->status = LOAD_inactive;
z->image = NULL; z->image = NULL;
z->bail = 0; z->bail = 0;
@ -749,6 +800,7 @@ void advance(int dir)
// need to grab the cache // need to grab the cache
stb_mutex_begin(cache_mutex); stb_mutex_begin(cache_mutex);
flush_cache(TRUE);
dc.num_files = 0; dc.num_files = 0;
queue_disk_command(&dc, cur_loc, 1); // first thing to load: this file queue_disk_command(&dc, cur_loc, 1); // first thing to load: this file
if (dir) { if (dir) {
@ -758,6 +810,8 @@ void advance(int dir)
if (dc.num_files) { if (dc.num_files) {
dc_shared = dc; dc_shared = dc;
for (i=0; i < dc.num_files; ++i)
assert(dc.files[i]->filedata == NULL);
stb_sem_release(disk_command_queue); stb_sem_release(disk_command_queue);
} }
stb_mutex_end(cache_mutex); stb_mutex_end(cache_mutex);
@ -782,6 +836,7 @@ void open_file(void)
filename = filenamebuffer; filename = filenamebuffer;
stb_fixpath(filename); stb_fixpath(filename);
stb_splitpath(path_to_file, filename, STB_PATH); stb_splitpath(path_to_file, filename, STB_PATH);
free_fileinfo();
init_filelist(); init_filelist();
advance(0); advance(0);
} }
@ -834,6 +889,8 @@ void resize(int step)
y -= y2>>1; y -= y2>>1;
enqueue_resize(x,y,x2,y2); enqueue_resize(x,y,x2,y2);
} }
display_mode = zoom==1 ? DISPLAY_actual : DISPLAY_current;
} }
enum enum
@ -864,11 +921,11 @@ static void cursor_regions(int *x0, int *y0, int *x1, int *y1)
if (w2 < 12) { if (w2 < 12) {
w2 = w >> 2; w2 = w >> 2;
if (w2 < 4) w2 = w >> 1; if (w2 < 4) w2 = w >> 1;
} } else if (w2 > 100) w2 = 100;
if (h2 < 12) { if (h2 < 12) {
h2 = h >> 2; h2 = h >> 2;
if (h2 < 4) h2 = h >> 1; if (h2 < 4) h2 = h >> 1;
} } else if (h2 > 100) h2 = 100;
if (h2 < w2) w2 = h2; if (h2 < w2) w2 = h2;
if (w2 < h2) h2 = w2; if (w2 < h2) h2 = w2;
*x0 = w2; *x0 = w2;
@ -895,6 +952,9 @@ void set_cursor(int x, int y)
void mouse(UINT ev, int x, int y) void mouse(UINT ev, int x, int y)
{ {
switch (ev) { switch (ev) {
case WM_LBUTTONDBLCLK:
toggle_display();
break;
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
if (!anymode()) { if (!anymode()) {
RECT rect; RECT rect;
@ -933,8 +993,10 @@ void mouse(UINT ev, int x, int y)
RECT rect; RECT rect;
GetWindowRect(win, &rect); GetWindowRect(win, &rect);
assert(rx || ry); assert(rx || ry);
display_mode = DISPLAY_current;
#define LIMIT 16 #define LIMIT 16
if (rx < 0) rect.left = stb_min(rect.left+x-ex, rect.right+-LIMIT); if (rx < 0) rect.left = stb_min(rect.left+x-ex, rect.right-LIMIT);
if (rx > 0) rect.right = stb_max(rect.left+LIMIT, rect.left+x-ex2); if (rx > 0) rect.right = stb_max(rect.left+LIMIT, rect.left+x-ex2);
if (ry < 0) rect.top = stb_min(rect.top+y-ey, rect.bottom-LIMIT); if (ry < 0) rect.top = stb_min(rect.top+y-ey, rect.bottom-LIMIT);
if (ry > 0) rect.bottom = stb_max(rect.top+LIMIT, rect.top+y-ey2); if (ry > 0) rect.bottom = stb_max(rect.top+LIMIT, rect.top+y-ey2);
@ -997,6 +1059,7 @@ int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_LBUTTONUP: case WM_LBUTTONUP:
case WM_RBUTTONUP: case WM_RBUTTONUP:
case WM_LBUTTONDBLCLK:
mouse(uMsg, (short) LOWORD(lParam), (short) HIWORD(lParam)); mouse(uMsg, (short) LOWORD(lParam), (short) HIWORD(lParam));
return 0; return 0;
@ -1073,7 +1136,7 @@ int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
break; break;
case MY_ALT | '\r': case MY_ALT | '\r':
// alt-enter toggle_display();
break; break;
default: default:
return DefWindowProc (hWnd, uMsg, wParam, lParam); return DefWindowProc (hWnd, uMsg, wParam, lParam);
@ -1133,6 +1196,12 @@ void ideal_window_size(int w, int h, int *w_ideal, int *h_ideal, int *x, int *y)
} }
} }
int cur_is_current(void)
{
if (!cur_filename) return FALSE;
if (!source_c || !source_c->filename) return FALSE;
return !strcmp(cur_filename, source_c->filename);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{ {
@ -1150,7 +1219,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
int image_n; int image_n;
resize_threads = stb_processor_count(); resize_threads = stb_processor_count();
#ifdef _DEBUG
do_debug = IsDebuggerPresent(); do_debug = IsDebuggerPresent();
#endif
hInst = hInstance; hInst = hInstance;
GlobalMemoryStatus(&mem); GlobalMemoryStatus(&mem);
@ -1159,7 +1230,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
/* Register the frame class */ /* Register the frame class */
memset(&wndclass, 0, sizeof(wndclass)); memset(&wndclass, 0, sizeof(wndclass));
wndclass.cbSize = sizeof(wndclass); wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_OWNDC; wndclass.style = CS_OWNDC | CS_DBLCLKS;
wndclass.lpfnWndProc = (WNDPROC)MainWndProc; wndclass.lpfnWndProc = (WNDPROC)MainWndProc;
wndclass.hInstance = hInstance; wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIcon = LoadIcon(hInstance, szAppName);
@ -1248,6 +1319,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
cur = pending_resize.image; cur = pending_resize.image;
pending_resize.image = NULL; pending_resize.image = NULL;
} }
cur_filename = strdup(filename);
wx = w; wx = w;
wy = h; wy = h;
@ -1267,12 +1339,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
for(;;) { for(;;) {
// if we're not currently resizing, start a resize // if we're not currently resizing, start a resize
if (qs.w && pending_resize.size.w == 0) { if (qs.w && pending_resize.size.w == 0) {
if ((qs.w == cur->x && qs.h >= cur->y) || (qs.h == cur->y && qs.w >= cur->x)) { if (cur_is_current() && ((qs.w == cur->x && qs.h >= cur->y) || (qs.h == cur->y && qs.w >= cur->x))) {
// no resize necessary, just a variant of the current shape // no resize necessary, just a variant of the current shape
MoveWindow(win, qs.x,qs.y,qs.w,qs.h, TRUE); MoveWindow(win, qs.x,qs.y,qs.w,qs.h, TRUE);
InvalidateRect(win, NULL, FALSE); InvalidateRect(win, NULL, FALSE);
} else { } else {
o("Enqueueing resize\n"); o(("Enqueueing resize\n"));
pending_resize.size = qs; pending_resize.size = qs;
queue_resize(qs.w, qs.h, source_c, FALSE); queue_resize(qs.w, qs.h, source_c, FALSE);
} }
@ -1286,9 +1358,11 @@ o("Enqueueing resize\n");
if (!pending_resize.image) { if (!pending_resize.image) {
Sleep(10); Sleep(10);
} else { } else {
o("Finished resize\n"); o(("Finished resize\n"));
imfree(cur); imfree(cur);
cur = pending_resize.image; cur = pending_resize.image;
cur_filename = pending_resize.filename;
pending_resize.filename = NULL;
SetWindowPos(hWnd,NULL,pending_resize.size.x, pending_resize.size.y, pending_resize.size.w, pending_resize.size.h, SWP_NOZORDER); SetWindowPos(hWnd,NULL,pending_resize.size.x, pending_resize.size.y, pending_resize.size.w, pending_resize.size.h, SWP_NOZORDER);
barrier(); barrier();
pending_resize.size.w = 0; pending_resize.size.w = 0;

View File

@ -1,10 +1,11 @@
RELEASE NOTES Version 0.54 ()
* resizing with ctrl- and ctrl+ correctly sets the actual-size-mode
Version 0.53 (2007-06-25)
* added Open File dialog if you run without a commandline
* ctrl-O lets you open an arbitrary file
* double-click, alt-enter to toggle actual-size vs. fullscreen
* changing images doesn't change window size except in actual-size mode
Version 0.53 Version 0.52 (2007-06-25)
- added Open File dialog if you run without a commandline * fixed a bug with resizing
- ctrl-O lets you open an arbitrary file
Version 0.52
- fixed a bug with resizing

9
notes_header.wiki Normal file
View File

@ -0,0 +1,9 @@
#summary Release notes for all versions
= Release =
The current version is 0.53.
= Release Notes =

View File

@ -51,3 +51,7 @@ Multiple images:
UNINSTALLING UNINSTALLING
Delete it. Delete it.
RELEASE NOTES

View File

@ -1,10 +1,52 @@
@call version.bat +@echo off
@mkdir ..\stb_imv call version.bat
@copy vc6\release\stb_imv.exe ..\stb_imv\imv.exe
@copy readme_binary.txt ..\stb_imv\readme.txt rem # Update ReleaseNotes on wiki
@cd ..
@del stb_imv-%VERSION%.zip cd wiki
@zip -r stb_imv-%VERSION%.zip stb_imv svn up
@del /q stb_imv\* copy /b /y ..\notes_header.wiki+..\notes.txt ReleaseNotes.wiki
@rmdir stb_imv svn ci -m "release %VERSION%"
@cd stb-imv cd ..
rem # Make release directory
mkdir ..\stb_imv
copy vc6\release\stb_imv.exe ..\stb_imv\imv.exe
copy readme_binary.txt+notes.txt ..\stb_imv\readme.txt
rem # Make tarball directory
mkdir ..\stb_imv_src-%VERSION%
mkdir ..\stb_imv_src-%VERSION%\vc6
copy vc6\stb_imv.ds? ..\stb_imv_src-%VERSION%\vc6
copy *.c ..\stb_imv_src-%VERSION%
copy *.h ..\stb_imv_src-%VERSION%
copy COPYING ..\stb_imv_src-%VERSION%
copy *.txt ..\stb_imv_src-%VERSION%
copy *.bat ..\stb_imv_src-%VERSION%
rem #
cd ..
rem # zip release directory
del stb_imv-%VERSION%.zip
zip -r stb_imv-%VERSION%.zip stb_imv
del /q stb_imv\*
rmdir stb_imv
rem # zip tarball directory
del stb_imv_src-%VERSION%.zip
zip -r stb_imv_src-%VERSION%.zip stb_imv_src-%VERSION%
del /s /q stb_imv_src-%VERSION%\*
rmdir stb_imv_src-%VERSION%\vc6
rmdir stb_imv_src-%VERSION%
rem # upload
call upload.bat
cd stb-imv

View File

@ -1,16 +0,0 @@
@call version
@mkdir ..\stb_imv_src-%VERSION%
@mkdir ..\stb_imv_src-%VERSION%\vc6
@copy vc6\stb_imv.ds? ..\stb_imv_src-%VERSION%\vc6
@copy *.c ..\stb_imv_src-%VERSION%
@copy *.h ..\stb_imv_src-%VERSION%
@copy COPYING ..\stb_imv_src-%VERSION%
@copy *.txt ..\stb_imv_src-%VERSION%
@copy *.bat ..\stb_imv_src-%VERSION%
@cd ..
@del stb_imv_src-%VERSION%.zip
@zip -r stb_imv_src-%VERSION%.zip stb_imv_src-%VERSION%
@del /s /q stb_imv_src-%VERSION%\*
@rmdir stb_imv_src-%VERSION%\vc6
@rmdir stb_imv_src-%VERSION%
@cd stb-imv

View File

@ -1 +1 @@
set VERSION=0.52 set VERSION=0.53