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