fe1e30482d1aa04a960f7a956295004e955b82b8
[sixth-3d.git] / src / main / java / eu / svjatoslav / sixth / e3d / renderer / raster / texture / TextureBitmap.java
1 /*
2  * Sixth 3D engine. Author: Svjatoslav Agejenko. 
3  * This project is released under Creative Commons Zero (CC0) license.
4  */
5 package eu.svjatoslav.sixth.e3d.renderer.raster.texture;
6
7 import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
8
9 public class TextureBitmap {
10
11     /**
12      * Byte order: Alpha, Blue, Green, Red
13      */
14     public final byte[] bytes;
15
16     public final int width;
17
18     public final int height;
19
20     public double multiplicationFactor;
21
22     public TextureBitmap(final int width, final int height, final byte[] bytes,
23                          final double multiplicationFactor) {
24
25         this.width = width;
26         this.height = height;
27         this.bytes = bytes;
28         this.multiplicationFactor = multiplicationFactor;
29     }
30
31     public TextureBitmap(final int width, final int height,
32                          final double multiplicationFactor) {
33
34         this(width, height, new byte[width * height * 4], multiplicationFactor);
35     }
36
37     /**
38      * Transfer (render) one pixel from current {@link TextureBitmap} to target raster bitmap.
39      *
40      * @param sourceBitmapPixelAddress Pixel address within current {@link TextureBitmap} as indicated by its offset.
41      * @param targetBitmap Bitmap of the target image where pixel should be rendered to.
42      * @param targetBitmapPixelAddress Pixel location within target image where pixel should be rendered to.
43      */
44     public void drawPixel(int sourceBitmapPixelAddress,
45                           final byte[] targetBitmap, int targetBitmapPixelAddress) {
46
47         final int textureAlpha = bytes[sourceBitmapPixelAddress] & 0xff;
48
49         if (textureAlpha == 0)
50             return;
51
52         if (textureAlpha == 255) {
53             // skip reading of background for fully opaque pixels
54             targetBitmap[targetBitmapPixelAddress] = (byte) 255;
55
56             targetBitmapPixelAddress++;
57             sourceBitmapPixelAddress++;
58             targetBitmap[targetBitmapPixelAddress] = bytes[sourceBitmapPixelAddress];
59
60             targetBitmapPixelAddress++;
61             sourceBitmapPixelAddress++;
62             targetBitmap[targetBitmapPixelAddress] = bytes[sourceBitmapPixelAddress];
63
64             targetBitmapPixelAddress++;
65             sourceBitmapPixelAddress++;
66             targetBitmap[targetBitmapPixelAddress] = bytes[sourceBitmapPixelAddress];
67             return;
68         }
69
70         final int backgroundAlpha = 255 - textureAlpha;
71         sourceBitmapPixelAddress++;
72
73         targetBitmap[targetBitmapPixelAddress] = (byte) 255;
74         targetBitmapPixelAddress++;
75
76         targetBitmap[targetBitmapPixelAddress] = (byte) ((((targetBitmap[targetBitmapPixelAddress] & 0xff) * backgroundAlpha) + ((bytes[sourceBitmapPixelAddress] & 0xff) * textureAlpha)) / 256);
77         sourceBitmapPixelAddress++;
78         targetBitmapPixelAddress++;
79
80         targetBitmap[targetBitmapPixelAddress] = (byte) ((((targetBitmap[targetBitmapPixelAddress] & 0xff) * backgroundAlpha) + ((bytes[sourceBitmapPixelAddress] & 0xff) * textureAlpha)) / 256);
81         sourceBitmapPixelAddress++;
82         targetBitmapPixelAddress++;
83
84         targetBitmap[targetBitmapPixelAddress] = (byte) ((((targetBitmap[targetBitmapPixelAddress] & 0xff) * backgroundAlpha) + ((bytes[sourceBitmapPixelAddress] & 0xff) * textureAlpha)) / 256);
85     }
86
87     public void drawPixel(final int x, final int y, final Color color) {
88         int address = getAddress(x, y);
89
90         bytes[address] = (byte) color.a;
91
92         address++;
93         bytes[address] = (byte) color.b;
94
95         address++;
96         bytes[address] = (byte) color.g;
97
98         address++;
99         bytes[address] = (byte) color.r;
100     }
101
102     public void drawRectangle(int x1, final int y1, int x2, final int y2,
103                               final Color color) {
104
105         if (x1 > x2) {
106             final int tmp = x1;
107             x1 = x2;
108             x2 = tmp;
109         }
110
111         if (y1 > y2) {
112             final int tmp = x1;
113             x1 = x2;
114             x2 = tmp;
115         }
116
117         for (int y = y1; y < y2; y++)
118             for (int x = x1; x < x2; x++)
119                 drawPixel(x, y, color);
120     }
121
122     public void fillColor(final Color color) {
123         int address = 0;
124         while (address < bytes.length) {
125             bytes[address] = (byte) color.a;
126             address++;
127
128             bytes[address] = (byte) color.b;
129             address++;
130
131             bytes[address] = (byte) color.g;
132             address++;
133
134             bytes[address] = (byte) color.r;
135             address++;
136         }
137     }
138
139     public int getAddress(int x, int y) {
140         if (x < 0)
141             x = 0;
142
143         if (x >= width)
144             x = width - 1;
145
146         if (y < 0)
147             y = 0;
148
149         if (y >= height)
150             y = height - 1;
151
152         return ((y * width) + x) * 4;
153     }
154 }