Fixed git clone URL
[sixth-3d.git] / src / main / java / eu / svjatoslav / sixth / e3d / renderer / raster / shapes / basic / ForwardOrientedTexture.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.shapes.basic;
6
7 import eu.svjatoslav.sixth.e3d.geometry.Point2D;
8 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
9 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
10 import eu.svjatoslav.sixth.e3d.math.Vertex;
11 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractCoordinateShape;
12 import eu.svjatoslav.sixth.e3d.renderer.raster.texture.Texture;
13 import eu.svjatoslav.sixth.e3d.renderer.raster.texture.TextureBitmap;
14
15 /**
16  * Texture object that is always oriented towards the viewer.
17  */
18 public class ForwardOrientedTexture extends AbstractCoordinateShape {
19
20     private static final double SCALE_MULTIPLIER = 0.005;
21     public final Texture texture;
22
23     /**
24      * Scale of the texture object.
25      * <p>
26      * Object rendered visible size on the screen depends on underlying texture size and scale.
27      * <p>
28      * 0 means that object will be infinitely small.
29      * 1 in recommended value to maintain sharpness of the texture as seen by the viewer.
30      */
31     private double scale;
32
33     public ForwardOrientedTexture(final Point3D point, final double scale,
34                                   final Texture texture) {
35         super(new Vertex(point));
36         this.texture = texture;
37         setScale(scale);
38     }
39
40     /**
41      * Paint the texture on the screen (targetRenderingArea)
42      *
43      * @param targetRenderingArea the screen to paint on
44      */
45     @Override
46     public void paint(final RenderingContext targetRenderingArea) {
47
48         // distance from camera/viewer to center of the texture
49         final double z = coordinates[0].transformedCoordinate.z;
50
51         // compute forward oriented texture visible distance from center
52         final double visibleHorizontalDistanceFromCenter = (targetRenderingArea.width
53                 * scale * texture.primaryBitmap.width) / z;
54
55         final double visibleVerticalDistanceFromCenter = (targetRenderingArea.width
56                 * scale * texture.primaryBitmap.height) / z;
57
58         // compute visible pixel density, and get appropriate bitmap
59         final double zoom = (visibleHorizontalDistanceFromCenter * 2)
60                 / texture.primaryBitmap.width;
61
62         final TextureBitmap textureBitmap = texture.getZoomedBitmap(zoom);
63
64         final Point2D onScreenCoordinate = coordinates[0].onScreenCoordinate;
65
66         // compute Y
67         final int onScreenUncappedYStart = (int) (onScreenCoordinate.y - visibleVerticalDistanceFromCenter);
68         final int onScreenUncappedYEnd = (int) (onScreenCoordinate.y + visibleVerticalDistanceFromCenter);
69         final int onScreenUncappedHeight = onScreenUncappedYEnd - onScreenUncappedYStart;
70
71         int onScreenCappedYStart = onScreenUncappedYStart;
72         int onScreenCappedYEnd = onScreenUncappedYEnd;
73
74         // cap Y to upper screen border
75         if (onScreenCappedYStart < 0)
76             onScreenCappedYStart = 0;
77
78         // cap Y to lower screen border
79         if (onScreenCappedYEnd > targetRenderingArea.height)
80             onScreenCappedYEnd = targetRenderingArea.height;
81
82         // compute X
83         final int onScreenUncappedXStart = (int) (onScreenCoordinate.x - visibleHorizontalDistanceFromCenter);
84         final int onScreenUncappedXEnd = (int) (onScreenCoordinate.x + visibleHorizontalDistanceFromCenter);
85         final int onScreenUncappedWidth = onScreenUncappedXEnd - onScreenUncappedXStart;
86
87         // cap X to left screen border
88         int onScreenCappedXStart = onScreenUncappedXStart;
89         if (onScreenCappedXStart < 0)
90             onScreenCappedXStart = 0;
91
92         // cap X to right screen border
93         int onScreenCappedXEnd = onScreenUncappedXEnd;
94         if (onScreenCappedXEnd > targetRenderingArea.width)
95             onScreenCappedXEnd = targetRenderingArea.width;
96
97         final byte[] targetRenderingAreaBytes = targetRenderingArea.pixels;
98
99         final int textureWidth = textureBitmap.width;
100
101         for (int y = onScreenCappedYStart; y < onScreenCappedYEnd; y++) {
102
103             final int sourceBitmapScanlinePixel = ((textureBitmap.height * (y - onScreenUncappedYStart)) / onScreenUncappedHeight)
104                     * textureWidth;
105
106             int targetRenderingAreaOffset = ((y * targetRenderingArea.width) + onScreenCappedXStart) * 4;
107
108             for (int x = onScreenCappedXStart; x < onScreenCappedXEnd; x++) {
109
110                 final int sourceBitmapPixelAddress = (sourceBitmapScanlinePixel + ((textureWidth * (x - onScreenUncappedXStart)) / onScreenUncappedWidth)) * 4;
111
112                 textureBitmap.drawPixel(sourceBitmapPixelAddress, targetRenderingAreaBytes, targetRenderingAreaOffset);
113
114                 targetRenderingAreaOffset += 4;
115             }
116         }
117     }
118
119     /**
120      * Set the scale of the texture
121      *
122      * @param scale the scale of the texture
123      */
124     public void setScale(final double scale) {
125         this.scale = scale * SCALE_MULTIPLIER;
126     }
127
128     public Point3D getLocation() {
129         return coordinates[0].coordinate;
130     }
131
132 }