2 * Sixth - System for data storage, computation, exploration and interaction.
3 * Copyright ©2012-2016, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 3 of the GNU Lesser General Public License
7 * 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;
30 * In order to get perspective correct textures, large textured polygons are
31 * sliced into smaller ones.
34 public class AbstractCompositeShape extends AbstractShape {
35 private final List<SubShape> originalSubShapes = new ArrayList<>();
36 private final UserRelativityTracker relativityTracker;
37 double currentSliceFactor = 5;
38 private List<AbstractShape> renderedSubShapes = new ArrayList<>();
39 private boolean slicingOutdated = true;
40 private Transform transform;
42 public AbstractCompositeShape() {
43 this(new Transform());
46 public AbstractCompositeShape(final Point3D location) {
47 this(new Transform(location));
50 public AbstractCompositeShape(final Transform transform) {
51 this.transform = transform;
52 relativityTracker = new UserRelativityTracker();
55 public void addShape(final AbstractShape shape) {
56 addShape(shape, null);
59 public void addShape(final AbstractShape shape, final String groupId) {
60 final SubShape subShape = new SubShape(shape);
61 subShape.setGroup(groupId);
62 subShape.setVisible(true);
63 originalSubShapes.add(subShape);
64 slicingOutdated = true;
68 * This method should be overridden by anyone wanting to customize shape
69 * before it is rendered.
71 public void beforeTransformHook(final TransformPipe transformPipe,
72 final RenderingContext context) {
75 public Point3D getLocation() {
76 return transform.getTranslation();
79 public List<SubShape> getOriginalSubShapes() {
80 return originalSubShapes;
83 public UserRelativityTracker getRelativityTracker() {
84 return relativityTracker;
87 public void hideGroup(final String groupIdentifier) {
88 originalSubShapes.stream().filter(subShape -> subShape.matchesGroup(groupIdentifier)).forEach(subShape -> {
89 subShape.setVisible(false);
90 slicingOutdated = true;
94 private boolean isReslicingNeeded(double sliceFactor1, double sliceFactor2) {
99 if (sliceFactor1 > sliceFactor2) {
100 final double tmp = sliceFactor1;
101 sliceFactor1 = sliceFactor2;
105 return (sliceFactor2 / sliceFactor1) > 1.5d;
109 public void removeGroup(final String groupIdentifier) {
110 final java.util.Iterator<SubShape> iterator = originalSubShapes
113 while (iterator.hasNext()) {
114 final SubShape subShape = iterator.next();
115 if (subShape.matchesGroup(groupIdentifier)) {
117 slicingOutdated = true;
122 private void resliceIfNeeded() {
124 final double proposedSliceFactor = relativityTracker
125 .proposeSliceFactor();
127 if (isReslicingNeeded(proposedSliceFactor, currentSliceFactor)) {
128 currentSliceFactor = proposedSliceFactor;
134 * Paint solid elements of this composite shape into given color.
136 public void setColor(final Color color) {
137 for (final SubShape subShape : getOriginalSubShapes()) {
138 final AbstractShape shape = subShape.getShape();
140 if (shape instanceof SolidPolygon)
141 ((SolidPolygon) shape).setColor(color);
143 if (shape instanceof Line)
144 ((Line) shape).color = color;
148 public void setGroupForUngrouped(final String groupIdentifier) {
149 originalSubShapes.stream().filter(subShape -> subShape.isUngrouped()).forEach(subShape -> subShape.setGroup(groupIdentifier));
153 public void setMouseInteractionController(
154 final MouseInteractionController mouseInteractionController) {
155 super.setMouseInteractionController(mouseInteractionController);
157 for (final SubShape subShape : originalSubShapes)
158 subShape.getShape().setMouseInteractionController(
159 mouseInteractionController);
161 slicingOutdated = true;
165 public void setTransform(final Transform transform) {
166 this.transform = transform;
169 public void showGroup(final String groupIdentifier) {
170 originalSubShapes.stream().filter(subShape -> subShape.matchesGroup(groupIdentifier)).forEach(subShape -> {
171 subShape.setVisible(true);
172 slicingOutdated = true;
176 private void slice() {
177 slicingOutdated = false;
179 final List<AbstractShape> result = new ArrayList<>();
181 final Slicer slicer = new Slicer(currentSliceFactor);
182 originalSubShapes.stream().filter(subShape -> subShape.isVisible()).forEach(subShape -> {
183 if (subShape.getShape() instanceof TexturedPolygon)
184 slicer.slice((TexturedPolygon) subShape.getShape());
186 result.add(subShape.getShape());
189 result.addAll(slicer.getResult());
191 renderedSubShapes = result;
195 public void transform(final TransformPipe transformPipe,
196 final RenderAggregator aggregator, final RenderingContext context) {
198 // add current composite shape transform to the end of the transform
200 transformPipe.addTransform(transform);
202 relativityTracker.analyze(transformPipe, context);
204 beforeTransformHook(transformPipe, context);
206 // hack, to get somewhat perspective correct textures
209 // transform rendered subshapes
210 for (final AbstractShape shape : renderedSubShapes)
211 shape.transform(transformPipe, aggregator, context);
213 transformPipe.dropTransform();