2 * Sixth 3D engine. Copyright ©2012-2017, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 3 of the GNU Lesser General Public License
6 * or later as published by the Free Software Foundation.
10 package eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base;
12 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
13 import eu.svjatoslav.sixth.e3d.geometry.Transform;
14 import eu.svjatoslav.sixth.e3d.geometry.TransformPipe;
15 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
16 import eu.svjatoslav.sixth.e3d.gui.UserRelativityTracker;
17 import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController;
18 import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
19 import eu.svjatoslav.sixth.e3d.renderer.raster.RenderAggregator;
20 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractShape;
21 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line.Line;
22 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon;
23 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.texturedpolygon.TexturedPolygon;
24 import eu.svjatoslav.sixth.e3d.renderer.raster.slicer.Slicer;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.stream.Collectors;
31 * In order to get perspective correct textures, large textured polygons are
32 * sliced into smaller ones.
35 public class AbstractCompositeShape extends AbstractShape {
36 private final List<SubShape> originalSubShapes = new ArrayList<>();
37 private final UserRelativityTracker relativityTracker;
38 double currentSliceFactor = 5;
39 private List<AbstractShape> renderedSubShapes = new ArrayList<>();
40 private boolean slicingOutdated = true;
41 private Transform transform;
43 public AbstractCompositeShape() {
44 this(new Transform());
47 public AbstractCompositeShape(final Point3D location) {
48 this(new Transform(location));
51 public AbstractCompositeShape(final Transform transform) {
52 this.transform = transform;
53 relativityTracker = new UserRelativityTracker();
56 public void addShape(final AbstractShape shape) {
57 addShape(shape, null);
60 public void addShape(final AbstractShape shape, final String groupId) {
61 final SubShape subShape = new SubShape(shape);
62 subShape.setGroup(groupId);
63 subShape.setVisible(true);
64 originalSubShapes.add(subShape);
65 slicingOutdated = true;
69 * This method should be overridden by anyone wanting to customize shape
70 * before it is rendered.
72 public void beforeTransformHook(final TransformPipe transformPipe,
73 final RenderingContext context) {
76 public Point3D getLocation() {
77 return transform.getTranslation();
80 public List<SubShape> getOriginalSubShapes() {
81 return originalSubShapes;
84 public UserRelativityTracker getRelativityTracker() {
85 return relativityTracker;
88 public void hideGroup(final String groupIdentifier) {
89 originalSubShapes.stream().filter(subShape -> subShape.matchesGroup(groupIdentifier)).forEach(subShape -> {
90 subShape.setVisible(false);
91 slicingOutdated = true;
95 private boolean isReslicingNeeded(double sliceFactor1, double sliceFactor2) {
100 if (sliceFactor1 > sliceFactor2) {
101 final double tmp = sliceFactor1;
102 sliceFactor1 = sliceFactor2;
106 return (sliceFactor2 / sliceFactor1) > 1.5d;
110 public void removeGroup(final String groupIdentifier) {
111 final java.util.Iterator<SubShape> iterator = originalSubShapes
114 while (iterator.hasNext()) {
115 final SubShape subShape = iterator.next();
116 if (subShape.matchesGroup(groupIdentifier)) {
118 slicingOutdated = true;
123 public List<SubShape> getGroup(final String groupIdentifier) {
124 return originalSubShapes.stream().filter(
125 subShape -> subShape.matchesGroup(groupIdentifier))
126 .collect(Collectors.toList());
129 private void resliceIfNeeded() {
131 final double proposedSliceFactor = relativityTracker
132 .proposeSliceFactor();
134 if (isReslicingNeeded(proposedSliceFactor, currentSliceFactor)) {
135 currentSliceFactor = proposedSliceFactor;
141 * Paint solid elements of this composite shape into given color.
143 public void setColor(final Color color) {
144 for (final SubShape subShape : getOriginalSubShapes()) {
145 final AbstractShape shape = subShape.getShape();
147 if (shape instanceof SolidPolygon)
148 ((SolidPolygon) shape).setColor(color);
150 if (shape instanceof Line)
151 ((Line) shape).color = color;
155 public void setGroupForUngrouped(final String groupIdentifier) {
156 originalSubShapes.stream().filter(subShape -> subShape.isUngrouped()).forEach(subShape -> subShape.setGroup(groupIdentifier));
160 public void setMouseInteractionController(
161 final MouseInteractionController mouseInteractionController) {
162 super.setMouseInteractionController(mouseInteractionController);
164 for (final SubShape subShape : originalSubShapes)
165 subShape.getShape().setMouseInteractionController(
166 mouseInteractionController);
168 slicingOutdated = true;
172 public void setTransform(final Transform transform) {
173 this.transform = transform;
176 public void showGroup(final String groupIdentifier) {
177 originalSubShapes.stream().filter(subShape -> subShape.matchesGroup(groupIdentifier)).forEach(subShape -> {
178 subShape.setVisible(true);
179 slicingOutdated = true;
183 private void slice() {
184 slicingOutdated = false;
186 final List<AbstractShape> result = new ArrayList<>();
188 final Slicer slicer = new Slicer(currentSliceFactor);
189 originalSubShapes.stream().filter(subShape -> subShape.isVisible()).forEach(subShape -> {
190 if (subShape.getShape() instanceof TexturedPolygon)
191 slicer.slice((TexturedPolygon) subShape.getShape());
193 result.add(subShape.getShape());
196 result.addAll(slicer.getResult());
198 renderedSubShapes = result;
202 public void transform(final TransformPipe transformPipe,
203 final RenderAggregator aggregator, final RenderingContext context) {
205 // add current composite shape transform to the end of the transform
207 transformPipe.addTransform(transform);
209 relativityTracker.analyze(transformPipe, context);
211 beforeTransformHook(transformPipe, context);
213 // hack, to get somewhat perspective correct textures
216 // transform rendered subshapes
217 for (final AbstractShape shape : renderedSubShapes)
218 shape.transform(transformPipe, aggregator, context);
220 transformPipe.dropTransform();