can you please tell me how i can change the color gradient in the following piece of code? In my code im trying to control the color gradient from here:
for( Marker marker : countryMarkers ) {
for( i=0; i<255; i++ ){
marker.setColor(color(255, i, 0));
}
}
Unfortunately im getting one color only. Can you help please?
import de.fhpotsdam.unfolding.mapdisplay.*;
import de.fhpotsdam.unfolding.utils.*;
import de.fhpotsdam.unfolding.marker.*;
import de.fhpotsdam.unfolding.tiles.*;
import de.fhpotsdam.unfolding.interactions.*;
import de.fhpotsdam.unfolding.ui.*;
import de.fhpotsdam.unfolding.*;
import de.fhpotsdam.unfolding.core.*;
import de.fhpotsdam.unfolding.mapdisplay.shaders.*;
import de.fhpotsdam.unfolding.data.*;
import de.fhpotsdam.unfolding.geo.*;
import de.fhpotsdam.unfolding.texture.*;
import de.fhpotsdam.unfolding.events.*;
import de.fhpotsdam.utils.*;
import de.fhpotsdam.unfolding.providers.*;
import java.util.List;
UnfoldingMap map;
void setup() {
size(800, 600);
int i=0,k=15;
map = new UnfoldingMap(this, new Microsoft.AerialProvider());
Location cyprusLocation = new Location(35f, 33f);
map.zoomAndPanTo(cyprusLocation, 11);
float maxPanningDistance = 30; // in km
map.setPanningRestriction(cyprusLocation, maxPanningDistance);
//map = new UnfoldingMap(this);
MapUtils.createDefaultEventDispatcher(this, map);
List<Feature> countries = GeoJSONReader.loadData(this, "Dasos.geo.json");
List<Marker> countryMarkers = MapUtils.createSimpleMarkers(countries);
map.addMarkers(countryMarkers);
/*
for (Marker marker : countryMarkers) {
// marker.setColor(color(255, 0, 0));
}
*/
for (Marker marker : countryMarkers) {
for(i=0;i<255;i++){
marker.setColor(color(255, i, 0));
}
}
}
void draw() {
map.draw();
}
void keyPressed() {
if (key == ' ') {
map.getDefaultMarkerManager().toggleDrawing();
}
}
You have a nested loop, so you are setting each marker with every color, from (255, 0 ,0) until (255, 255, 0), before displaying it. At the end they are all left with the same last color in the inner loop...
You might just use a regular for loop to traverse the array, so you can use the index as part of color(). But you need to mind somehow the maximum numbers, something like:
(note you were missing the int inside regular for loop)
for(int i = 0; i < countryMarkers.length; i++){
countryMarkers[i].setColor(color(255, (i%255), 0));
}
or just use an incremented var inside the for each instead the index...
for (Marker marker : countryMarkers) {
marker.setColor(color(255, (otherVar++)%255, 0));
}
Related
I have a project i'm trying to develop controls for. I need to be able to continuously rotate the object from a single mouse click and drag and release. After releasing I wish the object to continue rotating from its initial point to the position where i released the mouse.(provided the object has not already reached this position.) I've seen applications previously that worked in this manner and I cant seem to find any code online to show how that was implemented. I am using this below code to test my mouse controls before adding them to my project. It contains simple drag and release mechanics already. However I would appreciate some input as to how to go about adding the continuous rotation. I want the mouse to be able to control the speed of the rotation of the object along any axis. As i have it set up it rotates along any axis. But I would like a drag to instead of rotate the object, cause the object to spin(recursively rotate) at a velocity proportional to distance the mouse was dragged. This would increase velocity as distance increased. If I drag the same direction twice the same distance, the velocity should double, the object then rotating twice as fast.
package javafxapplication3;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.geometry.Point3D;
import javafx.scene.DepthTest;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class trafo extends Application {
final Group root = new Group();
final XformWorld world = new XformWorld();
final PerspectiveCamera camera = new PerspectiveCamera(true);
final XformCamera cameraXform = new XformCamera();
private static final double CAMERA_INITIAL_DISTANCE = -1000;
private static final double CAMERA_NEAR_CLIP = 0.1;
private static final double CAMERA_FAR_CLIP = 10000.0;
double mousePosX, mousePosY, mouseOldX, mouseOldY, mouseDeltaX, mouseDeltaY;
double mouseFactorX, mouseFactorY;
#Override
public void start(Stage primaryStage) {
root.getChildren().add(world);
root.setDepthTest(DepthTest.ENABLE);
buildCamera();
buildBodySystem();
Scene scene = new Scene(root, 800, 600, true);
scene.setFill(Color.GREY);
handleMouse(scene);
primaryStage.setTitle("TrafoTest");
primaryStage.setScene(scene);
primaryStage.show();
scene.setCamera(camera);
mouseFactorX = 180.0 / scene.getWidth();
mouseFactorY = 180.0 / scene.getHeight();
}
private void buildCamera() {
root.getChildren().add(cameraXform);
cameraXform.getChildren().add(camera);
camera.setNearClip(CAMERA_NEAR_CLIP);
camera.setFarClip(CAMERA_FAR_CLIP);
camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);
}
private void buildBodySystem() {
PhongMaterial whiteMaterial = new PhongMaterial();
whiteMaterial.setDiffuseColor(Color.WHITE);
whiteMaterial.setSpecularColor(Color.LIGHTBLUE);
Box box = new Box(400, 200, 100);
box.setMaterial(whiteMaterial);
PhongMaterial redMaterial = new PhongMaterial();
redMaterial.setDiffuseColor(Color.DARKRED);
redMaterial.setSpecularColor(Color.RED);
Sphere sphere = new Sphere(5);
sphere.setMaterial(redMaterial);
sphere.setTranslateX(200.0);
sphere.setTranslateY(-100.0);
sphere.setTranslateZ(-50.0);
world.getChildren().addAll(box);
world.getChildren().addAll(sphere);
}
private void handleMouse(Scene scene) {
scene.setOnMousePressed((MouseEvent me) -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseOldX = me.getSceneX();
mouseOldY = me.getSceneY();
});
scene.setOnMouseDragged((MouseEvent me) -> {
mouseOldX = mousePosX;
mouseOldY = mousePosY;
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseDeltaX = (mousePosX - mouseOldX);
mouseDeltaY = (mousePosY - mouseOldY);
if (me.isPrimaryButtonDown()) {
cameraXform.ry(mouseDeltaX * 180.0 / scene.getWidth());
cameraXform.rx(-mouseDeltaY * 180.0 / scene.getHeight());
} else if (me.isSecondaryButtonDown()) {
camera.setTranslateZ(camera.getTranslateZ() + mouseDeltaY);
}
});
}
public static void main(String[] args) {
launch(args);
}
}
class XformWorld extends Group {
final Translate t = new Translate(0.0, 0.0, 0.0);
final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS);
final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS);
final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS);
public XformWorld() {
super();
this.getTransforms().addAll(t, rx, ry, rz);
}
}
class XformCamera extends Group {
Point3D px = new Point3D(1.0, 0.0, 0.0);
Point3D py = new Point3D(0.0, 1.0, 0.0);
Rotate r;
Transform t = new Rotate();
public XformCamera() {
super();
}
public void rx(double angle) {
r = new Rotate(angle, px);
this.t = t.createConcatenation(r);
this.getTransforms().clear();
this.getTransforms().addAll(t);
}
public void ry(double angle) {
r = new Rotate(angle, py);
this.t = t.createConcatenation(r);
this.getTransforms().clear();
this.getTransforms().addAll(t);
}
}
So the way I see it, you want to calculate the arc that the drag made from the middle of the object that you want to rotate, and rotate the whenever that object is not rotated correctly, it will rotate at a constants speed until it reaches the desired rotation. I've never done something like that, so I don't know if my answer will actually work, but I can at least try, because I think I know the solution. Now the code below may or may not work, please tell me if anything is not correct, I'll try to fix it.
public class RotationNode extends Pane {
double startMouseAngle, goalAngle = 0.0, angleBeforeRotation;
boolean currentlyRotating = false;
public RotationNode(double angle) {
//Parameter angle is to give this Pane a start angle if you want to
super();
//This can all change to whatever you want it to be
setTranslateX(400.0);
setTranslateY(200.0);
setPrefSize(100.0, 100.0);
setRotationAxis(new Point3D(0.0, 0.0, 360.0));
//This is just to show something is actually rotating
Rectangle r = new Rectangle(0, 0, 100, 100);
r.setFill(Color.BLUE);
getChildren().add(r);
setRotate(angle);
angleBeforeRotation = 0.0;
addEventHandler(MouseEvent.MOUSE_PRESSED, ov -> {
if(ov.getButton() == MouseButton.PRIMARY) {
double x = ov.getX();
double y = ov.getY();
startMouseAngle = Math.toDegrees(Math.atan2(x, y));
angleBeforeRotation = currentlyRotating ? goalAngle : getRotate();
ov.consume();
}
});
addEventHandler(MouseEvent.MOUSE_DRAGGED, ov -> {
if(ov.getButton() == MouseButton.PRIMARY) {
double x = ov.getX();
double y = ov.getY();
double a = Math.toDegrees(Math.atan2(x, y));
double deltaAngle = startMouseAngle - a;
goalAngle = angleBeforeRotation + deltaAngle;
if(!currentlyRotating) {
new changeRotation();
}
ov.consume();
}
});
}
private class changeRotation {
private final long TIME_STEP = 25;
private final double ANGLE_PER_SECOND = 90;
public changeRotation() {
final ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
Runnable changeWidthCmd = () -> {
double rotationDelta = ANGLE_PER_SECOND / (1000.0 / TIME_STEP);
rotationDelta *= getRotate() > goalAngle ? -1 : 1;
setRotate(getRotate() + rotationDelta);
if(getRotate() - goalAngle < ANGLE_PER_SECOND / (1000.0 / TIME_STEP) && getRotate() - goalAngle > -ANGLE_PER_SECOND / (1000.0 / TIME_STEP)) {
setRotate(goalAngle);
currentlyRotating = false;
service.shutdown();
}
};
currentlyRotating = true;
service.scheduleAtFixedRate(changeWidthCmd, 0, TIME_STEP, TimeUnit.MILLISECONDS);
}
}
}
I hope this helps you,
Lenardjee
EDIT :
Updated the code, it now works kind of. The rotation based on mouse drag works, but the centre point is weird and doesn't work that well. I will try try to improve this and update this answer
IMPORTANT EDIT :
I forgot to mention that this answer contains code that uses an external library. To add it, add this to the projects pom file:
<dependencies>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.1.14</version>
</dependency>
</dependencies>
or download the library fromhttps://jar-download.com/?detail_search=g%3A%22io.reactivex.rxjava2%22&g=io.reactivex.rxjava2&p=1and add that jar to the projects dependencies.
im new in java and my question might be stupid but i really dont know how to solve this problem, im making a Minesweeper and im using javafx, im using a class for the mines, so im using a "stackPane" and im puting it inside a grid, the problem i have is that i don't know hot to make multiples instances of it, and i have no clue how to start, im makinga 10*10 board and the mines are suposed to apear randomly, so im using "math.random" to decide if one space will be empti or if it will have a mine, i hope some one out there can help me
well i find a solution, but the thing i dont know how to do now is how to set a "setaction" for each button, im trying to put setonactio(new eventhandler() ...
here is my code:
package buscaminas2;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author ALIENWARE R4
*/
public class Buscaminas2 extends Application {
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("buscaminas");
GridPane mainGrid = new GridPane();
GridPane flowPane = new GridPane();
flowPane.setPadding(new Insets(2, 2, 2, 2));
flowPane.setVgap(2);
flowPane.setHgap(2);
//flowPane.setPrefWrapLength(210);
HBox score = new HBox();
Button btn = new Button();
for (int i = 0; i < 10; i++) {//-----------------bob the constructor------------------//
for (int j = 0; j < 10; j++)
{
int abc = (int)(Math.random()*10);
System.out.print(abc);
if( abc > 2)
{
btn = new Button(" ");
btn.setId(STYLESHEET_MODENA);
btn.setPrefSize(35, 35);
flowPane.add(btn, i, j);
flowPane.getChildren().get(i);
}
else
{
StackPane boomb = new StackPane();//---------------------bombs--------------------//
boomb.setPrefSize(35, 35);
Label num = new Label("X");
num.setPrefSize(40, 40);
boomb.getChildren().add(num);
Button xyz = new Button();
xyz.setPrefSize(40, 40);
boomb.getChildren().add(xyz);
flowPane.add(boomb, i, j);// agrega bombas en xy agregando "boomb" en el grid
}
}
}
Scene scene = new Scene(flowPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I've written this code which creates a sketchbook.
I'm sure that there's a simple error, but why won't it stop playing at the end of the images?
Here is the code
import ddf.minim.spi.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*;
Minim minim;
AudioPlayer sou; //variable name;
final int NUMBER_IMAGES = 27;
PImage[] images; //sets PImage array
int framerate = 10;
int currentImage = 0;
String getImageName(int image_number) {
if (image_number == 0) { // == double equals checks for equality
return "title.gif"; //missing k0.gif and k26.gif until this line //added
} else if (image_number == 26) {
return "title2.gif";
} else {
return "data/K" + image_number + ".gif";
}
}
void setup () {
minim = new Minim(this); //define construction
sou = minim.loadFile("ambience.mp3");
sou.loop();
size (300, 300);
background (255);
frameRate(framerate);
imageMode (CENTER); // Tells the images to display relative to CENTRE
images = new PImage[NUMBER_IMAGES]; // initialises the array (not images)
for (int image_number = 0; image_number < NUMBER_IMAGES; image_number++) {
String filename; // Declared a String called filename
filename = getImageName(image_number);
images[image_number] = loadImage(filename);
}
}
void draw () {
// Set framerate
frameRate(framerate);
// Draws first image
image(images[currentImage], width/2.0, height/2.0);
currentImage++;
currentImage = currentImage % NUMBER_IMAGES;
}
void keyPressed() {
if (keyCode == UP) { // up arrow increases frame rate by one
framerate ++;
}
if (keyCode == DOWN) { //down arrow decreases framerate by one
framerate --;
}
}
I can't think of more details to add although I'm being told I can't post this as it is mostly code.
This line is the one that achieves the recurrent number loop.
currentImage = currentImage % NUMBER_IMAGES
What the % (Modulo) operator does is to calculates the remainder when one number is divided by another. So lets say for example that your NUMBER_IMAGES is 10, at first you'll have 1 & 10 and the value stored in currentImage would be 1. This continues until you reach 10 % 10 the value stored would be 0 and there you'll start all over again.
Here you can find more about the (Module) in Processing: https://www.processing.org/reference/modulo.html
Perhaps a more simple approach to achieve what you'll looking for would be to add a condition to stop when you reach the number of images.
void draw () {
// Set framerate
frameRate(framerate);
// Draws images
image(images[currentImage], width/2.0, height/2.0);
if(currentImage < NUMBER_IMAGES){
currentImage++;
}
}
Hope this helps.
Regards
Jose
Because you have this line inside your code it will show images forever
currentImage = currentImage % NUMBER_IMAGES
If you want stop drawing nex image simply change this line into something like this:
if(currentImage == NUMBER_IMAGES) noLoop()
noLoop() will stop whole draw() animation so it will display your last image. If you want then exit the animation you can add this to your keyPressed():
if (keyCode == ESC){
exit();
}
exit() will correctly exit your program. You can use this function instead of noLoop to end after last image.
I need to decrease the pixels in image from 480 X 480 to 30 X 30. This requires downsampling of pixels, i don't see any method to remove individual pixels in a bitmap image.
I need this downsampling because i'm studying distortion in image processing - on the brief side.
Any help in this would be appreciated.
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.net.URLRequest;
public class DownSampling extends Sprite
{
private var _loader : Loader;
public function DownSampling()
{
_loader = new Loader;
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImgLoaded);
// Get the bitmap
_loader.load(new URLRequest("https://appharbor.com/assets/images/stackoverflow-logo.png"));
}
private function onImgLoaded(e : Event) : void
{
var currentBitmapdata : BitmapData = Bitmap(_loader.content).bitmapData;
var i : uint = 9;
var downFactor : Number = 0.2;
// this will reduce size by 20%
var downMat : Matrix = new Matrix;
downMat.scale(1 - downFactor, 1 - downFactor);
while(--i)
{
// Create new bitmapdata but smaller
var smallerImg : BitmapData = new BitmapData(currentBitmapdata.width * (1-downFactor), currentBitmapdata.height * (1-downFactor), true, 0);
// Copy and apply scale
smallerImg.draw(currentBitmapdata, downMat);
// Add to stage and set alpha to 50%
addChild(new Bitmap(smallerImg)).alpha = .5;
// Apply the same transform next loop
currentBitmapdata = smallerImg;
}
}
}
}
Result :
I'm working on a card game based on the NetBeans platform and I'm struggling to get my head around dynamic images. Why dynamic? Well I want the cards to adjust at run time to changes to the page (i.e. name, text, cost, etc).
My first hack at it was creating a component (JPanel) with labels pre-placed where I loaded the text/image based on the card values. That seems to work fine but then it became troublesome when I thought about some pages having a different look in later editions (meaning not everything would be on the same place).
So I'm trying to get an idea about ways to do this based on some kind of template.
Any idea?
There's a follow-up question at: JList of cards?
Finally I got some time to get back to this and was able to figure out a way using Java 2D tutorial.
The pictures are not near what I will use in my application but serves as proof of concept.
package javaapplication3;
import java.awt.*; import java.awt.font.FontRenderContext; import
java.awt.font.LineBreakMeasurer; import java.awt.font.TextAttribute;
import java.awt.font.TextLayout; import java.awt.image.BufferedImage;
import java.io.File; import java.io.IOException; import
java.net.MalformedURLException; import java.net.URL; import
java.text.AttributedCharacterIterator; import
java.text.AttributedString; import java.util.ArrayList; import
java.util.HashMap; import java.util.logging.Level; import
java.util.logging.Logger; import javax.imageio.ImageIO;
/** * * #author Javier A. Ortiz Bultrón
*/ public class DefaultImageManager {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
// TODO code application logic here
DefaultImageManager manager = new DefaultImageManager();
URL url = DefaultImageManager.class.getResource("weather-rain.png");
manager.getLayers().add(ImageIO.read(url));
url = DefaultImageManager.class.getResource("weather-sun.png");
manager.getLayers().add(ImageIO.read(url));
manager.addText(new Font("Arial", Font.PLAIN, 10), "Many people believe that Vincent van Gogh painted his best works "
+ "during the two-year period he spent in Provence. Here is where he "
+ "painted The Starry Night--which some consider to be his greatest "
+ "work of all. However, as his artistic brilliance reached new "
+ "heights in Provence, his physical and mental health plummeted. ",
200, 150, new Point(0, 0));
manager.generate();
} catch (MalformedURLException ex) {
Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,
null, ex);
} catch (IOException ex) {
Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,
null, ex);
}
}
/**
* Layers used to create the final image
*/
private ArrayList layers = new ArrayList();
private ArrayList textLayers = new ArrayList();
/**
* #return the layers
*/
public ArrayList<BufferedImage> getLayers() {
return layers;
}
private Dimension getMaxSize() {
int width = 0, height = 0;
for (BufferedImage img : getLayers()) {
if (img.getWidth() > width) {
width = img.getWidth();
}
if (img.getHeight() > height) {
height = img.getHeight();
}
}
return new Dimension(width, height);
}
public void addText(Font font, String text, int height, int width, Point location) {
BufferedImage textImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
HashMap<TextAttribute, Object> map =
new HashMap<TextAttribute, Object>();
map.put(TextAttribute.FAMILY, font.getFamily());
map.put(TextAttribute.SIZE, font.getSize());
map.put(TextAttribute.FOREGROUND, Color.BLACK);
AttributedString aString = new AttributedString(text, map);
AttributedCharacterIterator paragraph = aString.getIterator();
// index of the first character in the paragraph.
int paragraphStart = paragraph.getBeginIndex();
// index of the first character after the end of the paragraph.
int paragraphEnd = paragraph.getEndIndex();
Graphics2D graphics = textImage.createGraphics();
FontRenderContext frc = graphics.getFontRenderContext();
// The LineBreakMeasurer used to line-break the paragraph.
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
// Set break width to width of Component.
float breakWidth = width;
float drawPosY = 0;
// Set position to the index of the first character in the paragraph.
lineMeasurer.setPosition(paragraphStart);
// Get lines until the entire paragraph has been displayed.
while (lineMeasurer.getPosition() < paragraphEnd) {
// Retrieve next layout. A cleverer program would also cache
// these layouts until the component is re-sized.
TextLayout layout = lineMeasurer.nextLayout(breakWidth);
// Compute pen x position. If the paragraph is right-to-left we
// will align the TextLayouts to the right edge of the panel.
// Note: this won't occur for the English text in this sample.
// Note: drawPosX is always where the LEFT of the text is placed.
float drawPosX = layout.isLeftToRight()
? 0 : breakWidth - layout.getAdvance();
// Move y-coordinate by the ascent of the layout.
drawPosY += layout.getAscent();
// Draw the TextLayout at (drawPosX, drawPosY).
layout.draw(graphics, drawPosX, drawPosY);
// Move y-coordinate in preparation for next layout.
drawPosY += layout.getDescent() + layout.getLeading();
}
getTextLayers().add(textImage);
}
public void generate() throws IOException {
Dimension size = getMaxSize();
BufferedImage finalImage = new BufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_ARGB);
for (BufferedImage img : getLayers()) {
finalImage.createGraphics().drawImage(img,
0, 0, size.width, size.height,
0, 0, img.getWidth(null),
img.getHeight(null),
null);
}
for(BufferedImage text: getTextLayers()){
finalImage.createGraphics().drawImage(text,
0, 0, text.getWidth(), text.getHeight(),
0, 0, text.getWidth(null),
text.getHeight(null),
null);
}
File outputfile = new File("saved.png");
ImageIO.write(finalImage, "png", outputfile);
}
/**
* #return the textLayers
*/
public ArrayList<BufferedImage> getTextLayers() {
return textLayers;
}
/**
* #param textLayers the textLayers to set
*/
public void setTextLayers(ArrayList<BufferedImage> textLayers) {
this.textLayers = textLayers;
} }
It still needs some refining specially on the placement of the text but it works. I guess I can implement a xml format to store all this information so is easily configurable. In the example below suns are drawn on top of rain, and the text is on top of all that. For my application each layer will build together the page I want.
Here are the images I used:
And the final result: