Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epoxy
GitHub Repository: epoxy/proj11
Path: blob/master/SLICK_HOME/src/org/newdawn/slick/Image.java
1456 views
1
package org.newdawn.slick;
2
3
import java.io.IOException;
4
import java.io.InputStream;
5
6
import org.lwjgl.opengl.EXTSecondaryColor;
7
import org.lwjgl.opengl.EXTTextureMirrorClamp;
8
import org.lwjgl.opengl.GL11;
9
import org.lwjgl.opengl.GLContext;
10
import org.newdawn.slick.opengl.ImageData;
11
import org.newdawn.slick.opengl.InternalTextureLoader;
12
import org.newdawn.slick.opengl.Texture;
13
import org.newdawn.slick.opengl.TextureImpl;
14
import org.newdawn.slick.opengl.pbuffer.GraphicsFactory;
15
import org.newdawn.slick.opengl.renderer.Renderer;
16
import org.newdawn.slick.opengl.renderer.SGL;
17
import org.newdawn.slick.util.Log;
18
19
/**
20
* An image loaded from a file and renderable to the canvas
21
*
22
* @author kevin
23
*/
24
public class Image implements Renderable {
25
/** The top left corner identifier */
26
public static final int TOP_LEFT = 0;
27
/** The top right corner identifier */
28
public static final int TOP_RIGHT = 1;
29
/** The bottom right corner identifier */
30
public static final int BOTTOM_RIGHT = 2;
31
/** The bottom left corner identifier */
32
public static final int BOTTOM_LEFT = 3;
33
34
/** The renderer to use for all GL operations */
35
protected static SGL GL = Renderer.get();
36
37
/** The sprite sheet currently in use */
38
protected static Image inUse;
39
/** Use Linear Filtering */
40
public static final int FILTER_LINEAR = 1;
41
/** Use Nearest Filtering */
42
public static final int FILTER_NEAREST = 2;
43
44
/** The OpenGL texture for this image */
45
protected Texture texture;
46
/** The width of the image */
47
protected int width;
48
/** The height of the image */
49
protected int height;
50
/** The texture coordinate width to use to find our image */
51
protected float textureWidth;
52
/** The texture coordinate height to use to find our image */
53
protected float textureHeight;
54
/** The x texture offset to use to find our image */
55
protected float textureOffsetX;
56
/** The y texture offset to use to find our image */
57
protected float textureOffsetY;
58
/** Angle to rotate the image to. */
59
protected float angle;
60
/** The alpha to draw the image at */
61
protected float alpha = 1.0f;
62
/** The name given for the image */
63
protected String ref;
64
/** True if this image's state has been initialised */
65
protected boolean inited = false;
66
/** A pixelData holding the pixel data if it's been read for this texture */
67
protected byte[] pixelData;
68
/** True if the image has been destroyed */
69
protected boolean destroyed;
70
71
/** The x coordinate of the centre of rotation */
72
protected float centerX;
73
/** The y coordinate of the centre of rotation */
74
protected float centerY;
75
76
/** A meaningful name provided by the user of the image to tag it */
77
protected String name;
78
79
/** The colours for each of the corners */
80
protected Color[] corners;
81
/** The OpenGL max filter */
82
private int filter = SGL.GL_LINEAR;
83
84
/** True if the image should be flipped vertically */
85
private boolean flipped;
86
/** The transparent colour set if any */
87
private Color transparent;
88
89
/**
90
* Create a texture as a copy of another
91
*
92
* @param other The other texture to copy
93
*/
94
protected Image(Image other) {
95
this.width = other.getWidth();
96
this.height = other.getHeight();
97
this.texture = other.texture;
98
this.textureWidth = other.textureWidth;
99
this.textureHeight = other.textureHeight;
100
this.ref = other.ref;
101
this.textureOffsetX = other.textureOffsetX;
102
this.textureOffsetY = other.textureOffsetY;
103
104
centerX = width / 2;
105
centerY = height / 2;
106
inited = true;
107
}
108
109
/**
110
* Cloning constructor - only used internally.
111
*/
112
protected Image() {
113
}
114
115
/**
116
* Creates an image using the specified texture
117
*
118
* @param texture
119
* The texture to use
120
*/
121
public Image(Texture texture) {
122
this.texture = texture;
123
ref = texture.toString();
124
clampTexture();
125
}
126
127
/**
128
* Create an image based on a file at the specified location
129
*
130
* @param ref
131
* The location of the image file to load
132
* @throws SlickException
133
* Indicates a failure to load the image
134
*/
135
public Image(String ref) throws SlickException {
136
this(ref, false);
137
}
138
139
/**
140
* Create an image based on a file at the specified location
141
*
142
* @param ref The location of the image file to load
143
* @param trans The color to be treated as transparent
144
* @throws SlickException Indicates a failure to load the image
145
*/
146
public Image(String ref, Color trans) throws SlickException {
147
this(ref, false, FILTER_LINEAR, trans);
148
}
149
150
/**
151
* Create an image based on a file at the specified location
152
*
153
* @param ref The location of the image file to load
154
* @param flipped True if the image should be flipped on the y-axis on load
155
* @throws SlickException Indicates a failure to load the image
156
*/
157
public Image(String ref, boolean flipped) throws SlickException {
158
this(ref, flipped, FILTER_LINEAR);
159
}
160
161
/**
162
* Create an image based on a file at the specified location
163
*
164
* @param ref The location of the image file to load
165
* @param flipped True if the image should be flipped on the y-axis on load
166
* @param filter The filtering method to use when scaling this image
167
* @throws SlickException Indicates a failure to load the image
168
*/
169
public Image(String ref, boolean flipped, int filter) throws SlickException {
170
this(ref, flipped, filter, null);
171
}
172
173
/**
174
* Create an image based on a file at the specified location
175
*
176
* @param ref The location of the image file to load
177
* @param flipped True if the image should be flipped on the y-axis on load
178
* @param f The filtering method to use when scaling this image
179
* @param transparent The color to treat as transparent
180
* @throws SlickException Indicates a failure to load the image
181
*/
182
public Image(String ref, boolean flipped, int f, Color transparent) throws SlickException {
183
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
184
this.transparent = transparent;
185
this.flipped = flipped;
186
187
try {
188
this.ref = ref;
189
int[] trans = null;
190
if (transparent != null) {
191
trans = new int[3];
192
trans[0] = (int) (transparent.r * 255);
193
trans[1] = (int) (transparent.g * 255);
194
trans[2] = (int) (transparent.b * 255);
195
}
196
texture = InternalTextureLoader.get().getTexture(ref, flipped, filter, trans);
197
} catch (IOException e) {
198
Log.error(e);
199
throw new SlickException("Failed to load image from: "+ref, e);
200
}
201
}
202
203
/**
204
* Set the image filtering to be used. This will cause the image
205
* to be reloaded.
206
*
207
* @param f The filtering mode to use
208
* @throws SlickException Indicates a failure to revalidate the image source
209
*/
210
public void setFilter(int f) throws SlickException {
211
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
212
213
try {
214
int[] trans = null;
215
if (transparent != null) {
216
trans = new int[3];
217
trans[0] = (int) (transparent.r * 255);
218
trans[1] = (int) (transparent.g * 255);
219
trans[2] = (int) (transparent.b * 255);
220
}
221
texture = InternalTextureLoader.get().getTexture(ref, flipped, filter, trans);
222
} catch (IOException e) {
223
Log.error(e);
224
throw new SlickException("Failed to load image from: "+ref, e);
225
}
226
}
227
/**
228
* Create an empty image
229
*
230
* @param width The width of the image
231
* @param height The height of the image
232
* @throws SlickException Indicates a failure to create the underlying resource
233
*/
234
public Image(int width, int height) throws SlickException {
235
ref = super.toString();
236
237
try {
238
texture = InternalTextureLoader.get().createTexture(width, height);
239
} catch (IOException e) {
240
Log.error(e);
241
throw new SlickException("Failed to create empty image "+width+"x"+height);
242
}
243
244
init();
245
}
246
247
/**
248
* Create an image based on a file at the specified location
249
*
250
* @param in The input stream to read the image from
251
* @param ref The name that should be assigned to the image
252
* @param flipped True if the image should be flipped on the y-axis on load
253
* @throws SlickException Indicates a failure to load the image
254
*/
255
public Image(InputStream in, String ref, boolean flipped) throws SlickException {
256
this(in, ref, flipped, FILTER_LINEAR);
257
}
258
259
/**
260
* Create an image based on a file at the specified location
261
*
262
* @param in The input stream to read the image from
263
* @param ref The name that should be assigned to the image
264
* @param flipped True if the image should be flipped on the y-axis on load
265
* @param filter The filter to use when scaling this image
266
* @throws SlickException Indicates a failure to load the image
267
*/
268
public Image(InputStream in, String ref, boolean flipped,int filter) throws SlickException {
269
load(in, ref, flipped, filter, null);
270
}
271
272
/**
273
* Create an image from a pixelData of pixels
274
*
275
* @param buffer The pixelData to use to create the image
276
*/
277
Image(ImageBuffer buffer) {
278
this(buffer, FILTER_LINEAR);
279
TextureImpl.bindNone();
280
}
281
282
/**
283
* Create an image from a pixelData of pixels
284
*
285
* @param buffer The pixelData to use to create the image
286
* @param filter The filter to use when scaling this image
287
*/
288
Image(ImageBuffer buffer, int filter) {
289
this((ImageData) buffer, filter);
290
TextureImpl.bindNone();
291
}
292
293
/**
294
* Create an image from a image data source
295
*
296
* @param data The pixelData to use to create the image
297
*/
298
public Image(ImageData data) {
299
this(data, FILTER_LINEAR);
300
}
301
302
/**
303
* Create an image from a image data source. Note that this method uses
304
*
305
* @param data The pixelData to use to create the image
306
* @param f The filter to use when scaling this image
307
*/
308
public Image(ImageData data, int f) {
309
try {
310
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
311
texture = InternalTextureLoader.get().getTexture(data, this.filter);
312
ref = texture.toString();
313
} catch (IOException e) {
314
Log.error(e);
315
}
316
}
317
318
/**
319
* Get the OpenGL image filter in use
320
*
321
* @return The filter for magnification
322
*/
323
public int getFilter() {
324
return filter;
325
}
326
327
/**
328
* Get the reference to the resource this image was loaded from, if any. Note that
329
* this can be null in the cases where an image was programatically generated.
330
*
331
* @return The reference to the resource the reference was loaded from
332
*/
333
public String getResourceReference() {
334
return ref;
335
}
336
337
/**
338
* Set the color of the given corner when this image is rendered. This is
339
* useful lots of visual effect but especially light maps
340
*
341
* @param corner The corner identifier for the corner to be set
342
* @param r The red component value to set (between 0 and 1)
343
* @param g The green component value to set (between 0 and 1)
344
* @param b The blue component value to set (between 0 and 1)
345
* @param a The alpha component value to set (between 0 and 1)
346
*/
347
public void setColor(int corner, float r, float g, float b, float a) {
348
if (corners == null) {
349
corners = new Color[] {new Color(1,1,1,1f),new Color(1,1,1,1f), new Color(1,1,1,1f), new Color(1,1,1,1f)};
350
}
351
352
corners[corner].r = r;
353
corners[corner].g = g;
354
corners[corner].b = b;
355
corners[corner].a = a;
356
}
357
358
/**
359
* Clamp the loaded texture to it's edges
360
*/
361
public void clampTexture() {
362
if (GLContext.getCapabilities().GL_EXT_texture_mirror_clamp) {
363
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, EXTTextureMirrorClamp.GL_MIRROR_CLAMP_TO_EDGE_EXT);
364
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, EXTTextureMirrorClamp.GL_MIRROR_CLAMP_TO_EDGE_EXT);
365
} else {
366
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
367
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
368
}
369
}
370
371
/**
372
* Give this image a meaningful tagging name. Can be used as user data/identifier
373
* for the image.
374
*
375
* @param name The name to assign the image
376
*/
377
public void setName(String name) {
378
this.name = name;
379
}
380
381
/**
382
* Return a meaningful tagging name that has been assigned to this image.
383
*
384
* @return A name or null if the name hasn't been set
385
*/
386
public String getName() {
387
return name;
388
}
389
390
/**
391
* Get a graphics context that can be used to draw to this image
392
*
393
* @return The graphics context used to render to this image
394
* @throws SlickException Indicates a failure to create a graphics context
395
*/
396
public Graphics getGraphics() throws SlickException {
397
return GraphicsFactory.getGraphicsForImage(this);
398
}
399
400
/**
401
* Load the image
402
*
403
* @param in The input stream to read the image from
404
* @param ref The name that should be assigned to the image
405
* @param flipped True if the image should be flipped on the y-axis on load
406
* @param f The filter to use when scaling this image
407
* @param transparent The color to treat as transparent
408
* @throws SlickException Indicates a failure to load the image
409
*/
410
private void load(InputStream in, String ref, boolean flipped, int f, Color transparent) throws SlickException {
411
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
412
413
try {
414
this.ref = ref;
415
int[] trans = null;
416
if (transparent != null) {
417
trans = new int[3];
418
trans[0] = (int) (transparent.r * 255);
419
trans[1] = (int) (transparent.g * 255);
420
trans[2] = (int) (transparent.b * 255);
421
}
422
texture = InternalTextureLoader.get().getTexture(in, ref, flipped, filter, trans);
423
} catch (IOException e) {
424
Log.error(e);
425
throw new SlickException("Failed to load image from: "+ref, e);
426
}
427
}
428
429
/**
430
* Bind to the texture of this image
431
*/
432
public void bind() {
433
texture.bind();
434
}
435
436
/**
437
* Reinitialise internal data
438
*/
439
protected void reinit() {
440
inited = false;
441
init();
442
}
443
444
/**
445
* Initialise internal data
446
*/
447
protected final void init() {
448
if (inited) {
449
return;
450
}
451
452
inited = true;
453
if (texture != null) {
454
width = texture.getImageWidth();
455
height = texture.getImageHeight();
456
textureOffsetX = 0;
457
textureOffsetY = 0;
458
textureWidth = texture.getWidth();
459
textureHeight = texture.getHeight();
460
}
461
462
initImpl();
463
464
centerX = width / 2;
465
centerY = height / 2;
466
}
467
468
/**
469
* Hook for subclasses to perform initialisation
470
*/
471
protected void initImpl() {
472
473
}
474
475
/**
476
* Draw this image at the current location
477
*/
478
public void draw() {
479
draw(0,0);
480
}
481
482
/**
483
* Draw the image based on it's center
484
*
485
* @param x The x coordinate to place the image's center at
486
* @param y The y coordinate to place the image's center at
487
*/
488
public void drawCentered(float x, float y) {
489
draw(x-(getWidth()/2),y-(getHeight()/2));
490
}
491
492
/**
493
* Draw this image at the specified location
494
*
495
* @param x The x location to draw the image at
496
* @param y The y location to draw the image at
497
*/
498
public void draw(float x, float y) {
499
init();
500
draw(x,y,width,height);
501
}
502
503
/**
504
* Draw this image at the specified location
505
*
506
* @param x The x location to draw the image at
507
* @param y The y location to draw the image at
508
* @param filter The color to filter with when drawing
509
*/
510
public void draw(float x, float y, Color filter) {
511
init();
512
draw(x,y,width,height, filter);
513
}
514
515
/**
516
* Draw this image as part of a collection of images
517
*
518
* @param x The x location to draw the image at
519
* @param y The y location to draw the image at
520
* @param width The width to render the image at
521
* @param height The height to render the image at
522
*/
523
public void drawEmbedded(float x,float y,float width,float height) {
524
init();
525
526
if (corners == null) {
527
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
528
GL.glVertex3f(x, y, 0);
529
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
530
GL.glVertex3f(x, y + height, 0);
531
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
532
+ textureHeight);
533
GL.glVertex3f(x + width, y + height, 0);
534
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
535
GL.glVertex3f(x + width, y, 0);
536
} else {
537
corners[TOP_LEFT].bind();
538
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
539
GL.glVertex3f(x, y, 0);
540
corners[BOTTOM_LEFT].bind();
541
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
542
GL.glVertex3f(x, y + height, 0);
543
corners[BOTTOM_RIGHT].bind();
544
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
545
+ textureHeight);
546
GL.glVertex3f(x + width, y + height, 0);
547
corners[TOP_RIGHT].bind();
548
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
549
GL.glVertex3f(x + width, y, 0);
550
}
551
}
552
553
/**
554
* Get the x offset in texels into the source texture
555
*
556
* @return The x offset
557
*/
558
public float getTextureOffsetX() {
559
init();
560
561
return textureOffsetX;
562
}
563
564
/**
565
* Get the y offset in texels into the source texture
566
*
567
* @return The y offset
568
*/
569
public float getTextureOffsetY() {
570
init();
571
572
return textureOffsetY;
573
}
574
575
/**
576
* Get the width in texels into the source texture
577
*
578
* @return The width
579
*/
580
public float getTextureWidth() {
581
init();
582
583
return textureWidth;
584
}
585
586
/**
587
* Get the height in texels into the source texture
588
*
589
* @return The height
590
*/
591
public float getTextureHeight() {
592
init();
593
594
return textureHeight;
595
}
596
597
/**
598
* Draw the image with a given scale
599
*
600
* @param x The x position to draw the image at
601
* @param y The y position to draw the image at
602
* @param scale The scaling to apply
603
*/
604
public void draw(float x,float y,float scale) {
605
init();
606
draw(x,y,width*scale,height*scale,Color.white);
607
}
608
609
/**
610
* Draw the image with a given scale
611
*
612
* @param x The x position to draw the image at
613
* @param y The y position to draw the image at
614
* @param scale The scaling to apply
615
* @param filter The colour filter to adapt the image with
616
*/
617
public void draw(float x,float y,float scale,Color filter) {
618
init();
619
draw(x,y,width*scale,height*scale,filter);
620
}
621
622
/**
623
* Draw this image at a specified location and size
624
*
625
* @param x
626
* The x location to draw the image at
627
* @param y
628
* The y location to draw the image at
629
* @param width
630
* The width to render the image at
631
* @param height
632
* The height to render the image at
633
*/
634
public void draw(float x,float y,float width,float height) {
635
init();
636
draw(x,y,width,height,Color.white);
637
}
638
639
/**
640
* Draw this image at a specified location and size
641
*
642
* @param x The x location to draw the image at
643
* @param y The y location to draw the image at
644
* @param hshear The amount to shear the bottom points by horizontally
645
* @param vshear The amount to shear the right points by vertically
646
*/
647
public void drawSheared(float x,float y, float hshear, float vshear) {
648
Color.white.bind();
649
texture.bind();
650
651
GL.glTranslatef(x, y, 0);
652
if (angle != 0) {
653
GL.glTranslatef(centerX, centerY, 0.0f);
654
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
655
GL.glTranslatef(-centerX, -centerY, 0.0f);
656
}
657
658
GL.glBegin(SGL.GL_QUADS);
659
init();
660
661
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
662
GL.glVertex3f(0, 0, 0);
663
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
664
GL.glVertex3f(hshear, height, 0);
665
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
666
+ textureHeight);
667
GL.glVertex3f(width + hshear, height + vshear, 0);
668
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
669
GL.glVertex3f(width, vshear, 0);
670
GL.glEnd();
671
672
if (angle != 0) {
673
GL.glTranslatef(centerX, centerY, 0.0f);
674
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
675
GL.glTranslatef(-centerX, -centerY, 0.0f);
676
}
677
GL.glTranslatef(-x, -y, 0);
678
}
679
680
/**
681
* Draw this image at a specified location and size
682
*
683
* @param x The x location to draw the image at
684
* @param y The y location to draw the image at
685
* @param width The width to render the image at
686
* @param height The height to render the image at
687
* @param filter The color to filter with while drawing
688
*/
689
public void draw(float x,float y,float width,float height,Color filter) {
690
if (alpha != 1) {
691
if (filter == null) {
692
filter = Color.white;
693
}
694
695
filter = new Color(filter);
696
filter.a *= alpha;
697
}
698
if (filter != null) {
699
filter.bind();
700
}
701
702
texture.bind();
703
704
GL.glTranslatef(x, y, 0);
705
if (angle != 0) {
706
GL.glTranslatef(centerX, centerY, 0.0f);
707
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
708
GL.glTranslatef(-centerX, -centerY, 0.0f);
709
}
710
711
GL.glBegin(SGL.GL_QUADS);
712
drawEmbedded(0,0,width,height);
713
GL.glEnd();
714
715
if (angle != 0) {
716
GL.glTranslatef(centerX, centerY, 0.0f);
717
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
718
GL.glTranslatef(-centerX, -centerY, 0.0f);
719
}
720
GL.glTranslatef(-x, -y, 0);
721
}
722
723
/**
724
* Draw this image at a specified location and size as a silohette
725
*
726
* @param x The x location to draw the image at
727
* @param y The y location to draw the image at
728
* @param width The width to render the image at
729
* @param height The height to render the image at
730
*/
731
public void drawFlash(float x,float y,float width,float height) {
732
drawFlash(x,y,width,height,Color.white);
733
}
734
735
/**
736
* Set the centre of the rotation when applied to this image
737
*
738
* @param x The x coordinate of center of rotation relative to the top left corner of the image
739
* @param y The y coordinate of center of rotation relative to the top left corner of the image
740
*/
741
public void setCenterOfRotation(float x, float y) {
742
centerX = x;
743
centerY = y;
744
}
745
746
/**
747
* Get the x component of the center of rotation of this image
748
*
749
* @return The x component of the center of rotation
750
*/
751
public float getCenterOfRotationX() {
752
init();
753
754
return centerX;
755
}
756
757
/**
758
* Get the y component of the center of rotation of this image
759
*
760
* @return The y component of the center of rotation
761
*/
762
public float getCenterOfRotationY() {
763
init();
764
765
return centerY;
766
}
767
768
/**
769
* Draw this image at a specified location and size as a silohette
770
*
771
* @param x The x location to draw the image at
772
* @param y The y location to draw the image at
773
* @param width The width to render the image at
774
* @param height The height to render the image at
775
* @param col The color for the sillohette
776
*/
777
public void drawFlash(float x,float y,float width,float height, Color col) {
778
init();
779
780
col.bind();
781
texture.bind();
782
783
if (GLContext.getCapabilities().GL_EXT_secondary_color) {
784
GL.glEnable(EXTSecondaryColor.GL_COLOR_SUM_EXT);
785
EXTSecondaryColor.glSecondaryColor3ubEXT((byte)(col.r * 255),
786
(byte)(col.g * 255),
787
(byte)(col.b * 255));
788
}
789
790
GL.glTexEnvi(SGL.GL_TEXTURE_ENV, SGL.GL_TEXTURE_ENV_MODE, SGL.GL_MODULATE);
791
792
GL.glTranslatef(x, y, 0);
793
if (angle != 0) {
794
GL.glTranslatef(centerX, centerY, 0.0f);
795
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
796
GL.glTranslatef(-centerX, -centerY, 0.0f);
797
}
798
799
GL.glBegin(SGL.GL_QUADS);
800
drawEmbedded(0,0,width,height);
801
GL.glEnd();
802
803
if (angle != 0) {
804
GL.glTranslatef(centerX, centerY, 0.0f);
805
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
806
GL.glTranslatef(-centerX, -centerY, 0.0f);
807
}
808
GL.glTranslatef(-x, -y, 0);
809
810
if (GLContext.getCapabilities().GL_EXT_secondary_color) {
811
GL.glDisable(EXTSecondaryColor.GL_COLOR_SUM_EXT);
812
}
813
}
814
815
/**
816
* Draw this image at a specified location and size in a white silohette
817
*
818
* @param x The x location to draw the image at
819
* @param y The y location to draw the image at
820
*/
821
public void drawFlash(float x,float y) {
822
drawFlash(x,y,getWidth(),getHeight());
823
}
824
825
/**
826
* Set the angle to rotate this image to. The angle will be normalized to
827
* be 0 <= angle < 360. The image will be rotated around its center.
828
*
829
* @param angle The angle to be set
830
*/
831
public void setRotation(float angle) {
832
this.angle = angle % 360.0f;
833
}
834
835
/**
836
* Get the current angle of rotation for this image.
837
* The image will be rotated around its center.
838
*
839
* @return The current angle.
840
*/
841
public float getRotation() {
842
return angle;
843
}
844
845
/**
846
* Get the alpha value to use when rendering this image
847
*
848
* @return The alpha value to use when rendering this image
849
*/
850
public float getAlpha() {
851
return alpha;
852
}
853
854
/**
855
* Set the alpha value to use when rendering this image
856
*
857
* @param alpha The alpha value to use when rendering this image
858
*/
859
public void setAlpha(float alpha) {
860
this.alpha = alpha;
861
}
862
863
/**
864
* Add the angle provided to the current rotation. The angle will be normalized to
865
* be 0 <= angle < 360. The image will be rotated around its center.
866
*
867
* @param angle The angle to add.
868
*/
869
public void rotate(float angle) {
870
this.angle += angle;
871
this.angle = this.angle % 360;
872
}
873
874
/**
875
* Get a sub-part of this image. Note that the create image retains a reference to the
876
* image data so should anything change it will affect sub-images too.
877
*
878
* @param x The x coordinate of the sub-image
879
* @param y The y coordinate of the sub-image
880
* @param width The width of the sub-image
881
* @param height The height of the sub-image
882
* @return The image represent the sub-part of this image
883
*/
884
public Image getSubImage(int x,int y,int width,int height) {
885
init();
886
887
float newTextureOffsetX = ((x / (float) this.width) * textureWidth) + textureOffsetX;
888
float newTextureOffsetY = ((y / (float) this.height) * textureHeight) + textureOffsetY;
889
float newTextureWidth = ((width / (float) this.width) * textureWidth);
890
float newTextureHeight = ((height / (float) this.height) * textureHeight);
891
892
Image sub = new Image();
893
sub.inited = true;
894
sub.texture = this.texture;
895
sub.textureOffsetX = newTextureOffsetX;
896
sub.textureOffsetY = newTextureOffsetY;
897
sub.textureWidth = newTextureWidth;
898
sub.textureHeight = newTextureHeight;
899
900
sub.width = width;
901
sub.height = height;
902
sub.ref = ref;
903
sub.centerX = width / 2;
904
sub.centerY = height / 2;
905
906
return sub;
907
}
908
909
/**
910
* Draw a section of this image at a particular location and scale on the screen
911
*
912
* @param x The x position to draw the image
913
* @param y The y position to draw the image
914
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
915
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
916
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
917
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
918
*/
919
public void draw(float x, float y, float srcx, float srcy, float srcx2, float srcy2) {
920
draw(x,y,x+width,y+height,srcx,srcy,srcx2,srcy2);
921
}
922
923
/**
924
* Draw a section of this image at a particular location and scale on the screen
925
*
926
* @param x The x position to draw the image
927
* @param y The y position to draw the image
928
* @param x2 The x position of the bottom right corner of the drawn image
929
* @param y2 The y position of the bottom right corner of the drawn image
930
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
931
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
932
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
933
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
934
*/
935
public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) {
936
draw(x,y,x2,y2,srcx,srcy,srcx2,srcy2,Color.white);
937
}
938
939
/**
940
* Draw a section of this image at a particular location and scale on the screen
941
*
942
* @param x The x position to draw the image
943
* @param y The y position to draw the image
944
* @param x2 The x position of the bottom right corner of the drawn image
945
* @param y2 The y position of the bottom right corner of the drawn image
946
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
947
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
948
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
949
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
950
* @param filter The colour filter to apply when drawing
951
*/
952
public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, Color filter) {
953
init();
954
955
if (alpha != 1) {
956
if (filter == null) {
957
filter = Color.white;
958
}
959
960
filter = new Color(filter);
961
filter.a *= alpha;
962
}
963
filter.bind();
964
texture.bind();
965
966
GL.glTranslatef(x, y, 0);
967
if (angle != 0) {
968
GL.glTranslatef(centerX, centerY, 0.0f);
969
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
970
GL.glTranslatef(-centerX, -centerY, 0.0f);
971
}
972
973
GL.glBegin(SGL.GL_QUADS);
974
drawEmbedded(0,0,x2-x,y2-y,srcx,srcy,srcx2,srcy2);
975
GL.glEnd();
976
977
if (angle != 0) {
978
GL.glTranslatef(centerX, centerY, 0.0f);
979
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
980
GL.glTranslatef(-centerX, -centerY, 0.0f);
981
}
982
GL.glTranslatef(-x, -y, 0);
983
984
// GL.glBegin(SGL.GL_QUADS);
985
// drawEmbedded(x,y,x2,y2,srcx,srcy,srcx2,srcy2);
986
// GL.glEnd();
987
}
988
989
/**
990
* Draw a section of this image at a particular location and scale on the screen, while this
991
* is image is "in use", i.e. between calls to startUse and endUse.
992
*
993
* @param x The x position to draw the image
994
* @param y The y position to draw the image
995
* @param x2 The x position of the bottom right corner of the drawn image
996
* @param y2 The y position of the bottom right corner of the drawn image
997
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
998
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
999
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
1000
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
1001
*/
1002
public void drawEmbedded(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) {
1003
drawEmbedded(x,y,x2,y2,srcx,srcy,srcx2,srcy2,null);
1004
}
1005
1006
/**
1007
* Draw a section of this image at a particular location and scale on the screen, while this
1008
* is image is "in use", i.e. between calls to startUse and endUse.
1009
*
1010
* @param x The x position to draw the image
1011
* @param y The y position to draw the image
1012
* @param x2 The x position of the bottom right corner of the drawn image
1013
* @param y2 The y position of the bottom right corner of the drawn image
1014
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
1015
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
1016
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
1017
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
1018
* @param filter The colour filter to apply when drawing
1019
*/
1020
public void drawEmbedded(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, Color filter) {
1021
if (filter != null) {
1022
filter.bind();
1023
}
1024
1025
float mywidth = x2 - x;
1026
float myheight = y2 - y;
1027
float texwidth = srcx2 - srcx;
1028
float texheight = srcy2 - srcy;
1029
1030
float newTextureOffsetX = (((srcx) / (width)) * textureWidth)
1031
+ textureOffsetX;
1032
float newTextureOffsetY = (((srcy) / (height)) * textureHeight)
1033
+ textureOffsetY;
1034
float newTextureWidth = ((texwidth) / (width))
1035
* textureWidth;
1036
float newTextureHeight = ((texheight) / (height))
1037
* textureHeight;
1038
1039
GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY);
1040
GL.glVertex3f(x,y, 0.0f);
1041
GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY
1042
+ newTextureHeight);
1043
GL.glVertex3f(x,(y + myheight), 0.0f);
1044
GL.glTexCoord2f(newTextureOffsetX + newTextureWidth,
1045
newTextureOffsetY + newTextureHeight);
1046
GL.glVertex3f((x + mywidth),(y + myheight), 0.0f);
1047
GL.glTexCoord2f(newTextureOffsetX + newTextureWidth,
1048
newTextureOffsetY);
1049
GL.glVertex3f((x + mywidth),y, 0.0f);
1050
}
1051
1052
/**
1053
* Get the width of this image
1054
*
1055
* @return The width of this image
1056
*/
1057
public int getWidth() {
1058
init();
1059
return width;
1060
}
1061
1062
/**
1063
* Get the height of this image
1064
*
1065
* @return The height of this image
1066
*/
1067
public int getHeight() {
1068
init();
1069
return height;
1070
}
1071
1072
/**
1073
* Get a copy of this image. This is a shallow copy and does not
1074
* duplicate image adata.
1075
*
1076
* @return The copy of this image
1077
*/
1078
public Image copy() {
1079
init();
1080
return getSubImage(0,0,width,height);
1081
}
1082
1083
/**
1084
* Get a scaled copy of this image with a uniform scale
1085
*
1086
* @param scale The scale to apply
1087
* @return The new scaled image
1088
*/
1089
public Image getScaledCopy(float scale) {
1090
init();
1091
return getScaledCopy((int) (width*scale),(int) (height*scale));
1092
}
1093
1094
/**
1095
* Get a scaled copy of this image
1096
*
1097
* @param width The width of the copy
1098
* @param height The height of the copy
1099
* @return The new scaled image
1100
*/
1101
public Image getScaledCopy(int width, int height) {
1102
init();
1103
Image image = copy();
1104
image.width = width;
1105
image.height = height;
1106
image.centerX = width / 2;
1107
image.centerY = height / 2;
1108
return image;
1109
}
1110
1111
/**
1112
* Make sure the texture cordinates are inverse on the y axis
1113
*/
1114
public void ensureInverted() {
1115
if (textureHeight > 0) {
1116
textureOffsetY = textureOffsetY + textureHeight;
1117
textureHeight = -textureHeight;
1118
}
1119
}
1120
1121
/**
1122
* Get a copy image flipped on potentially two axis
1123
*
1124
* @param flipHorizontal True if we want to flip the image horizontally
1125
* @param flipVertical True if we want to flip the image vertically
1126
* @return The flipped image instance
1127
*/
1128
public Image getFlippedCopy(boolean flipHorizontal, boolean flipVertical) {
1129
init();
1130
Image image = copy();
1131
1132
if (flipHorizontal) {
1133
image.textureOffsetX = textureOffsetX + textureWidth;
1134
image.textureWidth = -textureWidth;
1135
}
1136
if (flipVertical) {
1137
image.textureOffsetY = textureOffsetY + textureHeight;
1138
image.textureHeight = -textureHeight;
1139
}
1140
1141
return image;
1142
}
1143
1144
/**
1145
* End the use of this sprite sheet and release the lock.
1146
*
1147
* @see #startUse
1148
*/
1149
public void endUse() {
1150
if (inUse != this) {
1151
throw new RuntimeException("The sprite sheet is not currently in use");
1152
}
1153
inUse = null;
1154
GL.glEnd();
1155
}
1156
1157
/**
1158
* Start using this sheet. This method can be used for optimal rendering of a collection
1159
* of sprites from a single sprite sheet. First, startUse(). Then render each sprite by
1160
* calling renderInUse(). Finally, endUse(). Between start and end there can be no rendering
1161
* of other sprites since the rendering is locked for this sprite sheet.
1162
*/
1163
public void startUse() {
1164
if (inUse != null) {
1165
throw new RuntimeException("Attempt to start use of a sprite sheet before ending use with another - see endUse()");
1166
}
1167
inUse = this;
1168
init();
1169
1170
Color.white.bind();
1171
texture.bind();
1172
GL.glBegin(SGL.GL_QUADS);
1173
}
1174
1175
/**
1176
* @see java.lang.Object#toString()
1177
*/
1178
public String toString() {
1179
init();
1180
1181
return "[Image "+ref+" "+width+"x"+height+" "+textureOffsetX+","+textureOffsetY+","+textureWidth+","+textureHeight+"]";
1182
}
1183
1184
/**
1185
* Get the OpenGL texture holding this image
1186
*
1187
* @return The OpenGL texture holding this image
1188
*/
1189
public Texture getTexture() {
1190
return texture;
1191
}
1192
1193
/**
1194
* Set the texture used by this image
1195
*
1196
* @param texture The texture used by this image
1197
*/
1198
public void setTexture(Texture texture) {
1199
this.texture = texture;
1200
reinit();
1201
}
1202
1203
/**
1204
* Translate an unsigned int into a signed integer
1205
*
1206
* @param b The byte to convert
1207
* @return The integer value represented by the byte
1208
*/
1209
private int translate(byte b) {
1210
if (b < 0) {
1211
return 256 + b;
1212
}
1213
1214
return b;
1215
}
1216
1217
/**
1218
* Get the colour of a pixel at a specified location in this image
1219
*
1220
* @param x The x coordinate of the pixel
1221
* @param y The y coordinate of the pixel
1222
* @return The Color of the pixel at the specified location
1223
*/
1224
public Color getColor(int x, int y) {
1225
if (pixelData == null) {
1226
pixelData = texture.getTextureData();
1227
}
1228
1229
int xo = (int) (textureOffsetX * texture.getTextureWidth());
1230
int yo = (int) (textureOffsetY * texture.getTextureHeight());
1231
1232
if (textureWidth < 0) {
1233
x = xo - x;
1234
} else {
1235
x = xo + x;
1236
}
1237
1238
if (textureHeight < 0) {
1239
y = yo - y;
1240
} else {
1241
y = yo + y;
1242
}
1243
1244
int offset = x + (y * texture.getTextureWidth());
1245
offset *= texture.hasAlpha() ? 4 : 3;
1246
1247
if (texture.hasAlpha()) {
1248
return new Color(translate(pixelData[offset]),translate(pixelData[offset+1]),
1249
translate(pixelData[offset+2]),translate(pixelData[offset+3]));
1250
} else {
1251
return new Color(translate(pixelData[offset]),translate(pixelData[offset+1]),
1252
translate(pixelData[offset+2]));
1253
}
1254
}
1255
1256
/**
1257
* Check if this image has been destroyed
1258
*
1259
* @return True if this image has been destroyed
1260
*/
1261
public boolean isDestroyed() {
1262
return destroyed;
1263
}
1264
1265
/**
1266
* Destroy the image and release any native resources.
1267
* Calls on a destroyed image have undefined results
1268
*
1269
* @throws SlickException Indicates a failure to release resources on the graphics card
1270
*/
1271
public void destroy() throws SlickException {
1272
if (isDestroyed()) {
1273
return;
1274
}
1275
1276
destroyed = true;
1277
texture.release();
1278
GraphicsFactory.releaseGraphicsForImage(this);
1279
}
1280
1281
/**
1282
* Flush the current pixel data to force a re-read next update
1283
*/
1284
public void flushPixelData() {
1285
pixelData = null;
1286
}
1287
}
1288
1289