Newer
Older
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051
7052
7053
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072
7073
7074
7075
7076
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
7198
7199
7200
7201
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776
7777
7778
7779
7780
7781
7782
7783
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
7851
7852
7853
7854
7855
7856
7857
7858
7859
7860
7861
7862
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
7928
7929
7930
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967
7968
7969
7970
7971
7972
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982
7983
7984
7985
7986
7987
7988
7989
7990
7991
7992
7993
7994
7995
7996
7997
7998
7999
8000
//
//! \name Plugins
//@{
//---------------------------
#ifdef cimgdisplay_plugin
#include cimgdisplay_plugin
#endif
#ifdef cimgdisplay_plugin1
#include cimgdisplay_plugin1
#endif
#ifdef cimgdisplay_plugin2
#include cimgdisplay_plugin2
#endif
#ifdef cimgdisplay_plugin3
#include cimgdisplay_plugin3
#endif
#ifdef cimgdisplay_plugin4
#include cimgdisplay_plugin4
#endif
#ifdef cimgdisplay_plugin5
#include cimgdisplay_plugin5
#endif
#ifdef cimgdisplay_plugin6
#include cimgdisplay_plugin6
#endif
#ifdef cimgdisplay_plugin7
#include cimgdisplay_plugin7
#endif
#ifdef cimgdisplay_plugin8
#include cimgdisplay_plugin8
#endif
//@}
//--------------------------------------------------------
//
//! \name Constructors / Destructor / Instance Management
//@{
//--------------------------------------------------------
//! Destructor.
/**
\note If the associated window is visible on the screen, it is closed by the call to the destructor.
**/
~CImgDisplay() {
assign();
delete[] _keys;
delete[] _released_keys;
}
//! Construct an empty display.
/**
\note Constructing an empty CImgDisplay instance does not make a window appearing on the screen, until
display of valid data is performed.
\par Example
\code
CImgDisplay disp; // Does actually nothing.
...
disp.display(img); // Construct new window and display image in it.
\endcode
**/
CImgDisplay():
_width(0),_height(0),_normalization(0),
_min(0),_max(0),
_is_fullscreen(false),
_title(0),
_window_width(0),_window_height(0),_button(0),
_keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
assign();
}
//! Construct a display with specified dimensions.
/** \param width Window width.
\param height Window height.
\param title Window title.
\param normalization Normalization type
(<tt>0</tt>=none, <tt>1</tt>=always, <tt>2</tt>=once, <tt>3</tt>=pixel type-dependent, see normalization()).
\param is_fullscreen Tells if fullscreen mode is enabled.
\param is_closed Tells if associated window is initially visible or not.
\note A black background is initially displayed on the associated window.
**/
CImgDisplay(const unsigned int width, const unsigned int height,
const char *const title=0, const unsigned int normalization=3,
const bool is_fullscreen=false, const bool is_closed=false):
_width(0),_height(0),_normalization(0),
_min(0),_max(0),
_is_fullscreen(false),
_title(0),
_window_width(0),_window_height(0),_button(0),
_keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
assign(width,height,title,normalization,is_fullscreen,is_closed);
}
//! Construct a display from an image.
/** \param img Image used as a model to create the window.
\param title Window title.
\param normalization Normalization type
(<tt>0</tt>=none, <tt>1</tt>=always, <tt>2</tt>=once, <tt>3</tt>=pixel type-dependent, see normalization()).
\param is_fullscreen Tells if fullscreen mode is enabled.
\param is_closed Tells if associated window is initially visible or not.
\note The pixels of the input image are initially displayed on the associated window.
**/
template<typename T>
explicit CImgDisplay(const CImg<T>& img,
const char *const title=0, const unsigned int normalization=3,
const bool is_fullscreen=false, const bool is_closed=false):
_width(0),_height(0),_normalization(0),
_min(0),_max(0),
_is_fullscreen(false),
_title(0),
_window_width(0),_window_height(0),_button(0),
_keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
assign(img,title,normalization,is_fullscreen,is_closed);
}
//! Construct a display from an image list.
/** \param list The images list to display.
\param title Window title.
\param normalization Normalization type
(<tt>0</tt>=none, <tt>1</tt>=always, <tt>2</tt>=once, <tt>3</tt>=pixel type-dependent, see normalization()).
\param is_fullscreen Tells if fullscreen mode is enabled.
\param is_closed Tells if associated window is initially visible or not.
\note All images of the list, appended along the X-axis, are initially displayed on the associated window.
**/
template<typename T>
explicit CImgDisplay(const CImgList<T>& list,
const char *const title=0, const unsigned int normalization=3,
const bool is_fullscreen=false, const bool is_closed=false):
_width(0),_height(0),_normalization(0),
_min(0),_max(0),
_is_fullscreen(false),
_title(0),
_window_width(0),_window_height(0),_button(0),
_keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
assign(list,title,normalization,is_fullscreen,is_closed);
}
//! Construct a display as a copy of an existing one.
/**
\param disp Display instance to copy.
\note The pixel buffer of the input window is initially displayed on the associated window.
**/
CImgDisplay(const CImgDisplay& disp):
_width(0),_height(0),_normalization(0),
_min(0),_max(0),
_is_fullscreen(false),
_title(0),
_window_width(0),_window_height(0),_button(0),
_keys(new unsigned int[128]),_released_keys(new unsigned int[128]),
_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),_wheel(0),
_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) {
assign(disp);
}
//! Take a screenshot.
/**
\param[out] img Output screenshot. Can be empty on input
**/
template<typename T>
static void screenshot(CImg<T>& img) {
return screenshot(0,0,cimg::type<int>::max(),cimg::type<int>::max(),img);
}
#if cimg_display==0
static void _no_display_exception() {
throw CImgDisplayException("CImgDisplay(): No display available.");
}
//! Destructor - Empty constructor \inplace.
/**
\note Replace the current instance by an empty display.
**/
CImgDisplay& assign() {
return flush();
}
//! Construct a display with specified dimensions \inplace.
/**
**/
CImgDisplay& assign(const unsigned int width, const unsigned int height,
const char *const title=0, const unsigned int normalization=3,
const bool is_fullscreen=false, const bool is_closed=false) {
cimg::unused(width,height,title,normalization,is_fullscreen,is_closed);
_no_display_exception();
return assign();
}
//! Construct a display from an image \inplace.
/**
**/
template<typename T>
CImgDisplay& assign(const CImg<T>& img,
const char *const title=0, const unsigned int normalization=3,
const bool is_fullscreen=false, const bool is_closed=false) {
_no_display_exception();
return assign(img._width,img._height,title,normalization,is_fullscreen,is_closed);
}
//! Construct a display from an image list \inplace.
/**
**/
template<typename T>
CImgDisplay& assign(const CImgList<T>& list,
const char *const title=0, const unsigned int normalization=3,
const bool is_fullscreen=false, const bool is_closed=false) {
_no_display_exception();
return assign(list._width,list._width,title,normalization,is_fullscreen,is_closed);
}
//! Construct a display as a copy of another one \inplace.
/**
**/
CImgDisplay& assign(const CImgDisplay &disp) {
_no_display_exception();
return assign(disp._width,disp._height);
}
#endif
//! Return a reference to an empty display.
/**
\note Can be useful for writing function prototypes where one of the argument (of type CImgDisplay&)
must have a default value.
\par Example
\code
void foo(CImgDisplay& disp=CImgDisplay::empty());
\endcode
**/
static CImgDisplay& empty() {
static CImgDisplay _empty;
return _empty.assign();
}
//! Return a reference to an empty display \const.
static const CImgDisplay& const_empty() {
static const CImgDisplay _empty;
return _empty;
}
#define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false), \
CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz,
const int dmin, const int dmax,const bool return_y) {
const unsigned int _nw = dx + (dz>1?dz:0), _nh = dy + (dz>1?dz:0);
unsigned int nw = _nw?_nw:1, nh = _nh?_nh:1;
const unsigned int
sw = (unsigned int)CImgDisplay::screen_width(),
sh = (unsigned int)CImgDisplay::screen_height(),
mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
if (nw<mw) nw = mw;
if (nh<mh) nh = mh;
return return_y?nh:nw;
}
//@}
//------------------------------------------
//
//! \name Overloaded Operators
//@{
//------------------------------------------
//! Display image on associated window.
/**
\note <tt>disp = img</tt> is equivalent to <tt>disp.display(img)</tt>.
**/
template<typename t>
CImgDisplay& operator=(const CImg<t>& img) {
return display(img);
}
//! Display list of images on associated window.
/**
\note <tt>disp = list</tt> is equivalent to <tt>disp.display(list)</tt>.
**/
template<typename t>
CImgDisplay& operator=(const CImgList<t>& list) {
return display(list);
}
//! Construct a display as a copy of another one \inplace.
/**
\note Equivalent to assign(const CImgDisplay&).
**/
CImgDisplay& operator=(const CImgDisplay& disp) {
return assign(disp);
}
//! Return \c false if display is empty, \c true otherwise.
/**
\note <tt>if (disp) { ... }</tt> is equivalent to <tt>if (!disp.is_empty()) { ... }</tt>.
**/
operator bool() const {
return !is_empty();
}
//@}
//------------------------------------------
//
//! \name Instance Checking
//@{
//------------------------------------------
//! Return \c true if display is empty, \c false otherwise.
/**
**/
bool is_empty() const {
return !(_width && _height);
}
//! Return \c true if display is closed (i.e. not visible on the screen), \c false otherwise.
/**
\note
- When a user physically closes the associated window, the display is set to closed.
- A closed display is not destroyed. Its associated window can be show again on the screen using show().
**/
bool is_closed() const {
return _is_closed;
}
//! Return \c true if associated window has been resized on the screen, \c false otherwise.
/**
**/
bool is_resized() const {
return _is_resized;
}
//! Return \c true if associated window has been moved on the screen, \c false otherwise.
/**
**/
bool is_moved() const {
return _is_moved;
}
//! Return \c true if any event has occured on the associated window, \c false otherwise.
/**
**/
bool is_event() const {
return _is_event;
}
//! Return \c true if current display is in fullscreen mode, \c false otherwise.
/**
**/
bool is_fullscreen() const {
return _is_fullscreen;
}
//! Return \c true if any key is being pressed on the associated window, \c false otherwise.
/**
\note The methods below do the same only for specific keys.
**/
bool is_key() const {
return _is_keyESC || _is_keyF1 || _is_keyF2 || _is_keyF3 ||
_is_keyF4 || _is_keyF5 || _is_keyF6 || _is_keyF7 ||
_is_keyF8 || _is_keyF9 || _is_keyF10 || _is_keyF11 ||
_is_keyF12 || _is_keyPAUSE || _is_key1 || _is_key2 ||
_is_key3 || _is_key4 || _is_key5 || _is_key6 ||
_is_key7 || _is_key8 || _is_key9 || _is_key0 ||
_is_keyBACKSPACE || _is_keyINSERT || _is_keyHOME ||
_is_keyPAGEUP || _is_keyTAB || _is_keyQ || _is_keyW ||
_is_keyE || _is_keyR || _is_keyT || _is_keyY ||
_is_keyU || _is_keyI || _is_keyO || _is_keyP ||
_is_keyDELETE || _is_keyEND || _is_keyPAGEDOWN ||
_is_keyCAPSLOCK || _is_keyA || _is_keyS || _is_keyD ||
_is_keyF || _is_keyG || _is_keyH || _is_keyJ ||
_is_keyK || _is_keyL || _is_keyENTER ||
_is_keySHIFTLEFT || _is_keyZ || _is_keyX || _is_keyC ||
_is_keyV || _is_keyB || _is_keyN || _is_keyM ||
_is_keySHIFTRIGHT || _is_keyARROWUP || _is_keyCTRLLEFT ||
_is_keyAPPLEFT || _is_keyALT || _is_keySPACE || _is_keyALTGR ||
_is_keyAPPRIGHT || _is_keyMENU || _is_keyCTRLRIGHT ||
_is_keyARROWLEFT || _is_keyARROWDOWN || _is_keyARROWRIGHT ||
_is_keyPAD0 || _is_keyPAD1 || _is_keyPAD2 ||
_is_keyPAD3 || _is_keyPAD4 || _is_keyPAD5 ||
_is_keyPAD6 || _is_keyPAD7 || _is_keyPAD8 ||
_is_keyPAD9 || _is_keyPADADD || _is_keyPADSUB ||
_is_keyPADMUL || _is_keyPADDIV;
}
//! Return \c true if key specified by given keycode is being pressed on the associated window, \c false otherwise.
/**
\param keycode Keycode to test.
\note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure
your code stay portable (see cimg::keyESC).
\par Example
\code
CImgDisplay disp(400,400);
while (!disp.is_closed()) {
if (disp.key(cimg::keyTAB)) { ... } // Equivalent to 'if (disp.is_keyTAB())'.
disp.wait();
}
\endcode
**/
bool is_key(const unsigned int keycode) const {
#define _cimg_iskey_test(k) if (keycode==cimg::key##k) return _is_key##k;
_cimg_iskey_test(ESC); _cimg_iskey_test(F1); _cimg_iskey_test(F2); _cimg_iskey_test(F3);
_cimg_iskey_test(F4); _cimg_iskey_test(F5); _cimg_iskey_test(F6); _cimg_iskey_test(F7);
_cimg_iskey_test(F8); _cimg_iskey_test(F9); _cimg_iskey_test(F10); _cimg_iskey_test(F11);
_cimg_iskey_test(F12); _cimg_iskey_test(PAUSE); _cimg_iskey_test(1); _cimg_iskey_test(2);
_cimg_iskey_test(3); _cimg_iskey_test(4); _cimg_iskey_test(5); _cimg_iskey_test(6);
_cimg_iskey_test(7); _cimg_iskey_test(8); _cimg_iskey_test(9); _cimg_iskey_test(0);
_cimg_iskey_test(BACKSPACE); _cimg_iskey_test(INSERT); _cimg_iskey_test(HOME);
_cimg_iskey_test(PAGEUP); _cimg_iskey_test(TAB); _cimg_iskey_test(Q); _cimg_iskey_test(W);
_cimg_iskey_test(E); _cimg_iskey_test(R); _cimg_iskey_test(T); _cimg_iskey_test(Y);
_cimg_iskey_test(U); _cimg_iskey_test(I); _cimg_iskey_test(O); _cimg_iskey_test(P);
_cimg_iskey_test(DELETE); _cimg_iskey_test(END); _cimg_iskey_test(PAGEDOWN);
_cimg_iskey_test(CAPSLOCK); _cimg_iskey_test(A); _cimg_iskey_test(S); _cimg_iskey_test(D);
_cimg_iskey_test(F); _cimg_iskey_test(G); _cimg_iskey_test(H); _cimg_iskey_test(J);
_cimg_iskey_test(K); _cimg_iskey_test(L); _cimg_iskey_test(ENTER);
_cimg_iskey_test(SHIFTLEFT); _cimg_iskey_test(Z); _cimg_iskey_test(X); _cimg_iskey_test(C);
_cimg_iskey_test(V); _cimg_iskey_test(B); _cimg_iskey_test(N); _cimg_iskey_test(M);
_cimg_iskey_test(SHIFTRIGHT); _cimg_iskey_test(ARROWUP); _cimg_iskey_test(CTRLLEFT);
_cimg_iskey_test(APPLEFT); _cimg_iskey_test(ALT); _cimg_iskey_test(SPACE); _cimg_iskey_test(ALTGR);
_cimg_iskey_test(APPRIGHT); _cimg_iskey_test(MENU); _cimg_iskey_test(CTRLRIGHT);
_cimg_iskey_test(ARROWLEFT); _cimg_iskey_test(ARROWDOWN); _cimg_iskey_test(ARROWRIGHT);
_cimg_iskey_test(PAD0); _cimg_iskey_test(PAD1); _cimg_iskey_test(PAD2);
_cimg_iskey_test(PAD3); _cimg_iskey_test(PAD4); _cimg_iskey_test(PAD5);
_cimg_iskey_test(PAD6); _cimg_iskey_test(PAD7); _cimg_iskey_test(PAD8);
_cimg_iskey_test(PAD9); _cimg_iskey_test(PADADD); _cimg_iskey_test(PADSUB);
_cimg_iskey_test(PADMUL); _cimg_iskey_test(PADDIV);
return false;
}
//! Return \c true if key specified by given keycode is being pressed on the associated window, \c false otherwise.
/**
\param keycode C-string containing the keycode label of the key to test.
\note Use it when the key you want to test can be dynamically set by the user.
\par Example
\code
CImgDisplay disp(400,400);
const char *const keycode = "TAB";
while (!disp.is_closed()) {
if (disp.is_key(keycode)) { ... } // Equivalent to 'if (disp.is_keyTAB())'.
disp.wait();
}
\endcode
**/
bool& is_key(const char *const keycode) {
static bool f = false;
f = false;
#define _cimg_iskey_test2(k) if (!cimg::strcasecmp(keycode,#k)) return _is_key##k;
_cimg_iskey_test2(ESC); _cimg_iskey_test2(F1); _cimg_iskey_test2(F2); _cimg_iskey_test2(F3);
_cimg_iskey_test2(F4); _cimg_iskey_test2(F5); _cimg_iskey_test2(F6); _cimg_iskey_test2(F7);
_cimg_iskey_test2(F8); _cimg_iskey_test2(F9); _cimg_iskey_test2(F10); _cimg_iskey_test2(F11);
_cimg_iskey_test2(F12); _cimg_iskey_test2(PAUSE); _cimg_iskey_test2(1); _cimg_iskey_test2(2);
_cimg_iskey_test2(3); _cimg_iskey_test2(4); _cimg_iskey_test2(5); _cimg_iskey_test2(6);
_cimg_iskey_test2(7); _cimg_iskey_test2(8); _cimg_iskey_test2(9); _cimg_iskey_test2(0);
_cimg_iskey_test2(BACKSPACE); _cimg_iskey_test2(INSERT); _cimg_iskey_test2(HOME);
_cimg_iskey_test2(PAGEUP); _cimg_iskey_test2(TAB); _cimg_iskey_test2(Q); _cimg_iskey_test2(W);
_cimg_iskey_test2(E); _cimg_iskey_test2(R); _cimg_iskey_test2(T); _cimg_iskey_test2(Y);
_cimg_iskey_test2(U); _cimg_iskey_test2(I); _cimg_iskey_test2(O); _cimg_iskey_test2(P);
_cimg_iskey_test2(DELETE); _cimg_iskey_test2(END); _cimg_iskey_test2(PAGEDOWN);
_cimg_iskey_test2(CAPSLOCK); _cimg_iskey_test2(A); _cimg_iskey_test2(S); _cimg_iskey_test2(D);
_cimg_iskey_test2(F); _cimg_iskey_test2(G); _cimg_iskey_test2(H); _cimg_iskey_test2(J);
_cimg_iskey_test2(K); _cimg_iskey_test2(L); _cimg_iskey_test2(ENTER);
_cimg_iskey_test2(SHIFTLEFT); _cimg_iskey_test2(Z); _cimg_iskey_test2(X); _cimg_iskey_test2(C);
_cimg_iskey_test2(V); _cimg_iskey_test2(B); _cimg_iskey_test2(N); _cimg_iskey_test2(M);
_cimg_iskey_test2(SHIFTRIGHT); _cimg_iskey_test2(ARROWUP); _cimg_iskey_test2(CTRLLEFT);
_cimg_iskey_test2(APPLEFT); _cimg_iskey_test2(ALT); _cimg_iskey_test2(SPACE); _cimg_iskey_test2(ALTGR);
_cimg_iskey_test2(APPRIGHT); _cimg_iskey_test2(MENU); _cimg_iskey_test2(CTRLRIGHT);
_cimg_iskey_test2(ARROWLEFT); _cimg_iskey_test2(ARROWDOWN); _cimg_iskey_test2(ARROWRIGHT);
_cimg_iskey_test2(PAD0); _cimg_iskey_test2(PAD1); _cimg_iskey_test2(PAD2);
_cimg_iskey_test2(PAD3); _cimg_iskey_test2(PAD4); _cimg_iskey_test2(PAD5);
_cimg_iskey_test2(PAD6); _cimg_iskey_test2(PAD7); _cimg_iskey_test2(PAD8);
_cimg_iskey_test2(PAD9); _cimg_iskey_test2(PADADD); _cimg_iskey_test2(PADSUB);
_cimg_iskey_test2(PADMUL); _cimg_iskey_test2(PADDIV);
return f;
}
//! Return \c true if specified key sequence has been typed on the associated window, \c false otherwise.
/**
\param keycodes_sequence Buffer of keycodes to test.
\param length Number of keys in the \c keycodes_sequence buffer.
\param remove_sequence Tells if the key sequence must be removed from the key history, if found.
\note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure
your code stay portable (see cimg::keyESC).
\par Example
\code
CImgDisplay disp(400,400);
const unsigned int key_seq[] = { cimg::keyCTRLLEFT, cimg::keyD };
while (!disp.is_closed()) {
if (disp.is_key_sequence(key_seq,2)) { ... } // Test for the 'CTRL+D' keyboard event.
disp.wait();
}
\endcode
**/
bool is_key_sequence(const unsigned int *const keycodes_sequence, const unsigned int length,
const bool remove_sequence=false) {
if (keycodes_sequence && length) {
const unsigned int
*const ps_end = keycodes_sequence + length - 1,
*const pk_end = (unsigned int*)_keys + 1 + 128 - length,
k = *ps_end;
for (unsigned int *pk = (unsigned int*)_keys; pk<pk_end; ) {
if (*(pk++)==k) {
bool res = true;
const unsigned int *ps = ps_end, *pk2 = pk;
for (unsigned int i = 1; i<length; ++i) res = (*(--ps)==*(pk2++));
if (res) {
if (remove_sequence) std::memset((void*)(pk - 1),0,sizeof(unsigned int)*length);
return true;
}
}
}
}
return false;
}
#define _cimg_iskey_def(k) \
bool is_key##k() const { \
return _is_key##k; \
}
//! Return \c true if the \c ESC key is being pressed on the associated window, \c false otherwise.
/**
\note Similar methods exist for all keys managed by \CImg (see cimg::keyESC).
**/
_cimg_iskey_def(ESC); _cimg_iskey_def(F1); _cimg_iskey_def(F2); _cimg_iskey_def(F3);
_cimg_iskey_def(F4); _cimg_iskey_def(F5); _cimg_iskey_def(F6); _cimg_iskey_def(F7);
_cimg_iskey_def(F8); _cimg_iskey_def(F9); _cimg_iskey_def(F10); _cimg_iskey_def(F11);
_cimg_iskey_def(F12); _cimg_iskey_def(PAUSE); _cimg_iskey_def(1); _cimg_iskey_def(2);
_cimg_iskey_def(3); _cimg_iskey_def(4); _cimg_iskey_def(5); _cimg_iskey_def(6);
_cimg_iskey_def(7); _cimg_iskey_def(8); _cimg_iskey_def(9); _cimg_iskey_def(0);
_cimg_iskey_def(BACKSPACE); _cimg_iskey_def(INSERT); _cimg_iskey_def(HOME);
_cimg_iskey_def(PAGEUP); _cimg_iskey_def(TAB); _cimg_iskey_def(Q); _cimg_iskey_def(W);
_cimg_iskey_def(E); _cimg_iskey_def(R); _cimg_iskey_def(T); _cimg_iskey_def(Y);
_cimg_iskey_def(U); _cimg_iskey_def(I); _cimg_iskey_def(O); _cimg_iskey_def(P);
_cimg_iskey_def(DELETE); _cimg_iskey_def(END); _cimg_iskey_def(PAGEDOWN);
_cimg_iskey_def(CAPSLOCK); _cimg_iskey_def(A); _cimg_iskey_def(S); _cimg_iskey_def(D);
_cimg_iskey_def(F); _cimg_iskey_def(G); _cimg_iskey_def(H); _cimg_iskey_def(J);
_cimg_iskey_def(K); _cimg_iskey_def(L); _cimg_iskey_def(ENTER);
_cimg_iskey_def(SHIFTLEFT); _cimg_iskey_def(Z); _cimg_iskey_def(X); _cimg_iskey_def(C);
_cimg_iskey_def(V); _cimg_iskey_def(B); _cimg_iskey_def(N); _cimg_iskey_def(M);
_cimg_iskey_def(SHIFTRIGHT); _cimg_iskey_def(ARROWUP); _cimg_iskey_def(CTRLLEFT);
_cimg_iskey_def(APPLEFT); _cimg_iskey_def(ALT); _cimg_iskey_def(SPACE); _cimg_iskey_def(ALTGR);
_cimg_iskey_def(APPRIGHT); _cimg_iskey_def(MENU); _cimg_iskey_def(CTRLRIGHT);
_cimg_iskey_def(ARROWLEFT); _cimg_iskey_def(ARROWDOWN); _cimg_iskey_def(ARROWRIGHT);
_cimg_iskey_def(PAD0); _cimg_iskey_def(PAD1); _cimg_iskey_def(PAD2);
_cimg_iskey_def(PAD3); _cimg_iskey_def(PAD4); _cimg_iskey_def(PAD5);
_cimg_iskey_def(PAD6); _cimg_iskey_def(PAD7); _cimg_iskey_def(PAD8);
_cimg_iskey_def(PAD9); _cimg_iskey_def(PADADD); _cimg_iskey_def(PADSUB);
_cimg_iskey_def(PADMUL); _cimg_iskey_def(PADDIV);
//@}
//------------------------------------------
//
//! \name Instance Characteristics
//@{
//------------------------------------------
#if cimg_display==0
//! Return width of the screen (current resolution along the X-axis).
/**
**/
static int screen_width() {
_no_display_exception();
return 0;
}
//! Return height of the screen (current resolution along the Y-axis).
/**
**/
static int screen_height() {
_no_display_exception();
return 0;
}
#endif
//! Return display width.
/**
\note The width of the display (i.e. the width of the pixel data buffer associated to the CImgDisplay instance)
may be different from the actual width of the associated window.
**/
int width() const {
return (int)_width;
}
//! Return display height.
/**
\note The height of the display (i.e. the height of the pixel data buffer associated to the CImgDisplay instance)
may be different from the actual height of the associated window.
**/
int height() const {
return (int)_height;
}
//! Return normalization type of the display.
/**
The normalization type tells about how the values of an input image are normalized by the CImgDisplay to be
correctly displayed. The range of values for pixels displayed on screen is <tt>[0,255]</tt>.
If the range of values of the data to display is different, a normalization may be required for displaying
the data in a correct way. The normalization type can be one of:
- \c 0: Value normalization is disabled. It is then assumed that all input data to be displayed by the
CImgDisplay instance have values in range <tt>[0,255]</tt>.
- \c 1: Value normalization is always performed (this is the default behavior).
Before displaying an input image, its values will be (virtually) stretched
in range <tt>[0,255]</tt>, so that the contrast of the displayed pixels will be maximum.
Use this mode for images whose minimum and maximum values are not prescribed to known values
(e.g. float-valued images).
Note that when normalized versions of images are computed for display purposes, the actual values of these
images are not modified.
- \c 2: Value normalization is performed once (on the first image display), then the same normalization
coefficients are kept for next displayed frames.
- \c 3: Value normalization depends on the pixel type of the data to display. For integer pixel types,
the normalization is done regarding the minimum/maximum values of the type (no normalization occurs then
for <tt>unsigned char</tt>).
For float-valued pixel types, the normalization is done regarding the minimum/maximum value of the image
data instead.
**/
unsigned int normalization() const {
return _normalization;
}
//! Return title of the associated window as a C-string.
/**
\note Window title may be not visible, depending on the used window manager or if the current display is
in fullscreen mode.
**/
const char *title() const {
return _title?_title:"";
}
//! Return width of the associated window.
/**
\note The width of the display (i.e. the width of the pixel data buffer associated to the CImgDisplay instance)
may be different from the actual width of the associated window.
**/
int window_width() const {
return (int)_window_width;
}
//! Return height of the associated window.
/**
\note The height of the display (i.e. the height of the pixel data buffer associated to the CImgDisplay instance)
may be different from the actual height of the associated window.
**/
int window_height() const {
return (int)_window_height;
}
//! Return X-coordinate of the associated window.
/**
\note The returned coordinate corresponds to the location of the upper-left corner of the associated window.
**/
int window_x() const {
return _window_x;
}
//! Return Y-coordinate of the associated window.
/**
\note The returned coordinate corresponds to the location of the upper-left corner of the associated window.
**/
int window_y() const {
return _window_y;
}
//! Return X-coordinate of the mouse pointer.
/**
\note
- If the mouse pointer is outside window area, \c -1 is returned.
- Otherwise, the returned value is in the range [0,width()-1].
**/
int mouse_x() const {
return _mouse_x;
}
//! Return Y-coordinate of the mouse pointer.
/**
\note
- If the mouse pointer is outside window area, \c -1 is returned.
- Otherwise, the returned value is in the range [0,height()-1].
**/
int mouse_y() const {
return _mouse_y;
}
//! Return current state of the mouse buttons.
/**
\note Three mouse buttons can be managed. If one button is pressed, its corresponding bit in the returned
value is set:
- bit \c 0 (value \c 0x1): State of the left mouse button.
- bit \c 1 (value \c 0x2): State of the right mouse button.
- bit \c 2 (value \c 0x4): State of the middle mouse button.
Several bits can be activated if more than one button are pressed at the same time.
\par Example
\code
CImgDisplay disp(400,400);
while (!disp.is_closed()) {
if (disp.button()&1) { // Left button clicked.
...
}
if (disp.button()&2) { // Right button clicked.
...
}
if (disp.button()&4) { // Middle button clicked.
...
}
disp.wait();
}
\endcode
**/
unsigned int button() const {
return _button;
}
//! Return current state of the mouse wheel.
/**
\note
- The returned value can be positive or negative depending on whether the mouse wheel has been scrolled
forward or backward.
- Scrolling the wheel forward add \c 1 to the wheel value.
- Scrolling the wheel backward substract \c 1 to the wheel value.
- The returned value cumulates the number of forward of backward scrolls since the creation of the display,
or since the last reset of the wheel value (using set_wheel()). It is strongly recommended to quickly reset
the wheel counter when an action has been performed regarding the current wheel value.
Otherwise, the returned wheel value may be for instance \c 0 despite the fact that many scrolls have been done
(as many in forward as in backward directions).
\par Example
\code
CImgDisplay disp(400,400);
while (!disp.is_closed()) {
if (disp.wheel()) {
int counter = disp.wheel(); // Read the state of the mouse wheel.
... // Do what you want with 'counter'.
disp.set_wheel(); // Reset the wheel value to 0.
}
disp.wait();
}
\endcode
**/
int wheel() const {
return _wheel;
}
//! Return one entry from the pressed keys history.
/**
\param pos Indice to read from the pressed keys history (indice \c 0 corresponds to latest entry).
\return Keycode of a pressed key or \c 0 for a released key.
\note
- Each CImgDisplay stores a history of the pressed keys in a buffer of size \c 128. When a new key is pressed,
its keycode is stored in the pressed keys history. When a key is released, \c 0 is put instead.
This means that up to the 64 last pressed keys may be read from the pressed keys history.
When a new value is stored, the pressed keys history is shifted so that the latest entry is always
stored at position \c 0.
- Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure
your code stay portable (see cimg::keyESC).
**/
unsigned int key(const unsigned int pos=0) const {
return pos<128?_keys[pos]:0;
}
//! Return one entry from the released keys history.
/**
\param pos Indice to read from the released keys history (indice \c 0 corresponds to latest entry).
\return Keycode of a released key or \c 0 for a pressed key.
\note
- Each CImgDisplay stores a history of the released keys in a buffer of size \c 128. When a new key is released,
its keycode is stored in the pressed keys history. When a key is pressed, \c 0 is put instead.
This means that up to the 64 last released keys may be read from the released keys history.
When a new value is stored, the released keys history is shifted so that the latest entry is always
stored at position \c 0.
- Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure
your code stay portable (see cimg::keyESC).
**/
unsigned int released_key(const unsigned int pos=0) const {
return pos<128?_released_keys[pos]:0;
}
//! Return keycode corresponding to the specified string.
/**
\note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure
your code stay portable (see cimg::keyESC).
\par Example
\code
const unsigned int keyTAB = CImgDisplay::keycode("TAB"); // Return cimg::keyTAB.
\endcode
**/
static unsigned int keycode(const char *const keycode) {
#define _cimg_keycode(k) if (!cimg::strcasecmp(keycode,#k)) return cimg::key##k;
_cimg_keycode(ESC); _cimg_keycode(F1); _cimg_keycode(F2); _cimg_keycode(F3);
_cimg_keycode(F4); _cimg_keycode(F5); _cimg_keycode(F6); _cimg_keycode(F7);
_cimg_keycode(F8); _cimg_keycode(F9); _cimg_keycode(F10); _cimg_keycode(F11);
_cimg_keycode(F12); _cimg_keycode(PAUSE); _cimg_keycode(1); _cimg_keycode(2);
_cimg_keycode(3); _cimg_keycode(4); _cimg_keycode(5); _cimg_keycode(6);
_cimg_keycode(7); _cimg_keycode(8); _cimg_keycode(9); _cimg_keycode(0);
_cimg_keycode(BACKSPACE); _cimg_keycode(INSERT); _cimg_keycode(HOME);
_cimg_keycode(PAGEUP); _cimg_keycode(TAB); _cimg_keycode(Q); _cimg_keycode(W);
_cimg_keycode(E); _cimg_keycode(R); _cimg_keycode(T); _cimg_keycode(Y);
_cimg_keycode(U); _cimg_keycode(I); _cimg_keycode(O); _cimg_keycode(P);
_cimg_keycode(DELETE); _cimg_keycode(END); _cimg_keycode(PAGEDOWN);
_cimg_keycode(CAPSLOCK); _cimg_keycode(A); _cimg_keycode(S); _cimg_keycode(D);
_cimg_keycode(F); _cimg_keycode(G); _cimg_keycode(H); _cimg_keycode(J);
_cimg_keycode(K); _cimg_keycode(L); _cimg_keycode(ENTER);
_cimg_keycode(SHIFTLEFT); _cimg_keycode(Z); _cimg_keycode(X); _cimg_keycode(C);
_cimg_keycode(V); _cimg_keycode(B); _cimg_keycode(N); _cimg_keycode(M);
_cimg_keycode(SHIFTRIGHT); _cimg_keycode(ARROWUP); _cimg_keycode(CTRLLEFT);
_cimg_keycode(APPLEFT); _cimg_keycode(ALT); _cimg_keycode(SPACE); _cimg_keycode(ALTGR);
_cimg_keycode(APPRIGHT); _cimg_keycode(MENU); _cimg_keycode(CTRLRIGHT);
_cimg_keycode(ARROWLEFT); _cimg_keycode(ARROWDOWN); _cimg_keycode(ARROWRIGHT);
_cimg_keycode(PAD0); _cimg_keycode(PAD1); _cimg_keycode(PAD2);
_cimg_keycode(PAD3); _cimg_keycode(PAD4); _cimg_keycode(PAD5);
_cimg_keycode(PAD6); _cimg_keycode(PAD7); _cimg_keycode(PAD8);
_cimg_keycode(PAD9); _cimg_keycode(PADADD); _cimg_keycode(PADSUB);
_cimg_keycode(PADMUL); _cimg_keycode(PADDIV);
return 0;
}
//! Return the current refresh rate, in frames per second.
/**
\note Returns a significant value when the current instance is used to display successive frames.
It measures the delay between successive calls to frames_per_second().
**/
float frames_per_second() {
if (!_fps_timer) _fps_timer = cimg::time();
const float delta = (cimg::time() - _fps_timer)/1000.0f;
++_fps_frames;
if (delta>=1) {
_fps_fps = _fps_frames/delta;
_fps_frames = 0;
_fps_timer = cimg::time();
}
return _fps_fps;
}
//@}
//---------------------------------------
//
//! \name Window Manipulation
//@{
//---------------------------------------
#if cimg_display==0
//! Display image on associated window.
/**
\param img Input image to display.
\note This method returns immediately.
**/
template<typename T>
CImgDisplay& display(const CImg<T>& img) {
return assign(img);
}
#endif
//! Display list of images on associated window.
/**
\param list List of images to display.
\param axis Axis used to append the images along, for the visualization (can be \c x, \c y, \c z or \c c).
\param align Relative position of aligned images when displaying lists with images of different sizes
(\c 0 for upper-left, \c 0.5 for centering and \c 1 for lower-right).
\note This method returns immediately.
**/
template<typename T>
CImgDisplay& display(const CImgList<T>& list, const char axis='x', const float align=0) {
if (list._width==1) {
const CImg<T>& img = list[0];
if (img._depth==1 && (img._spectrum==1 || img._spectrum>=3) && _normalization!=1) return display(img);
}
CImgList<typename CImg<T>::ucharT> visu(list._width);
unsigned int dims = 0;
cimglist_for(list,l) {
const CImg<T>& img = list._data[l];
img.__get_select(*this,_normalization,(img._width - 1)/2,(img._height - 1)/2,
(img._depth - 1)/2).move_to(visu[l]);
dims = std::max(dims,visu[l]._spectrum);
}
cimglist_for(list,l) if (visu[l]._spectrum<dims) visu[l].resize(-100,-100,-100,dims,1);
visu.get_append(axis,align).display(*this);
return *this;
}
#if cimg_display==0
//! Show (closed) associated window on the screen.
/**
\note
- Force the associated window of a display to be visible on the screen, even if it has been closed before.
- Using show() on a visible display does nothing.
**/
CImgDisplay& show() {
return assign();
}
//! Close (visible) associated window and make it disappear from the screen.
/**
\note
- A closed display only means the associated window is not visible anymore. This does not mean the display has
been destroyed.
Use show() to make the associated window reappear.
- Using close() on a closed display does nothing.
**/
CImgDisplay& close() {
return assign();
}
//! Move associated window to a new location.
/**
\param pos_x X-coordinate of the new window location.
\param pos_y Y-coordinate of the new window location.
\note Depending on the window manager behavior, this method may not succeed (no exceptions are thrown
nevertheless).
**/
CImgDisplay& move(const int pos_x, const int pos_y) {
return assign(pos_x,pos_y);
}
#endif
//! Resize display to the size of the associated window.
/**
\param force_redraw Tells if the previous window content must be updated and refreshed as well.
\note
- Calling this method ensures that width() and window_width() become equal, as well as height() and
window_height().
- The associated window is also resized to specified dimensions.
**/
CImgDisplay& resize(const bool force_redraw=true) {
resize(window_width(),window_height(),force_redraw);
return *this;
}
#if cimg_display==0
//! Resize display to the specified size.
/**
\param width Requested display width.
\param height Requested display height.
\param force_redraw Tells if the previous window content must be updated and refreshed as well.
\note The associated window is also resized to specified dimensions.
**/
CImgDisplay& resize(const int width, const int height, const bool force_redraw=true) {
return assign(width,height,0,3,force_redraw);
}
#endif
//! Resize display to the size of an input image.
/**
\param img Input image to take size from.
\param force_redraw Tells if the previous window content must be resized and updated as well.
\note
- Calling this method ensures that width() and <tt>img.width()</tt> become equal, as well as height() and
<tt>img.height()</tt>.
- The associated window is also resized to specified dimensions.
**/
template<typename T>
CImgDisplay& resize(const CImg<T>& img, const bool force_redraw=true) {
return resize(img._width,img._height,force_redraw);
}
//! Resize display to the size of another CImgDisplay instance.
/**
\param disp Input display to take size from.
\param force_redraw Tells if the previous window content must be resized and updated as well.
\note
- Calling this method ensures that width() and <tt>disp.width()</tt> become equal, as well as height() and
<tt>disp.height()</tt>.
- The associated window is also resized to specified dimensions.
**/
CImgDisplay& resize(const CImgDisplay& disp, const bool force_redraw=true) {
return resize(disp.width(),disp.height(),force_redraw);
}
// [internal] Render pixel buffer with size (wd,hd) from source buffer of size (ws,hs).
template<typename t, typename T>
static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
t *ptrd, const unsigned int wd, const unsigned int hd) {
unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd + 1], *poffx, *poffy;
float s, curr, old;
s = (float)ws/wd;
poffx = offx; curr = 0; for (unsigned int x = 0; x<wd; ++x) {
old = curr; curr+=s; *(poffx++) = (unsigned int)curr - (unsigned int)old;
}
s = (float)hs/hd;
poffy = offy; curr = 0; for (unsigned int y = 0; y<hd; ++y) {
old = curr; curr+=s; *(poffy++) = ws*((unsigned int)curr - (unsigned int)old);
}
*poffy = 0;
poffy = offy;
for (unsigned int y = 0; y<hd; ) {