EricRogerGarcia

// PstarEngine 0.21.5 Java version


// 1. Functions
// 1.1. BugMessage
// 2. System
// 2.1. EventType
// 2.2. PEvent
// 2.3. ActionEvents
// 2.4. SystemEvents
// 3. Base Nodes
// 3.1. Observable
// 3.2. Observer
// 3.3. NodeType
// 3.4. Node
// 3.5. Node2D
// 3.6. PEngine
// 3.7. Responsive
// 3.8. RefSize
// 3.9. Components
// 3.9.1. ComponentType
// 3.9.2. Component
// 3.9.3. Component2D
// 3.9.4. Sprite2D
// 3.9.5. Rotation
// 3.9.6. Timer
// 3.9.7. Background (TODO cf JS)
// 4. Physic Engine
// 5. GUI
// 5.1. Control
// 5.2. GUIcomponent
// 5.3. Themes
// 5.3.1. ThemeType
// 5.3.2. Theme
// 5.4. Focus
// 5.5. Languages
// 5.W. Widgets
// 5.W.x. a widget
// 5.W.x.1. the widget (extends Control)
// 5.W.x.2. GUIScript for FLAT
// 5.W.x.y. GUIScript for ...
// 5.W.1. Slider
// 5.W.1.1. Slider class
// 5.W.1.2. Slider GUIscript for FLAT
// 6. special
// 6.1. Preload

 

// 1. Functions

// 1.1. BugMessage

void bugMessage(String message) {
// TODO ; popWindow with application freezed with Palert(String message)
println(message);
}

// 2. System

// 2.1. EventType

// cf TAB Application

// 2.2. PEvent

class PEvent {
EventType eventType;
Object source;

PEvent(EventType eventType, Object source) {
this.eventType=eventType;
this.source=source;
}
}


// 2.4. SystemEvents

// singleton pengine.systemEvents
class SystemEvents implements Observable {
ArrayList listeners = new ArrayList<>();

// keyboard

// dictionary : String key -> ActionType (enum))
HashMap<String, EventType> Inputs = new HashMap<>();


// Implements Observable

void listen(Node node) {
listeners.add(node);
}

//void unListen(Node node);

void notify(PEvent event) {
for (Node node : listeners) {
node.signal(event);
}
}

// end Implements Observable

// mouse

void clicEvent() {
notify(new PEvent(EventType.CLIC, this));
}

// keyboard

SystemEvents addInput(String s, EventType e) {
Inputs.put(s, e);
return this;
}

void run() {

if (keyPressed) {
//println("["+key+"] <"+keyCode+">");
switch(keyCode) {
case 37 :
keyboard("LEFT");
break;
case 38 :
keyboard("UP");
break;
case 39 :
keyboard("RIGHT");
break;
case 40 :
keyboard("DOWN");
break;
case 155 :
keyboard("INSERT");
break;
case 36 :
keyboard("HOME");
break;
case 35 :
keyboard("END");
break;
case 17 :
keyboard("CTRL");
break;
case 16 :
keyboard("SHIFT");
break;
case 20 :
keyboard("MAJ");
break;
case 18 :
keyboard("ALT");
break;
case 27 :
keyboard("ESC");
break;
case 65406 :
keyboard("ALTGR");
break;
case 33 :
keyboard("PAGEUP");
break;
case 34 :
keyboard("PAGEDOWN");
break;

// problem with this key !!! do not use it !!!
case 127 :
keyboard("DEL");
break;


default :
switch(str(key)) {
case "\n":
keyboard("ENTER");
break;
case "\b":
keyboard("BACKSPACE");
break;
case "\t":
keyboard("TAB");
break;
default :
keyboard(str(key).toUpperCase());
}
}
}
} //end Run()

void keyboard(String k) {
if (Inputs.containsKey(k)) {
notify(new PEvent(Inputs.get(k), this));
}
}
} // End SystemEvents

void mouseReleased() {
pengine.systemEvents.clicEvent();
}

 

// 3. Base Nodes

// 3.1. Observable

interface Observable {
void listen(Node node);
//void unListen(Node node);
void notify(PEvent event);
}
// 3.2. Observer

interface Observer {
void signal(PEvent event);
}

// 3.3. NodeType

enum NodeType {
NULL,
NODE, NODE2D, PRELOAD, TEST, REFSIZE, CONTROL,
// Widgets type :
WIDGETTEST, SLIDER;
}

// 3.4. Node

class Node implements Observable, Observer {
NodeType nodeType;
Boolean isRoot = false; // Only PEngine class marks it as true
String name;
Boolean isDisabled, isFreezed, isToRemove;
Boolean isReady=false;
ArrayList children = new ArrayList<>();
Node parent; // nothing for root Node
// Components
ArrayList components = new ArrayList<>();

// implements Observable
ArrayList listeners = new ArrayList<>();


Node(String name) {
nodeType = NodeType.NODE;
this.name=name;
isDisabled = isFreezed = isToRemove = false;
}

String toString() {
String toReturn = name+"("+nodeType+")";
for (Component component : components) {
toReturn+="\n COMPONENT : "+component.name+"("+component.componentType+")\n";
}
return toReturn;
}

void _printTreeHelp(int decal, String toPrint) {
if (decal!=0) {
for (int i=0; i<decal; i++) {
print("---->");
}
}
print(toPrint);
println("");
}

void printTree() {
_printTreeHelp(pengine.decalTree, toString());
pengine.decalTree+=1;
for (Node child : children) {
child.printTree();
}
pengine.decalTree-=1;
}

// implements Observable

void listen(Node node) {
listeners.add(node);
}

// TODO in JS !
void unListen(Node node) {
listeners.remove(node);
}

void notify(PEvent pEvent) {
for (Node node : listeners) {
node.signal(pEvent);
}
}

// implements Observer

void signal(PEvent pEvent) {
for (Component component : components) {
component.signal(this, pEvent);
}
}

// end implementations

void addChild(Node child) {
children.add(child);
child.parent=this;
}

Node addComponent(Component component) { // D.P. Decorator
components.add(component);
return this;
}

void _runReady() {
ready();
for (Node child : children) {
child._runReady();
}
}

void _runInMatrix() {
for (Node child : children) {
if (!child.isDisabled && !child.isToRemove) {
child._runInMatrix();
}
}
}

void _runOutMatrix(float delta) {
process(delta);
for (Node child : children) {
if (!child.isDisabled && !child.isToRemove && !isFreezed) {
child._runOutMatrix(delta);
}
}
}

void ready() {
if (!isReady) {
for (Component component : components) {
component.ready(this);
}
isReady=true;
}
}

void process(float delta) {
for (Component component : components) {
component.process(this, delta);
}
}

void toRemove() {
if (!isRoot) {
isToRemove=true;
}
}

void _remove() {
if (!isRoot) {
if (isToRemove) {
parent.children.remove(this);
}
}
}

void setDisable(Boolean b) {
if (!isRoot) {
isDisabled = b;
}
}

void setFreezed(Boolean b) {
if (!isRoot) {
isFreezed=b;
for (Node child : children) {
child.setFreezed(b);
}
}
}
}

// 3.5. Node2D

class Node2D extends Node {

PVector position, globalPosition, size, globalSize;
float rotation, globalRotation, scale, globalScale;
// Components2D
ArrayList components = new ArrayList();

Node2D(String name) {
super(name);
nodeType = NodeType.NODE2D;
position=new PVector(0, 0);
rotation=0;
globalRotation=0;
scale=1;
globalScale=1;
globalPosition = position.copy();
size=new PVector(10, 10);
}

Node2D setPosition(float x, float y) {
position.set(x, y);
globalPosition = position.copy();
return this;
}

Node2D setSize(float w, float h) {
size.set(w, h);
return this;
}

Node2D setScale(float s) {
scale=s;
return this;
}

PVector topLeft() {
return new PVector(-size.x/2, -size.y/2);
}

PVector globalTopLeft() {
return globalPosition.copy().add(topLeft());
}

Node2D addComponent(Component2D component) { // D.P. Decorator
components.add(component);
return this;
}

void signal(PEvent pEvent) {
for (Component2D component : components) {
component.signal(this, pEvent);
}
}

String toString() {
String toReturn = name+"("+nodeType+"), position = ("+this.position.x+","+this.position.y+"), rotation = "+this.rotation+", scale = "+this.scale;
for (Component2D component : components) {
toReturn+="\n COMPONENT : "+component.name+"("+component.componentType+")\n";
}
return toReturn;
}

void addChild(Node child) {
if (child.nodeType==NodeType.NODE) {
bugMessage("Node2D.addChild("+child.name+") : children can't be Node type !");
} else {
super.addChild(child);
}
}

void _runInMatrix() {
push();
translate(this.position.x, this.position.y);
rotate(this.rotation);
scale(this.scale);
this.display();
super._runInMatrix();
pop();
}

void ready() {
if (!isReady) {
for (Component2D component : components) {
component.ready(this);
}
isReady=true;
}
}

void process(float delta) {
for (Component2D component : components) {
component.process(this, delta);
}
}

void display() {
if (pengine.debug) {
push();
fill(255, 0, 0);
stroke(255, 0, 0);
strokeWeight(1);
circle(0, 0, 10);
textFont(font);
textSize(20);
strokeWeight(1);
text(this.name, 10, 10);
pop();
}

for (Component2D component : components) {
component.display(this);
}
}

void globalComputations() {
this.globalPosition = this.position.copy();
this.globalRotation = this.rotation;
this.globalScale = this.scale;
if (!this.isRoot) {
if (this.parent.nodeType!=NodeType.NODE) {
Node2D parentBis = (Node2D) parent;
globalRotation += parentBis.globalRotation;
globalScale *= parentBis.globalScale;
globalPosition = parentBis.globalPosition.copy().add(position.copy().rotate(parentBis.globalRotation).mult(parentBis.globalScale));
}
}
globalSize = size.copy().mult(globalScale);
}

void _runOutMatrix(float delta) {
globalComputations();
super._runOutMatrix(delta);
}

PVector _parentGlobalPosition() {
if (this.parent.nodeType==NodeType.NODE) {
return new PVector(0, 0);
} else {
Node2D parentBis = (Node2D) parent;
return parentBis.globalPosition;
}
}

// DON'T TRY TO USE D.P. DECORATOR HERE !!!
void setGlobalPosition(float globalX, float globalY) {
if (this.isRoot) {
this.position.set(globalX, globalY);
} else {
PVector globalPosition=new PVector(globalX, globalY);
position.set(globalPosition.sub(_parentGlobalPosition()));
}
}

void setGlobalPositionX(float globalX) {
this.setGlobalPosition(globalX, this.globalPosition.y);
}

void setGlobalPositionY(float globalY) {
this.setGlobalPosition(this.globalPosition.x, globalY);
}
}

// 3.6. PEngine

class PEngine {
Node root;
Node sceneParent;
Boolean isPreloadReady;
float delta;
float pMillis=0; // only for Java version !
color backgroundColor=color(0, 0, 0);

// Preload
Preload preload=new Preload();
Node2D preloadPreviousScene=null;

// global variables
Boolean hasRefSize=false;
RefSize refSize;
String userLang;
int decalTree=0;
Boolean debug=false;
Theme theme;
SystemEvents systemEvents = new SystemEvents();

// End global variables

PEngine () {
root = new Node("root");
root.isRoot=true;
sceneParent=root;
isPreloadReady = false;
userLang="??"; // must be ask to the user as the JVM is Processing JVM most of the time !

theme = new Theme();
theme.addGUIcomponent(new SliderBASIC("SliderBASIC"));
}

PEngine setBackground(color bg) {
backgroundColor=bg;
return this;
}

PEngine setRefSize(color bgColor) {
if (frameCount==0) { // setRefSize() called in setup()
hasRefSize=true;
refSize = new RefSize(bgColor);
sceneParent = refSize;
root.addChild(sceneParent);
} else {
bugMessage("pengine.setRefSize() must not be called in draw() !");
exit();
}
return this;
}

void setRefSizeColor(color bgColor) {
if (hasRefSize) {
RefSize rs = (RefSize) sceneParent;
rs.bgColor=bgColor;
} else {
bugMessage("PEngine.setRefSize() cannot change RefSize color : no RefSize !");
exit();
}
}

void run() {
// / defaults
imageMode(CENTER);
textAlign(CENTER);

// delta computation
delta=(millis()-pMillis)/1000;
pMillis=millis();

// Reading keyboard
systemEvents.run();

if (root==null) {
bugMessage("PEngine : root doesn't exist !");
exit();
} else {
if (!isPreloadReady) {
preloadPreviousScene=getScene();
setScene(preload);
root._runReady();
isPreloadReady=true;
}
background(backgroundColor);
root._runOutMatrix(delta);
root._runInMatrix();
root._remove();
}
}

void printTree() {
println("");
root.printTree();
println("");
decalTree=0;
}

void setScene(Node2D node2d) {
sceneParent.children=new ArrayList<>();
sceneParent.addChild(node2d);
if (frameCount!=0) { // setScene() not called in setup()
node2d._runReady();
}
}

Node2D getScene() {
if (sceneParent.children.size()!=0) {
return (Node2D) sceneParent.children.get(0);
} else {
return null;
}
}
}
// 3.7. Responsive

// only for JS !
// use
// surface.setResizable(true); in setup()
// windowRatio(,); in draw()
//for Java

// 3.8. RefSize

// singleton pengine.refSize may be null if not used
class RefSize extends Node2D {
color bgColor;
RefSize(color bgColor) {
super("RefSize");
nodeType=NodeType.REFSIZE;
this.bgColor=bgColor;
setPosition(width/2, height/2);
setSize(width, height);
}
void display() {
push();
rectMode(CENTER);
noStroke();
fill(this.bgColor);
rect(0, 0, size.x, size.y);
pop();
}
}

// 3.9. Components

// 3.9.1. ComponentType

enum ComponentType {
COMPONENT, COMPONENT2D, TEST, PRINTTREEONCE, SPRITE2D, ROTATION, TIMER,
GUICOMPONENT
}

// 3.9.2. Component

class Component { // almost abstract !
String name;
ComponentType componentType;

Component(String name) {
this.name=name;
componentType=ComponentType.COMPONENT;
}

void ready(Node n) {
}

void process(Node n, float delta) {
}

void signal(Node n, PEvent pEvent) {
}

void input(Node n, PEvent pEvent) {
}

void display(Node n) {
}
}

// 3.9.3. Component2D

class Component2D { // almost abstract !
String name;
ComponentType componentType;

Component2D(String name) {
this.name=name;
componentType=ComponentType.COMPONENT2D;
}

void ready(Node2D n) {
}

void process(Node2D n, float delta) {
}

void signal(Node2D n, PEvent pEvent) {
}

void input(Node2D n, PEvent pEvent) {
}

void display(Node2D n) {
}
}

// 3.9.4. Sprite2D

class Sprite2D extends Component2D {

PImage image;

Sprite2D(String name, PImage image) {
super(name);
componentType=ComponentType.SPRITE2D;
this.image=image;
}

void ready(Node2D n) {
n.size.set(image.width, image.height);
}

void display(Node2D n) {
image(image, 0, 0);
if (pengine.debug) {
push();
rectMode(CENTER);
stroke(255, 0, 0);
noFill();
rect(0, 0, n.size.x, n.size.y);
fill(255, 0, 0);
circle(0, 0, 20);
pop();
}
}
}

// 3.9.5. Rotation

class Rotation extends Component2D {

float rotation;

Rotation(String name, float rotation) {
super(name);
componentType=ComponentType.ROTATION;
this.rotation=rotation;
}

void process(Node2D n, float delta) {
n.rotation+=rotation*delta;
}
}

// 3.9.6. Timer

class Timer extends Component2D {

float time; // seconds
float _start; // seconds
boolean isOn;
int loop; // loop number (infinite if 0)
int _loopCount;

Timer(String name, float time) {
super(name);
componentType=ComponentType.TIMER;
this.time=time;
isOn=false;
loop=0;
_loopCount=0;
}

Timer setOn() {
isOn=true;
if (frameCount!=0) { // not called in setup() !
_start=millis()/1000;
_loopCount=0;
}
return this;
}

Timer setLoop(int loop) {
this.loop=loop;
return this;
}

void ready(Node2D n) {
if (isOn) {
_start=millis()/1000;
}
}

void process(Node2D n, float delta) {
if (isOn && (millis()/1000) >= (_start+time) ) {
n.signal(new PEvent(EventType.TIMER, n));
_loopCount+=1;
if (loop==0 || _loopCount<=loop) {
_start=millis()/1000; // start Timer again
} else {
isOn=false;
}
}
}

//void signal(Node2D n, PEvent pEvent) {
// if (pEvent.eventType==EventType.TIMER && pEvent.source==this) {
// // DO something
// }
//}
}

// 3.9.7. Background


// 4. Physic Engine

// 5. GUI

// 5.1. Control

class Control extends Node2D {
GUIcomponent themeComponent;

Control(String name) {
super(name);
nodeType=NodeType.CONTROL;
}

void ready() {
pengine.theme.listen(this);
themeComponent=pengine.theme.getGUIcomponent(this);
super.ready();
}

void display() {
super.display();
if (themeComponent.themeType!=ThemeType.NULL) {
themeComponent.display(this);
} else {
if (pengine.debug) {
bugMessage("themeScript.themeType is NULL in "+name+" ("+nodeType+") !");
}
}
}

void signal(PEvent pEvent) {
super.signal(pEvent);
if (pEvent.eventType==EventType.THEME) {
themeComponent=pengine.theme.getGUIcomponent(this);
}
}
}

// 5.2. GUIcomponent

class GUIcomponent extends Component2D {
ThemeType themeType;
NodeType nodeType;

GUIcomponent(String name) {
super(name);
componentType=ComponentType.GUICOMPONENT;
themeType=ThemeType.NULL;
nodeType=NodeType.NULL;
}
}

// 5.3. Themes

// 5.3.1. ThemeType

enum ThemeType {
NULL, BASIC, FLAT, SF
}

// 5.3.2. Theme

class Theme implements Observable {
// Pour pouvoir indiquer aux widgets un changement de thème :
ArrayList widgets = new ArrayList();
// La "réserve de scripts" :
ArrayList components = new ArrayList<>();
ThemeType currentTheme;

Theme() {
currentTheme=ThemeType.FLAT;
}

// implements Observable

void listen(Node node) { // Les widgets écoutent pour être tenu au courant d'un changement de thème
widgets.add(node);
}

void notify(PEvent event) {// Indiquer un changement de thème
for (Node node : widgets) {
node.signal(event);
}
}

// End implements Observable

void addGUIcomponent(GUIcomponent component) {
components.add(component);
}

GUIcomponent getGUIcomponent(Control widget) {
GUIcomponent toReturn = new GUIcomponent("a GUI component");
for (GUIcomponent component : components) {
if (component.nodeType==widget.nodeType) {
if (component.themeType==currentTheme) {
return component;
} else {
if (component.themeType==ThemeType.BASIC) {
toReturn=component;
}
}
}
}
return toReturn;
}

void setTheme(ThemeType themeType) {
currentTheme=themeType;
notify(new PEvent(EventType.THEME, this));
}
} // End Theme

// 5.4. Focus

// 5.5. Languages

// 5.W. Widgets


// 5.W.1. Slider

// 5.W.1.1. Slider class

class Slider extends Control {
float percent=0;
Slider(String name) {
super(name);
nodeType=NodeType.SLIDER;
}

Slider setSize(float w, float h) {
return (Slider) super.setSize(w, h);
}

Slider setPercent(float percent) {
this.percent=percent;
return this;
}

Slider setPosition(float x, float y) {
super.setPosition(x, y);
return this;
}
}

// 5.W.1.2. Slider GUIscript for FLAT

class SliderBASIC extends GUIcomponent {
SliderBASIC(String name) {
super(name);
themeType=ThemeType.BASIC;
nodeType=NodeType.SLIDER;
}
void display(Node2D n) {
push();
stroke(200);
strokeWeight(5);
noFill();
rectMode(CENTER);
Slider s = (Slider) n;
rect(0, 0, s.size.x, s.size.y);
noStroke();
fill(0);
if (s.percent!=0) {
{
rectMode(CORNER);
rect(s.topLeft().x, s.topLeft().y, s.size.x*s.percent, s.size.y);
}
}
pop();
}
}

// 6. special

// 6.1. Preload

// Must be declared after Node2D class in JS !

PImage pLoadImage(String file) {
PImage image=loadImage(file);
pengine.preload.addImage(image);
return image;
}

/** For PengineJS compatibility
*/
PFont pLoadFont(String file) {
return loadFont(file);
}

class Preload extends Node2D {
ArrayList images = new ArrayList<>();
Boolean done= false;
Boolean wait = false;
float MAXTIME = 1.5;
int filesLoaded=0;
int filesToLoad=0;

Slider slider=new Slider("Preload Slider")
.setPercent(0)
.setPosition(0, 100)
.setSize(150, 30);

Preload() {
super("preload");
nodeType = NodeType.PRELOAD;
}

void addImage(PImage image) {
images.add(image);
}

void ready() {
addComponent(new Sprite2D("logo PEngine", loadImage("PEngine.png")));
addChild(slider);
Node2D star = new Node2D("Star").setPosition(50, 50)
.addComponent(new Sprite2D("logo Star", loadImage("logoP5.png")))
.addComponent(new Rotation("star rotation", 4));
star.scale=.4;
addChild(star);
filesToLoad=images.size();
}

void process(float delta) {
if (!wait) {
filesLoaded=0;
for (int i=0; i<images.size(); i++) {
if (images.get(i)!=null) {
filesLoaded+=1;
}
}
if (filesToLoad!=0) {
slider.percent=filesLoaded/filesToLoad;
}
if (filesLoaded==filesToLoad) {
wait=true;
slider.isToRemove=true;
Node2D hg = new Node2D("Hourglass").setPosition(0, 100)
.addComponent(new Sprite2D("Preload hourglass", loadImage("data/hourglass.png")))
.addComponent(new Rotation("hourglass rotation", 2));
hg.scale=.8;
addChild(hg);
}
} else {
if ((millis()/1000)>MAXTIME) {
done=true;
}
}
if (done) {
pengine.setScene(pengine.preloadPreviousScene);
pengine.preloadPreviousScene=null;
pengine.preload=null;
}
}

void display() {
super.display();
}
}