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