Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epoxy
GitHub Repository: epoxy/proj11
Path: blob/master/SLICK_HOME/src/org/newdawn/slick/BigImage.java
1456 views
1
package org.newdawn.slick;
2
3
import java.io.IOException;
4
import java.nio.ByteBuffer;
5
import java.nio.IntBuffer;
6
7
import org.lwjgl.BufferUtils;
8
import org.newdawn.slick.opengl.ImageData;
9
import org.newdawn.slick.opengl.ImageDataFactory;
10
import org.newdawn.slick.opengl.LoadableImageData;
11
import org.newdawn.slick.opengl.Texture;
12
import org.newdawn.slick.opengl.renderer.SGL;
13
import org.newdawn.slick.opengl.renderer.Renderer;
14
import org.newdawn.slick.util.OperationNotSupportedException;
15
import org.newdawn.slick.util.ResourceLoader;
16
17
/**
18
* An image implementation that handles loaded images that are larger than the
19
* maximum texture size supported by the card. In most cases it makes sense
20
* to make sure all of your image resources are less than 512x512 in size when
21
* using OpenGL. However, in the rare circumstances where this isn't possible
22
* this implementation can be used to draw a tiled version of the image built
23
* from several smaller textures.
24
*
25
* This implementation does come with limitations and some performance impact
26
* however - so use only when absolutely required.
27
*
28
* TODO: The code in here isn't pretty, really needs revisiting with a comment stick.
29
*
30
* @author kevin
31
*/
32
public class BigImage extends Image {
33
/** The renderer to use for all GL operations */
34
protected static SGL GL = Renderer.get();
35
36
/**
37
* Get the maximum size of an image supported by the underlying
38
* hardware.
39
*
40
* @return The maximum size of the textures supported by the underlying
41
* hardware.
42
*/
43
public static final int getMaxSingleImageSize() {
44
IntBuffer buffer = BufferUtils.createIntBuffer(16);
45
GL.glGetInteger(SGL.GL_MAX_TEXTURE_SIZE, buffer);
46
47
return buffer.get(0);
48
}
49
50
/** The last image that we put into "in use" mode */
51
private static Image lastBind;
52
53
/** The images building up this sub-image */
54
private Image[][] images;
55
/** The number of images on the xaxis */
56
private int xcount;
57
/** The number of images on the yaxis */
58
private int ycount;
59
/** The real width of the whole image - maintained even when scaled */
60
private int realWidth;
61
/** The real hieght of the whole image - maintained even when scaled */
62
private int realHeight;
63
64
/**
65
* Create a new big image. Empty contructor for cloning only
66
*/
67
private BigImage() {
68
inited = true;
69
}
70
71
/**
72
* Create a new big image by loading it from the specified reference
73
*
74
* @param ref The reference to the image to load
75
* @throws SlickException Indicates we were unable to locate the resource
76
*/
77
public BigImage(String ref) throws SlickException {
78
this(ref, Image.FILTER_NEAREST);
79
}
80
81
/**
82
* Create a new big image by loading it from the specified reference
83
*
84
* @param ref The reference to the image to load
85
* @param filter The image filter to apply (@see #Image.FILTER_NEAREST)
86
* @throws SlickException Indicates we were unable to locate the resource
87
*/
88
public BigImage(String ref,int filter) throws SlickException {
89
90
build(ref, filter, getMaxSingleImageSize());
91
}
92
93
/**
94
* Create a new big image by loading it from the specified reference
95
*
96
* @param ref The reference to the image to load
97
* @param filter The image filter to apply (@see #Image.FILTER_NEAREST)
98
* @param tileSize The maximum size of the tiles to use to build the bigger image
99
* @throws SlickException Indicates we were unable to locate the resource
100
*/
101
public BigImage(String ref, int filter, int tileSize) throws SlickException {
102
build(ref, filter, tileSize);
103
}
104
105
/**
106
* Create a new big image by loading it from the specified image data
107
*
108
* @param data The pixelData to use to create the image
109
* @param imageBuffer The buffer containing texture data
110
* @param filter The image filter to apply (@see #Image.FILTER_NEAREST)
111
*/
112
public BigImage(LoadableImageData data, ByteBuffer imageBuffer, int filter) {
113
build(data, imageBuffer, filter, getMaxSingleImageSize());
114
}
115
116
/**
117
* Create a new big image by loading it from the specified image data
118
*
119
* @param data The pixelData to use to create the image
120
* @param imageBuffer The buffer containing texture data
121
* @param filter The image filter to apply (@see #Image.FILTER_NEAREST)
122
* @param tileSize The maximum size of the tiles to use to build the bigger image
123
*/
124
public BigImage(LoadableImageData data, ByteBuffer imageBuffer, int filter, int tileSize) {
125
build(data, imageBuffer, filter, tileSize);
126
}
127
128
/**
129
* Get a sub tile of this big image. Useful for debugging
130
*
131
* @param x The x tile index
132
* @param y The y tile index
133
* @return The image used for this tile
134
*/
135
public Image getTile(int x, int y) {
136
return images[x][y];
137
}
138
139
/**
140
* Create a new big image by loading it from the specified reference
141
*
142
* @param ref The reference to the image to load
143
* @param filter The image filter to apply (@see #Image.FILTER_NEAREST)
144
* @param tileSize The maximum size of the tiles to use to build the bigger image
145
* @throws SlickException Indicates we were unable to locate the resource
146
*/
147
private void build(String ref, int filter, int tileSize) throws SlickException {
148
try {
149
final LoadableImageData data = ImageDataFactory.getImageDataFor(ref);
150
final ByteBuffer imageBuffer = data.loadImage(ResourceLoader.getResourceAsStream(ref), false, null);
151
build(data, imageBuffer, filter, tileSize);
152
} catch (IOException e) {
153
throw new SlickException("Failed to load: "+ref, e);
154
}
155
}
156
157
/**
158
* Create an big image from a image data source.
159
*
160
* @param data The pixelData to use to create the image
161
* @param imageBuffer The buffer containing texture data
162
* @param filter The filter to use when scaling this image
163
* @param tileSize The maximum size of the tiles to use to build the bigger image
164
*/
165
private void build(final LoadableImageData data, final ByteBuffer imageBuffer, int filter, int tileSize) {
166
final int dataWidth = data.getTexWidth();
167
final int dataHeight = data.getTexHeight();
168
169
realWidth = width = data.getWidth();
170
realHeight = height = data.getHeight();
171
172
if ((dataWidth <= tileSize) && (dataHeight <= tileSize)) {
173
images = new Image[1][1];
174
ImageData tempData = new ImageData() {
175
public int getDepth() {
176
return data.getDepth();
177
}
178
179
public int getHeight() {
180
return dataHeight;
181
}
182
183
public ByteBuffer getImageBufferData() {
184
return imageBuffer;
185
}
186
187
public int getTexHeight() {
188
return dataHeight;
189
}
190
191
public int getTexWidth() {
192
return dataWidth;
193
}
194
195
public int getWidth() {
196
return dataWidth;
197
}
198
};
199
images[0][0] = new Image(tempData, filter);
200
xcount = 1;
201
ycount = 1;
202
inited = true;
203
return;
204
}
205
206
xcount = ((realWidth-1) / tileSize) + 1;
207
ycount = ((realHeight-1) / tileSize) + 1;
208
209
images = new Image[xcount][ycount];
210
int components = data.getDepth() / 8;
211
212
for (int x=0;x<xcount;x++) {
213
for (int y=0;y<ycount;y++) {
214
int finalX = ((x+1) * tileSize);
215
int finalY = ((y+1) * tileSize);
216
final int imageWidth = tileSize;
217
final int imageHeight = tileSize;
218
219
final int xSize = Math.min(dataWidth, imageWidth);
220
final int ySize = Math.min(dataHeight, imageHeight);
221
222
final ByteBuffer subBuffer = BufferUtils.createByteBuffer(tileSize*tileSize*components);
223
int xo = x*tileSize*components;
224
225
byte[] byteData = new byte[xSize*components];
226
for (int i=0;i<ySize;i++) {
227
int yo = (((y * tileSize) + i) * dataWidth) * components;
228
imageBuffer.position(yo+xo);
229
230
imageBuffer.get(byteData, 0, xSize*components);
231
subBuffer.put(byteData);
232
}
233
234
subBuffer.flip();
235
ImageData imgData = new ImageData() {
236
public int getDepth() {
237
return data.getDepth();
238
}
239
240
public int getHeight() {
241
return imageHeight;
242
}
243
244
public int getWidth() {
245
return imageWidth;
246
}
247
248
public ByteBuffer getImageBufferData() {
249
return subBuffer;
250
}
251
252
public int getTexHeight() {
253
return ySize;
254
}
255
256
public int getTexWidth() {
257
return xSize;
258
}
259
};
260
images[x][y] = new Image(imgData, filter);
261
}
262
}
263
264
inited = true;
265
}
266
267
/**
268
* Not supported in BigImage
269
*
270
* @see org.newdawn.slick.Image#bind()
271
*/
272
public void bind() {
273
throw new OperationNotSupportedException("Can't bind big images yet");
274
}
275
276
/**
277
* Not supported in BigImage
278
*
279
* @see org.newdawn.slick.Image#copy()
280
*/
281
public Image copy() {
282
throw new OperationNotSupportedException("Can't copy big images yet");
283
}
284
285
/**
286
* @see org.newdawn.slick.Image#draw()
287
*/
288
public void draw() {
289
draw(0,0);
290
}
291
292
/**
293
* @see org.newdawn.slick.Image#draw(float, float, org.newdawn.slick.Color)
294
*/
295
public void draw(float x, float y, Color filter) {
296
draw(x,y,width,height,filter);
297
}
298
299
/**
300
* @see org.newdawn.slick.Image#draw(float, float, float, org.newdawn.slick.Color)
301
*/
302
public void draw(float x, float y, float scale, Color filter) {
303
draw(x,y,width*scale,height*scale,filter);
304
}
305
306
/**
307
* @see org.newdawn.slick.Image#draw(float, float, float, float, org.newdawn.slick.Color)
308
*/
309
public void draw(float x, float y, float width, float height, Color filter) {
310
float sx = width / realWidth;
311
float sy = height / realHeight;
312
313
GL.glTranslatef(x,y,0);
314
GL.glScalef(sx,sy,1);
315
316
float xp = 0;
317
float yp = 0;
318
319
for (int tx=0;tx<xcount;tx++) {
320
yp = 0;
321
for (int ty=0;ty<ycount;ty++) {
322
Image image = images[tx][ty];
323
324
image.draw(xp,yp,image.getWidth(), image.getHeight(), filter);
325
326
yp += image.getHeight();
327
if (ty == ycount - 1) {
328
xp += image.getWidth();
329
}
330
}
331
332
}
333
334
GL.glScalef(1.0f/sx,1.0f/sy,1);
335
GL.glTranslatef(-x,-y,0);
336
}
337
338
/**
339
* @see org.newdawn.slick.Image#draw(float, float, float, float, float, float, float, float)
340
*/
341
public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) {
342
int srcwidth = (int) (srcx2 - srcx);
343
int srcheight = (int) (srcy2 - srcy);
344
345
Image subImage = getSubImage((int) srcx,(int) srcy,srcwidth,srcheight);
346
347
int width = (int) (x2 - x);
348
int height = (int) (y2 - y);
349
350
subImage.draw(x,y,width,height);
351
}
352
353
/**
354
* @see org.newdawn.slick.Image#draw(float, float, float, float, float, float)
355
*/
356
public void draw(float x, float y, float srcx, float srcy, float srcx2, float srcy2) {
357
int srcwidth = (int) (srcx2 - srcx);
358
int srcheight = (int) (srcy2 - srcy);
359
360
draw(x,y,srcwidth,srcheight,srcx,srcy,srcx2,srcy2);
361
}
362
363
/**
364
* @see org.newdawn.slick.Image#draw(float, float, float, float)
365
*/
366
public void draw(float x, float y, float width, float height) {
367
draw(x,y,width,height,Color.white);
368
}
369
370
/**
371
* @see org.newdawn.slick.Image#draw(float, float, float)
372
*/
373
public void draw(float x, float y, float scale) {
374
draw(x,y,scale,Color.white);
375
}
376
377
/**
378
* @see org.newdawn.slick.Image#draw(float, float)
379
*/
380
public void draw(float x, float y) {
381
draw(x,y,Color.white);
382
}
383
384
/**
385
* @see org.newdawn.slick.Image#drawEmbedded(float, float, float, float)
386
*/
387
public void drawEmbedded(float x, float y, float width, float height) {
388
float sx = width / realWidth;
389
float sy = height / realHeight;
390
391
float xp = 0;
392
float yp = 0;
393
394
for (int tx=0;tx<xcount;tx++) {
395
yp = 0;
396
for (int ty=0;ty<ycount;ty++) {
397
Image image = images[tx][ty];
398
399
if ((lastBind == null) || (image.getTexture() != lastBind.getTexture())) {
400
if (lastBind != null) {
401
lastBind.endUse();
402
}
403
lastBind = image;
404
lastBind.startUse();
405
}
406
image.drawEmbedded(xp+x,yp+y,image.getWidth(), image.getHeight());
407
408
yp += image.getHeight();
409
if (ty == ycount - 1) {
410
xp += image.getWidth();
411
}
412
}
413
414
}
415
}
416
417
/**
418
* @see org.newdawn.slick.Image#drawFlash(float, float, float, float)
419
*/
420
public void drawFlash(float x, float y, float width, float height) {
421
float sx = width / realWidth;
422
float sy = height / realHeight;
423
424
GL.glTranslatef(x,y,0);
425
GL.glScalef(sx,sy,1);
426
427
float xp = 0;
428
float yp = 0;
429
430
for (int tx=0;tx<xcount;tx++) {
431
yp = 0;
432
for (int ty=0;ty<ycount;ty++) {
433
Image image = images[tx][ty];
434
435
image.drawFlash(xp,yp,image.getWidth(), image.getHeight());
436
437
yp += image.getHeight();
438
if (ty == ycount - 1) {
439
xp += image.getWidth();
440
}
441
}
442
443
}
444
445
GL.glScalef(1.0f/sx,1.0f/sy,1);
446
GL.glTranslatef(-x,-y,0);
447
}
448
449
/**
450
* @see org.newdawn.slick.Image#drawFlash(float, float)
451
*/
452
public void drawFlash(float x, float y) {
453
drawFlash(x,y,width,height);
454
}
455
456
/**
457
* Not supported in BigImage
458
*
459
* @see org.newdawn.slick.Image#endUse()
460
*/
461
public void endUse() {
462
if (lastBind != null) {
463
lastBind.endUse();
464
}
465
lastBind = null;
466
}
467
468
/**
469
* Not supported in BigImage
470
*
471
* @see org.newdawn.slick.Image#startUse()
472
*/
473
public void startUse() {
474
}
475
476
/**
477
* Not supported in BigImage
478
*
479
* @see org.newdawn.slick.Image#ensureInverted()
480
*/
481
public void ensureInverted() {
482
throw new OperationNotSupportedException("Doesn't make sense for tiled operations");
483
}
484
485
/**
486
* Not supported in BigImage
487
*
488
* @see org.newdawn.slick.Image#getColor(int, int)
489
*/
490
public Color getColor(int x, int y) {
491
throw new OperationNotSupportedException("Can't use big images as buffers");
492
}
493
494
/**
495
* @see org.newdawn.slick.Image#getFlippedCopy(boolean, boolean)
496
*/
497
public Image getFlippedCopy(boolean flipHorizontal, boolean flipVertical) {
498
BigImage image = new BigImage();
499
500
image.images = images;
501
image.xcount = xcount;
502
image.ycount = ycount;
503
image.width = width;
504
image.height = height;
505
image.realWidth = realWidth;
506
image.realHeight = realHeight;
507
508
if (flipHorizontal) {
509
Image[][] images = image.images;
510
image.images = new Image[xcount][ycount];
511
512
for (int x=0;x<xcount;x++) {
513
for (int y=0;y<ycount;y++) {
514
image.images[x][y] = images[xcount-1-x][y].getFlippedCopy(true, false);
515
}
516
}
517
}
518
519
if (flipVertical) {
520
Image[][] images = image.images;
521
image.images = new Image[xcount][ycount];
522
523
for (int x=0;x<xcount;x++) {
524
for (int y=0;y<ycount;y++) {
525
image.images[x][y] = images[x][ycount-1-y].getFlippedCopy(false, true);
526
}
527
}
528
}
529
530
return image;
531
}
532
533
/**
534
* Not supported in BigImage
535
*
536
* @see org.newdawn.slick.Image#getGraphics()
537
*/
538
public Graphics getGraphics() throws SlickException {
539
throw new OperationNotSupportedException("Can't use big images as offscreen buffers");
540
}
541
542
/**
543
* @see org.newdawn.slick.Image#getScaledCopy(float)
544
*/
545
public Image getScaledCopy(float scale) {
546
return getScaledCopy((int) (scale * width), (int) (scale * height));
547
}
548
549
/**
550
* @see org.newdawn.slick.Image#getScaledCopy(int, int)
551
*/
552
public Image getScaledCopy(int width, int height) {
553
BigImage image = new BigImage();
554
555
image.images = images;
556
image.xcount = xcount;
557
image.ycount = ycount;
558
image.width = width;
559
image.height = height;
560
image.realWidth = realWidth;
561
image.realHeight = realHeight;
562
563
return image;
564
}
565
566
/**
567
* @see org.newdawn.slick.Image#getSubImage(int, int, int, int)
568
*/
569
public Image getSubImage(int x, int y, int width, int height) {
570
BigImage image = new BigImage();
571
572
image.width = width;
573
image.height = height;
574
image.realWidth = width;
575
image.realHeight = height;
576
image.images = new Image[this.xcount][this.ycount];
577
578
float xp = 0;
579
float yp = 0;
580
int x2 = x+width;
581
int y2 = y+height;
582
583
int startx = 0;
584
int starty = 0;
585
boolean foundStart = false;
586
587
for (int xt=0;xt<xcount;xt++) {
588
yp = 0;
589
starty = 0;
590
foundStart = false;
591
for (int yt=0;yt<ycount;yt++) {
592
Image current = images[xt][yt];
593
594
int xp2 = (int) (xp + current.getWidth());
595
int yp2 = (int) (yp + current.getHeight());
596
597
// if the top corner of the subimage is inside the area
598
// we want or the bottom corrent of the image is, then consider using the
599
// image
600
601
// this image contributes to the sub image we're attempt to retrieve
602
int targetX1 = (int) Math.max(x, xp);
603
int targetY1 = (int) Math.max(y, yp);
604
int targetX2 = Math.min(x2, xp2);
605
int targetY2 = Math.min(y2, yp2);
606
607
int targetWidth = targetX2 - targetX1;
608
int targetHeight = targetY2 - targetY1;
609
610
if ((targetWidth > 0) && (targetHeight > 0)) {
611
Image subImage = current.getSubImage((int) (targetX1 - xp), (int) (targetY1 - yp),
612
(targetX2 - targetX1),
613
(targetY2 - targetY1));
614
foundStart = true;
615
image.images[startx][starty] = subImage;
616
starty++;
617
image.ycount = Math.max(image.ycount, starty);
618
}
619
620
yp += current.getHeight();
621
if (yt == ycount - 1) {
622
xp += current.getWidth();
623
}
624
}
625
if (foundStart) {
626
startx++;
627
image.xcount++;
628
}
629
}
630
631
return image;
632
}
633
634
/**
635
* Not supported in BigImage
636
*
637
* @see org.newdawn.slick.Image#getTexture()
638
*/
639
public Texture getTexture() {
640
throw new OperationNotSupportedException("Can't use big images as offscreen buffers");
641
}
642
643
/**
644
* @see org.newdawn.slick.Image#initImpl()
645
*/
646
protected void initImpl() {
647
throw new OperationNotSupportedException("Can't use big images as offscreen buffers");
648
}
649
650
/**
651
* @see org.newdawn.slick.Image#reinit()
652
*/
653
protected void reinit() {
654
throw new OperationNotSupportedException("Can't use big images as offscreen buffers");
655
}
656
657
/**
658
* Not supported in BigImage
659
*
660
* @see org.newdawn.slick.Image#setTexture(org.newdawn.slick.opengl.Texture)
661
*/
662
public void setTexture(Texture texture) {
663
throw new OperationNotSupportedException("Can't use big images as offscreen buffers");
664
}
665
666
/**
667
* Get a sub-image that builds up this image. Note that the offsets
668
* used will depend on the maximum texture size on the OpenGL hardware
669
*
670
* @param offsetX The x position of the image to return
671
* @param offsetY The y position of the image to return
672
* @return The image at the specified offset into the big image
673
*/
674
public Image getSubImage(int offsetX, int offsetY) {
675
return images[offsetX][offsetY];
676
}
677
678
/**
679
* Get a count of the number images that build this image up horizontally
680
*
681
* @return The number of sub-images across the big image
682
*/
683
public int getHorizontalImageCount() {
684
return xcount;
685
}
686
687
/**
688
* Get a count of the number images that build this image up vertically
689
*
690
* @return The number of sub-images down the big image
691
*/
692
public int getVerticalImageCount() {
693
return ycount;
694
}
695
696
/**
697
* @see org.newdawn.slick.Image#toString()
698
*/
699
public String toString() {
700
return "[BIG IMAGE]";
701
}
702
703
/**
704
* Destroy the image and release any native resources.
705
* Calls on a destroyed image have undefined results
706
*/
707
public void destroy() throws SlickException {
708
for (int tx=0;tx<xcount;tx++) {
709
for (int ty=0;ty<ycount;ty++) {
710
Image image = images[tx][ty];
711
image.destroy();
712
}
713
}
714
}
715
716
/**
717
* @see org.newdawn.slick.Image#draw(float, float, float, float, float, float, float, float, org.newdawn.slick.Color)
718
*/
719
public void draw(float x, float y, float x2, float y2, float srcx,
720
float srcy, float srcx2, float srcy2, Color filter) {
721
int srcwidth = (int) (srcx2 - srcx);
722
int srcheight = (int) (srcy2 - srcy);
723
724
Image subImage = getSubImage((int) srcx,(int) srcy,srcwidth,srcheight);
725
726
int width = (int) (x2 - x);
727
int height = (int) (y2 - y);
728
729
subImage.draw(x,y,width,height,filter);
730
}
731
732
/**
733
* @see org.newdawn.slick.Image#drawCentered(float, float)
734
*/
735
public void drawCentered(float x, float y) {
736
throw new UnsupportedOperationException();
737
}
738
739
/**
740
* @see org.newdawn.slick.Image#drawEmbedded(float, float, float, float, float, float, float, float, org.newdawn.slick.Color)
741
*/
742
public void drawEmbedded(float x, float y, float x2, float y2, float srcx,
743
float srcy, float srcx2, float srcy2, Color filter) {
744
throw new UnsupportedOperationException();
745
}
746
747
/**
748
* @see org.newdawn.slick.Image#drawEmbedded(float, float, float, float, float, float, float, float)
749
*/
750
public void drawEmbedded(float x, float y, float x2, float y2, float srcx,
751
float srcy, float srcx2, float srcy2) {
752
throw new UnsupportedOperationException();
753
}
754
755
/**
756
* @see org.newdawn.slick.Image#drawFlash(float, float, float, float, org.newdawn.slick.Color)
757
*/
758
public void drawFlash(float x, float y, float width, float height, Color col) {
759
throw new UnsupportedOperationException();
760
}
761
762
/**
763
* @see org.newdawn.slick.Image#drawSheared(float, float, float, float)
764
*/
765
public void drawSheared(float x, float y, float hshear, float vshear) {
766
throw new UnsupportedOperationException();
767
}
768
}
769
770