1 package org.newdawn.slick;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.nio.IntBuffer;
6
7 import org.lwjgl.BufferUtils;
8 import org.newdawn.slick.opengl.EmptyImageData;
9 import org.newdawn.slick.opengl.ImageData;
10 import org.newdawn.slick.opengl.InternalTextureLoader;
11 import org.newdawn.slick.opengl.Texture;
12 import org.newdawn.slick.opengl.TextureImpl;
13 import org.newdawn.slick.opengl.pbuffer.GraphicsFactory;
14 import org.newdawn.slick.opengl.renderer.Renderer;
15 import org.newdawn.slick.opengl.renderer.SGL;
16 import org.newdawn.slick.util.FastTrig;
17 import org.newdawn.slick.util.Log;
18
19 import javax.annotation.Nonnull;
20 import javax.annotation.Nullable;
21
22
23
24
25
26
27
28
29 public class Image implements Renderable {
30
31
32
33
34
35
36
37
38
39 public static final int getMaxSingleImageSize() {
40 IntBuffer buffer = BufferUtils.createIntBuffer(16);
41 GL.glGetInteger(SGL.GL_MAX_TEXTURE_SIZE, buffer);
42 return buffer.get(0);
43 }
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 @Nonnull
62 private static Image createOffscreenImage(int width, int height, int filter) throws SlickException {
63
64
65
66 Image i = new Image();
67 i.width = width;
68 i.height = height;
69 i.filter = filter;
70 i.inited = true;
71 i.getGraphics();
72 return i;
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 @Nonnull
90 public static Image createOffscreenImage(int width, int height) throws SlickException {
91 return createOffscreenImage(width, height, Image.FILTER_LINEAR);
92 }
93
94
95 private static final int TOP_LEFT = 0;
96
97 private static final int TOP_RIGHT = 1;
98
99 private static final int BOTTOM_RIGHT = 2;
100
101 private static final int BOTTOM_LEFT = 3;
102
103
104 private static final SGL GL = Renderer.get();
105
106
107 @Nullable
108 private static Texture inUse;
109
110 private static final int FILTER_LINEAR = SGL.GL_LINEAR;
111
112 public static final int FILTER_NEAREST = SGL.GL_NEAREST;
113
114
115 @Nullable
116 private Texture texture;
117
118 private int width;
119
120 private int height;
121
122 private float textureWidth;
123
124 private float textureHeight;
125
126 private float textureOffsetX;
127
128 private float textureOffsetY;
129
130 private float angle;
131
132 private float alpha = 1.0f;
133
134 private String ref;
135
136 private boolean inited = false;
137
138 @Nullable
139 private byte[] pixelData;
140
141 private boolean destroyed;
142
143
144 private float centerX;
145
146 private float centerY;
147
148
149 private String name;
150
151
152 private Color[] corners;
153
154 private int filter = FILTER_LINEAR;
155
156
157
158
159
160
161 Image(@Nonnull Image other) {
162 this.width = other.getWidth();
163 this.height = other.getHeight();
164 this.texture = other.texture;
165 this.textureWidth = other.textureWidth;
166 this.textureHeight = other.textureHeight;
167 this.ref = other.ref;
168 this.textureOffsetX = other.textureOffsetX;
169 this.textureOffsetY = other.textureOffsetY;
170
171 centerX = width / 2f;
172 centerY = height / 2f;
173 inited = true;
174 }
175
176
177
178
179 Image() {
180 }
181
182
183
184
185
186
187
188 public Image(@Nonnull Texture texture) {
189 this.texture = texture;
190 ref = texture.toString();
191 clampTexture();
192 }
193
194
195
196
197
198
199
200
201
202 public Image(String ref) throws SlickException {
203 this(ref, false);
204 }
205
206
207
208
209
210
211
212
213 public Image(String ref, Color trans) throws SlickException {
214 this(ref, false, FILTER_LINEAR, trans);
215 }
216
217
218
219
220
221
222
223
224
225 public Image(String ref, int filter) throws SlickException {
226 this(ref, false, filter);
227 }
228
229
230
231
232
233
234
235
236 private Image(String ref, boolean flipped) throws SlickException {
237 this(ref, flipped, FILTER_LINEAR);
238 }
239
240
241
242
243
244
245
246
247
248 private Image(String ref, boolean flipped, int filter) throws SlickException {
249 this(ref, flipped, filter, null);
250 }
251
252
253
254
255
256
257
258
259
260
261 public Image(String ref, boolean flipped, int f, @Nullable Color transparent) throws SlickException {
262 this.filter = f;
263 try {
264 this.ref = ref;
265 int[] trans = null;
266 if (transparent != null) {
267 trans = new int[3];
268 trans[0] = (int) (transparent.r * 255);
269 trans[1] = (int) (transparent.g * 255);
270 trans[2] = (int) (transparent.b * 255);
271 }
272 texture = InternalTextureLoader.get().getTexture(ref, flipped, filter, trans);
273 } catch (IOException e) {
274 Log.error(e);
275 throw new SlickException("Failed to load image from: "+ref, e);
276 }
277 }
278
279
280
281
282
283
284
285 public void setFilter(int f) {
286 this.filter = f;
287
288 texture.bind();
289 GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_MIN_FILTER, filter);
290 GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_MAG_FILTER, filter);
291 }
292
293
294
295
296
297
298
299
300 public Image(int width, int height) {
301 this(width, height, FILTER_NEAREST);
302 }
303
304
305
306
307
308
309
310
311
312 private Image(int width, int height, int f) {
313 this(new EmptyImageData(width, height), f);
314 }
315
316
317
318
319
320
321
322
323
324 public Image(@Nonnull InputStream in, String ref, boolean flipped) throws SlickException {
325 this(in, ref, flipped, FILTER_LINEAR);
326 }
327
328
329
330
331
332
333
334
335
336
337 private Image(@Nonnull InputStream in, String ref, boolean flipped, int filter) throws SlickException {
338 load(in, ref, flipped, filter, null);
339 }
340
341
342
343
344
345
346 Image(ImageBuffer buffer) {
347 this(buffer, FILTER_LINEAR);
348 TextureImpl.bindNone();
349 }
350
351
352
353
354
355
356
357 Image(ImageBuffer buffer, int filter) {
358 this((ImageData) buffer, filter);
359 TextureImpl.bindNone();
360 }
361
362
363
364
365
366
367 public Image(@Nonnull ImageData data) {
368 this(data, FILTER_LINEAR);
369 }
370
371
372
373
374
375
376
377 private Image(@Nonnull ImageData data, int f) {
378 try {
379 this.filter = f;
380 texture = InternalTextureLoader.get().getTexture(data, this.filter);
381 ref = texture.toString();
382 } catch (IOException e) {
383 Log.error(e);
384 }
385 }
386
387
388
389
390
391
392 public int getFilter() {
393 return filter;
394 }
395
396
397
398
399
400
401
402 public String getResourceReference() {
403 return ref;
404 }
405
406
407
408
409
410
411
412
413
414 public void setImageColor(float r, float g, float b, float a) {
415 setColor(TOP_LEFT, r, g, b, a);
416 setColor(TOP_RIGHT, r, g, b, a);
417 setColor(BOTTOM_LEFT, r, g, b, a);
418 setColor(BOTTOM_RIGHT, r, g, b, a);
419 }
420
421
422
423
424
425
426
427
428 public void setImageColor(float r, float g, float b) {
429 setColor(TOP_LEFT, r, g, b);
430 setColor(TOP_RIGHT, r, g, b);
431 setColor(BOTTOM_LEFT, r, g, b);
432 setColor(BOTTOM_RIGHT, r, g, b);
433 }
434
435
436
437
438
439
440
441
442
443
444
445 void setColor(int corner, float r, float g, float b, float a) {
446 if (corners == null) {
447 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)};
448 }
449
450 corners[corner].r = r;
451 corners[corner].g = g;
452 corners[corner].b = b;
453 corners[corner].a = a;
454 }
455
456
457
458
459
460
461
462
463
464
465 void setColor(int corner, float r, float g, float b) {
466 if (corners == null) {
467 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)};
468 }
469
470 corners[corner].r = r;
471 corners[corner].g = g;
472 corners[corner].b = b;
473 }
474
475
476
477
478 void clampTexture() {
479 if (GL.canTextureMirrorClamp()) {
480 GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_S, SGL.GL_MIRROR_CLAMP_TO_EDGE_EXT);
481 GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_T, SGL.GL_MIRROR_CLAMP_TO_EDGE_EXT);
482 } else {
483 GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_S, SGL.GL_CLAMP);
484 GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_T, SGL.GL_CLAMP);
485 }
486 }
487
488
489
490
491
492
493
494 public void setName(String name) {
495 this.name = name;
496 }
497
498
499
500
501
502
503 public String getName() {
504 return name;
505 }
506
507
508
509
510
511
512
513 Graphics getGraphics() throws SlickException {
514 return GraphicsFactory.getGraphicsForImage(this);
515 }
516
517
518
519
520
521
522
523
524
525
526
527 private void load(@Nonnull InputStream in, String ref, boolean flipped, int f, @Nullable Color transparent) throws SlickException {
528 this.filter = f;
529
530 try {
531 this.ref = ref;
532 int[] trans = null;
533 if (transparent != null) {
534 trans = new int[3];
535 trans[0] = (int) (transparent.r * 255);
536 trans[1] = (int) (transparent.g * 255);
537 trans[2] = (int) (transparent.b * 255);
538 }
539 texture = InternalTextureLoader.get().getTexture(in, ref, flipped, filter, trans);
540 } catch (IOException e) {
541 Log.error(e);
542 throw new SlickException("Failed to load image from: "+ref, e);
543 }
544 }
545
546
547
548
549 public void bind() {
550 texture.bind();
551 }
552
553
554
555
556 void reinit() {
557 inited = false;
558 flushPixelData();
559 init();
560 }
561
562
563
564
565 final void init() {
566 if (inited) {
567 return;
568 }
569
570 inited = true;
571 if (texture != null) {
572 width = texture.getImageWidth();
573 height = texture.getImageHeight();
574 textureOffsetX = 0;
575 textureOffsetY = 0;
576 textureWidth = texture.getWidth();
577 textureHeight = texture.getHeight();
578 }
579
580 initImpl();
581
582 centerX = width / 2f;
583 centerY = height / 2f;
584 }
585
586
587
588
589 void initImpl() {
590
591 }
592
593
594
595
596 public void draw() {
597 draw(0,0);
598 }
599
600
601
602
603
604
605
606 public void drawCentered(float x, float y) {
607 draw(x-(getWidth()/2f),y-(getHeight()/2f));
608 }
609
610
611
612
613
614
615
616 public void draw(float x, float y) {
617 init();
618 draw(x,y,width,height);
619 }
620
621
622
623
624
625
626
627
628 public void draw(float x, float y, Color filter) {
629 init();
630 draw(x,y,width,height, filter);
631 }
632
633
634
635
636
637
638
639
640
641
642
643
644
645 void drawEmbedded(float x, float y, float width, float height, float rotation) {
646 if (rotation==0) {
647 drawEmbedded(x, y, width, height);
648 return;
649 }
650 init();
651 float scaleX = width/this.width;
652 float scaleY = height/this.height;
653
654 float cx = getCenterOfRotationX()*scaleX;
655 float cy = getCenterOfRotationY()*scaleY;
656
657 float p1x = -cx;
658 float p1y = -cy;
659 float p2x = width - cx;
660 float p2y = -cy;
661 float p3x = width - cx;
662 float p3y = height - cy;
663 float p4x = -cx;
664 float p4y = height - cy;
665
666 double rad = Math.toRadians(rotation);
667 final float cos = (float) FastTrig.cos(rad);
668 final float sin = (float) FastTrig.sin(rad);
669
670 float tx = getTextureOffsetX();
671 float ty = getTextureOffsetY();
672 float tw = getTextureWidth();
673 float th = getTextureHeight();
674
675 float x1 = (cos * p1x - sin * p1y) + cx;
676 float y1 = (sin * p1x + cos * p1y) + cy;
677 float x2 = (cos * p4x - sin * p4y) + cx;
678 float y2 = (sin * p4x + cos * p4y) + cy;
679 float x3 = (cos * p3x - sin * p3y) + cx;
680 float y3 = (sin * p3x + cos * p3y) + cy;
681 float x4 = (cos * p2x - sin * p2y) + cx;
682 float y4 = (sin * p2x + cos * p2y) + cy;
683 if (corners == null) {
684 GL.glTexCoord2f(tx, ty);
685 GL.glVertex3f(x+x1, y+y1, 0);
686 GL.glTexCoord2f(tx, ty + th);
687 GL.glVertex3f(x+x2, y+y2, 0);
688 GL.glTexCoord2f(tx + tw, ty + th);
689 GL.glVertex3f(x+x3, y+y3, 0);
690 GL.glTexCoord2f(tx + tw, ty);
691 GL.glVertex3f(x+x4, y+y4, 0);
692 } else {
693 corners[TOP_LEFT].bind();
694 GL.glTexCoord2f(tx, ty);
695 GL.glVertex3f(x+x1, y+y1, 0);
696 corners[BOTTOM_LEFT].bind();
697 GL.glTexCoord2f(tx, ty + th);
698 GL.glVertex3f(x+x2, y+y2, 0);
699 corners[BOTTOM_RIGHT].bind();
700 GL.glTexCoord2f(tx + tw, ty + th);
701 GL.glVertex3f(x+x3, y+y3, 0);
702 corners[TOP_RIGHT].bind();
703 GL.glTexCoord2f(tx + tw, ty);
704 GL.glVertex3f(x+x4, y+y4, 0);
705 }
706 }
707
708
709
710
711
712
713
714 public void drawEmbedded(float x,float y) {
715 drawEmbedded(x, y, getWidth(), getHeight());
716 }
717
718
719
720
721
722
723
724
725
726 public void drawEmbedded(float x,float y,float width,float height) {
727 init();
728
729 if (corners == null) {
730 GL.glTexCoord2f(textureOffsetX, textureOffsetY);
731 GL.glVertex3f(x, y, 0);
732 GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
733 GL.glVertex3f(x, y + height, 0);
734 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
735 + textureHeight);
736 GL.glVertex3f(x + width, y + height, 0);
737 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
738 GL.glVertex3f(x + width, y, 0);
739 } else {
740 corners[TOP_LEFT].bind();
741 GL.glTexCoord2f(textureOffsetX, textureOffsetY);
742 GL.glVertex3f(x, y, 0);
743 corners[BOTTOM_LEFT].bind();
744 GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
745 GL.glVertex3f(x, y + height, 0);
746 corners[BOTTOM_RIGHT].bind();
747 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
748 + textureHeight);
749 GL.glVertex3f(x + width, y + height, 0);
750 corners[TOP_RIGHT].bind();
751 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
752 GL.glVertex3f(x + width, y, 0);
753 }
754 }
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769 void drawEmbedded(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) {
770 drawEmbedded(x,y,x2,y2,srcx,srcy,srcx2,srcy2,null);
771 }
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787 void drawEmbedded(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, @Nullable Color filter) {
788 init();
789 if (filter != null) {
790 filter.bind();
791 }
792
793 float mywidth = x2 - x;
794 float myheight = y2 - y;
795 float texwidth = srcx2 - srcx;
796 float texheight = srcy2 - srcy;
797
798 float newTextureOffsetX = (((srcx) / (width)) * textureWidth)
799 + textureOffsetX;
800 float newTextureOffsetY = (((srcy) / (height)) * textureHeight)
801 + textureOffsetY;
802 float newTextureWidth = ((texwidth) / (width))
803 * textureWidth;
804 float newTextureHeight = ((texheight) / (height))
805 * textureHeight;
806
807 GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY);
808 GL.glVertex3f(x,y, 0.0f);
809 GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY
810 + newTextureHeight);
811 GL.glVertex3f(x,(y + myheight), 0.0f);
812 GL.glTexCoord2f(newTextureOffsetX + newTextureWidth,
813 newTextureOffsetY + newTextureHeight);
814 GL.glVertex3f((x + mywidth),(y + myheight), 0.0f);
815 GL.glTexCoord2f(newTextureOffsetX + newTextureWidth,
816 newTextureOffsetY);
817 GL.glVertex3f((x + mywidth),y, 0.0f);
818 }
819
820
821
822
823
824
825
826 public float getTextureOffsetX() {
827 init();
828
829 return textureOffsetX;
830 }
831
832
833
834
835
836
837
838 public float getTextureOffsetY() {
839 init();
840
841 return textureOffsetY;
842 }
843
844
845
846
847
848
849
850 public float getTextureWidth() {
851 init();
852
853 return textureWidth;
854 }
855
856
857
858
859
860
861
862 public float getTextureHeight() {
863 init();
864
865 return textureHeight;
866 }
867
868
869
870
871
872
873
874
875 public void draw(float x,float y,float scale) {
876 init();
877 draw(x,y,width*scale,height*scale,Color.white);
878 }
879
880
881
882
883
884
885
886
887
888 public void draw(float x,float y,float scale,Color filter) {
889 init();
890 draw(x,y,width*scale,height*scale,filter);
891 }
892
893
894
895
896
897
898
899
900
901
902
903
904
905 void draw(float x, float y, float width, float height) {
906 init();
907 draw(x,y,width,height,Color.white);
908 }
909
910
911
912
913
914
915
916
917
918 public void drawSheared(float x,float y, float hshear, float vshear) {
919 this.drawSheared(x, y, hshear, vshear, Color.white);
920 }
921
922
923
924
925
926
927
928
929
930
931 void drawSheared(float x, float y, float hshear, float vshear, @Nullable Color filter) {
932 init();
933 if (alpha != 1) {
934 if (filter == null) {
935 filter = Color.white;
936 }
937
938 filter = new Color(filter);
939 filter.a *= alpha;
940 }
941 if (filter != null) {
942 filter.bind();
943 }
944
945 texture.bind();
946
947 GL.glTranslatef(x, y, 0);
948 if (angle != 0) {
949 GL.glTranslatef(centerX, centerY, 0.0f);
950 GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
951 GL.glTranslatef(-centerX, -centerY, 0.0f);
952 }
953
954 GL.glBegin(SGL.GL_QUADS);
955 GL.glTexCoord2f(textureOffsetX, textureOffsetY);
956 GL.glVertex3f(0, 0, 0);
957 GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
958 GL.glVertex3f(hshear, height, 0);
959 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
960 + textureHeight);
961 GL.glVertex3f(width + hshear, height + vshear, 0);
962 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
963 GL.glVertex3f(width, vshear, 0);
964 GL.glEnd();
965
966 if (angle != 0) {
967 GL.glTranslatef(centerX, centerY, 0.0f);
968 GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
969 GL.glTranslatef(-centerX, -centerY, 0.0f);
970 }
971 GL.glTranslatef(-x, -y, 0);
972 }
973
974
975
976
977
978
979
980
981
982
983 public void draw(float x,float y,float width,float height, @Nullable Color filter) {
984 init();
985 if (alpha != 1) {
986 if (filter == null) {
987 filter = Color.white;
988 }
989
990 filter = new Color(filter);
991 filter.a *= alpha;
992 }
993 if (filter != null) {
994 filter.bind();
995 }
996
997 float centerX = this.centerX * (width / (float)getWidth());
998 float centerY = this.centerY * (height / (float)getHeight());
999
1000 texture.bind();
1001
1002 GL.glTranslatef(x, y, 0);
1003 if (angle != 0) {
1004 GL.glTranslatef(centerX, centerY, 0.0f);
1005 GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
1006 GL.glTranslatef(-centerX, -centerY, 0.0f);
1007 }
1008
1009 GL.glBegin(SGL.GL_QUADS);
1010 drawEmbedded(0,0,width,height);
1011 GL.glEnd();
1012
1013 if (angle != 0) {
1014 GL.glTranslatef(centerX, centerY, 0.0f);
1015 GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
1016 GL.glTranslatef(-centerX, -centerY, 0.0f);
1017 }
1018 GL.glTranslatef(-x, -y, 0);
1019 }
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029 void drawFlash(float x, float y, float width, float height) {
1030 drawFlash(x,y,width,height,Color.white);
1031 }
1032
1033
1034
1035
1036
1037
1038
1039 public void setCenterOfRotation(float x, float y) {
1040 init();
1041 centerX = x;
1042 centerY = y;
1043 }
1044
1045
1046
1047
1048
1049
1050 float getCenterOfRotationX() {
1051 init();
1052
1053 return centerX;
1054 }
1055
1056
1057
1058
1059
1060
1061 float getCenterOfRotationY() {
1062 init();
1063
1064 return centerY;
1065 }
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 public void drawFlash(float x,float y,float width,float height, @Nonnull Color col) {
1077 init();
1078
1079 col.bind();
1080 texture.bind();
1081
1082 float centerX = this.centerX * (width / (float)getWidth());
1083 float centerY = this.centerY * (height / (float)getHeight());
1084
1085 if (GL.canSecondaryColor()) {
1086 GL.glEnable(SGL.GL_COLOR_SUM_EXT);
1087 GL.glSecondaryColor3ubEXT((byte)(col.r * 255),
1088 (byte)(col.g * 255),
1089 (byte)(col.b * 255));
1090 }
1091
1092 GL.glTexEnvi(SGL.GL_TEXTURE_ENV, SGL.GL_TEXTURE_ENV_MODE, SGL.GL_MODULATE);
1093
1094 GL.glTranslatef(x, y, 0);
1095 if (angle != 0) {
1096 GL.glTranslatef(centerX, centerY, 0.0f);
1097 GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
1098 GL.glTranslatef(-centerX, -centerY, 0.0f);
1099 }
1100
1101 GL.glBegin(SGL.GL_QUADS);
1102 drawEmbedded(0,0,width,height);
1103 GL.glEnd();
1104
1105 if (angle != 0) {
1106 GL.glTranslatef(centerX, centerY, 0.0f);
1107 GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
1108 GL.glTranslatef(-centerX, -centerY, 0.0f);
1109 }
1110 GL.glTranslatef(-x, -y, 0);
1111
1112 if (GL.canSecondaryColor()) {
1113 GL.glDisable(SGL.GL_COLOR_SUM_EXT);
1114 }
1115 }
1116
1117
1118
1119
1120
1121
1122
1123 public void drawFlash(float x,float y) {
1124 drawFlash(x,y,getWidth(),getHeight());
1125 }
1126
1127
1128
1129
1130
1131
1132
1133 public void setRotation(float angle) {
1134 this.angle = angle % 360.0f;
1135 }
1136
1137
1138
1139
1140
1141
1142
1143 public float getRotation() {
1144 return angle;
1145 }
1146
1147
1148
1149
1150
1151
1152 public float getAlpha() {
1153 return alpha;
1154 }
1155
1156
1157
1158
1159
1160
1161 public void setAlpha(float alpha) {
1162 this.alpha = alpha;
1163 }
1164
1165
1166
1167
1168
1169
1170
1171 public void rotate(float angle) {
1172 this.angle += angle;
1173 this.angle = this.angle % 360;
1174 }
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186 public void draw(float x, float y, float srcx, float srcy, float srcx2, float srcy2) {
1187 draw(x,y,x+width,y+height,srcx,srcy,srcx2,srcy2);
1188 }
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202 public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) {
1203 draw(x,y,x2,y2,srcx,srcy,srcx2,srcy2,Color.white);
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221 public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, @Nullable Color filter) {
1222 init();
1223
1224 if (alpha != 1) {
1225 if (filter == null) {
1226 filter = Color.white;
1227 }
1228
1229 filter = new Color(filter);
1230 filter.a *= alpha;
1231 }
1232 filter.bind();
1233 texture.bind();
1234
1235 float centerX = this.centerX * ((x2-x) / (float)getWidth());
1236 float centerY = this.centerY * ((y2-y) / (float)getHeight());
1237
1238 GL.glTranslatef(x, y, 0);
1239 if (angle != 0) {
1240 GL.glTranslatef(centerX, centerY, 0.0f);
1241 GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
1242 GL.glTranslatef(-centerX, -centerY, 0.0f);
1243 }
1244
1245 GL.glBegin(SGL.GL_QUADS);
1246 drawEmbedded(0,0,x2-x,y2-y,srcx,srcy,srcx2,srcy2);
1247 GL.glEnd();
1248
1249 if (angle != 0) {
1250 GL.glTranslatef(centerX, centerY, 0.0f);
1251 GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
1252 GL.glTranslatef(-centerX, -centerY, 0.0f);
1253 }
1254 GL.glTranslatef(-x, -y, 0);
1255
1256
1257
1258
1259 }
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277 public void drawWarped(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
1278 Color.white.bind();
1279 texture.bind();
1280
1281 GL.glTranslatef(x1, y1, 0);
1282 if (angle != 0) {
1283 GL.glTranslatef(centerX, centerY, 0.0f);
1284 GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
1285 GL.glTranslatef(-centerX, -centerY, 0.0f);
1286 }
1287
1288 GL.glBegin(SGL.GL_QUADS);
1289 init();
1290
1291 GL.glTexCoord2f(textureOffsetX, textureOffsetY);
1292 GL.glVertex3f(0, 0, 0);
1293 GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
1294 GL.glVertex3f(x2 - x1, y2 - y1, 0);
1295 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
1296 + textureHeight);
1297 GL.glVertex3f(x3 - x1, y3 - y1, 0);
1298 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
1299 GL.glVertex3f(x4 - x1, y4 - y1, 0);
1300 GL.glEnd();
1301
1302 if (angle != 0) {
1303 GL.glTranslatef(centerX, centerY, 0.0f);
1304 GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
1305 GL.glTranslatef(-centerX, -centerY, 0.0f);
1306 }
1307 GL.glTranslatef(-x1, -y1, 0);
1308 }
1309
1310
1311
1312
1313
1314
1315 public int getWidth() {
1316 init();
1317 return width;
1318 }
1319
1320
1321
1322
1323
1324
1325 public int getHeight() {
1326 init();
1327 return height;
1328 }
1329
1330
1331
1332
1333
1334
1335
1336
1337 @Nonnull
1338 Image copy() {
1339 init();
1340 return getScaledCopy(width,height);
1341 }
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355 @Nonnull
1356 public Image getSubImage(int x,int y,int width,int height) {
1357 init();
1358
1359 float newTextureOffsetX = ((x / (float) this.width) * textureWidth) + textureOffsetX;
1360 float newTextureOffsetY = ((y / (float) this.height) * textureHeight) + textureOffsetY;
1361 float newTextureWidth = ((width / (float) this.width) * textureWidth);
1362 float newTextureHeight = ((height / (float) this.height) * textureHeight);
1363
1364 Image sub = new Image();
1365 sub.inited = true;
1366 sub.filter = this.filter;
1367 sub.texture = this.texture;
1368 sub.ref = ref;
1369
1370 sub.textureOffsetX = newTextureOffsetX;
1371 sub.textureOffsetY = newTextureOffsetY;
1372 sub.textureWidth = newTextureWidth;
1373 sub.textureHeight = newTextureHeight;
1374
1375 sub.width = width;
1376 sub.height = height;
1377 sub.centerX = width / 2f;
1378 sub.centerY = height / 2f;
1379
1380 return sub;
1381 }
1382
1383
1384
1385
1386
1387
1388
1389 @Nonnull
1390 public Image getScaledCopy(float scale) {
1391 init();
1392 return getScaledCopy((int) (width*scale),(int) (height*scale));
1393 }
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403 @Nonnull
1404 Image getScaledCopy(int width, int height) {
1405 init();
1406 Image image = new Image();
1407 image.inited = true;
1408 image.filter = this.filter;
1409 image.texture = this.texture;
1410 image.ref = ref;
1411
1412 image.textureOffsetX = this.textureOffsetX;
1413 image.textureOffsetY = this.textureOffsetY;
1414 image.textureWidth = this.textureWidth;
1415 image.textureHeight = this.textureHeight;
1416 image.width = width;
1417 image.height = height;
1418 image.centerX = this.centerX * (width / (float)this.width);
1419 image.centerY = this.centerY * (height / (float)this.height);
1420 return image;
1421 }
1422
1423
1424
1425
1426 public void ensureInverted() {
1427 init();
1428 if (textureHeight > 0) {
1429 textureOffsetY = textureOffsetY + textureHeight;
1430 textureHeight = -textureHeight;
1431
1432
1433 }
1434 }
1435
1436
1437
1438
1439
1440
1441
1442
1443 @Nonnull
1444 public Image getFlippedCopy(boolean flipHorizontal, boolean flipVertical) {
1445 init();
1446 Image image = copy();
1447
1448 if (flipHorizontal) {
1449 image.textureOffsetX = textureOffsetX + textureWidth;
1450 image.textureWidth = -textureWidth;
1451 }
1452 if (flipVertical) {
1453 image.textureOffsetY = textureOffsetY + textureHeight;
1454 image.textureHeight = -textureHeight;
1455 }
1456
1457 return image;
1458 }
1459
1460
1461
1462
1463
1464
1465 void endUse() {
1466 if (inUse != texture) {
1467 throw new RuntimeException("The sprite sheet is not currently in use");
1468 }
1469 inUse = null;
1470 GL.glEnd();
1471 }
1472
1473
1474
1475
1476
1477
1478
1479 void startUse() {
1480 if (inUse != null) {
1481 throw new RuntimeException("Attempt to start use of a sprite sheet before ending use with another - see endUse()");
1482 }
1483 inUse = texture;
1484 init();
1485
1486 Color.white.bind();
1487 texture.bind();
1488 GL.glBegin(SGL.GL_QUADS);
1489 }
1490
1491
1492
1493
1494 @Nonnull
1495 public String toString() {
1496 init();
1497
1498 return "[Image "+ref+" "+width+"x"+height+" "+textureOffsetX+","+textureOffsetY+","+textureWidth+","+textureHeight+"]";
1499 }
1500
1501
1502
1503
1504
1505
1506 @Nullable
1507 public Texture getTexture() {
1508 return texture;
1509 }
1510
1511
1512
1513
1514
1515
1516
1517
1518 public void setTexture(@Nullable Texture texture) {
1519 if (texture!=this.texture)
1520 destroyed = false;
1521 this.texture = texture;
1522 reinit();
1523 }
1524
1525
1526
1527
1528
1529
1530
1531 private int translate(byte b) {
1532 if (b < 0) {
1533 return 256 + b;
1534 }
1535
1536 return b;
1537 }
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556 @Nonnull
1557 public Color getColor(int x, int y) {
1558 if (pixelData == null) {
1559 pixelData = texture.getTextureData();
1560 }
1561
1562 int xo = (int) (textureOffsetX * texture.getTextureWidth());
1563 int yo = (int) (textureOffsetY * texture.getTextureHeight());
1564 if (textureWidth < 0) {
1565 x = xo - x - 1;
1566 } else {
1567 x = xo + x;
1568 }
1569
1570 if (textureHeight < 0) {
1571 y = yo - y - 1;
1572 } else {
1573 y = yo + y;
1574 }
1575 int offset = x + (y * texture.getTextureWidth());
1576 offset *= texture.hasAlpha() ? 4 : 3;
1577
1578 if (texture.hasAlpha()) {
1579 return new Color(translate(pixelData[offset]),translate(pixelData[offset+1]),
1580 translate(pixelData[offset+2]),translate(pixelData[offset+3]));
1581 } else {
1582 return new Color(translate(pixelData[offset]),translate(pixelData[offset+1]),
1583 translate(pixelData[offset+2]));
1584 }
1585 }
1586
1587
1588
1589
1590
1591
1592 boolean isDestroyed() {
1593 return destroyed;
1594 }
1595
1596
1597
1598
1599
1600
1601
1602 public void destroy() {
1603 if (isDestroyed()) {
1604 return;
1605 }
1606 flushPixelData();
1607 destroyed = true;
1608 texture.release();
1609 GraphicsFactory.releaseGraphicsForImage(this);
1610 }
1611
1612
1613
1614
1615 public void flushPixelData() {
1616 pixelData = null;
1617 }
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635 void drawEmbedded(float x, float y, float width, float height, byte transform) {
1636 boolean rotate = (transform & 1) > 0;
1637 boolean flipY = ((transform & 2) > 0) ^ rotate;
1638 boolean flipX = ((transform & 4) > 0) ^ rotate;
1639
1640 if (flipX) {
1641 x+=width;
1642 width*=-1;
1643 }
1644 if (flipY) {
1645 y+=height;
1646 height*=-1;
1647 }
1648 if (!rotate)
1649 drawEmbedded(x,y,width, height);
1650 else {
1651 init();
1652 if (corners == null) {
1653 GL.glTexCoord2f(textureOffsetX + textureWidth,
1654 textureOffsetY+ textureHeight);
1655 GL.glVertex3f(x, y, 0);
1656 GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
1657 GL.glVertex3f(x, y + height, 0);
1658 GL.glTexCoord2f(textureOffsetX , textureOffsetY);
1659 GL.glVertex3f(x + width, y + height, 0);
1660 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
1661 GL.glVertex3f(x + width, y, 0);
1662 } else {
1663 corners[TOP_LEFT].bind();
1664 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
1665 + textureHeight);
1666 GL.glVertex3f(x, y, 0);
1667 corners[BOTTOM_LEFT].bind();
1668 GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
1669 GL.glVertex3f(x, y + height, 0);
1670 corners[BOTTOM_RIGHT].bind();
1671 GL.glTexCoord2f(textureOffsetX , textureOffsetY);
1672 GL.glVertex3f(x + width, y + height, 0);
1673 corners[TOP_RIGHT].bind();
1674 GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
1675 GL.glVertex3f(x + width, y, 0);
1676 }
1677 }
1678 }
1679 }