Skip to content

Commit 79b26ed

Browse files
committed
New Texture Editor for basic texture edits.
1 parent 7da3393 commit 79b26ed

File tree

10 files changed

+283
-20
lines changed

10 files changed

+283
-20
lines changed

resources/textures/ui/pbwhite.png

263 Bytes
Loading

resources/textures/white.png

174 Bytes
Loading

src/net/fexcraft/app/fmt/FMTB.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ public void setupUI(UserInterface ui){
273273
ui.getElements().put("helpertree", new HelperTree());
274274
ui.getElements().put("preview_editor", new PreviewEditor());
275275
ui.getElements().put("model_editor", new ModelEditor());
276+
ui.getElements().put("texture_editor", new net.fexcraft.app.fmt.ui.editor.TextureEditor());
276277
//
277278
ui.getElements().put("z_crossbar", new Crossbar());
278279
ui.getElements().put(TOOLBARID, new Toolbar());

src/net/fexcraft/app/fmt/ui/editor/Editor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,12 @@ public TextField getField(String string){
7878
return (TextField)elements.get(string);
7979
}
8080

81+
public Button getButton(String string){
82+
return (Button)elements.get(string);
83+
}
84+
85+
public static Editor get(String string){
86+
for(Editor edit : editors) if(edit.id.equals(string)) return edit; return null;
87+
}
88+
8189
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package net.fexcraft.app.fmt.ui.editor;
2+
3+
import org.newdawn.slick.Color;
4+
5+
import net.fexcraft.app.fmt.ui.Element;
6+
import net.fexcraft.app.fmt.ui.generic.Button;
7+
import net.fexcraft.app.fmt.ui.generic.TextField;
8+
import net.fexcraft.app.fmt.utils.TextureManager;
9+
import net.fexcraft.lib.common.math.RGB;
10+
11+
public class TextureEditor extends Editor {
12+
13+
public static RGB CURRENTCOLOR = new RGB(RGB.WHITE);
14+
private static final int rows = 9, colls = 32;
15+
private static RGB[] pallete = new RGB[rows * rows];
16+
private static RGB[] hopall = new RGB[36];
17+
public static boolean BUCKETMODE;
18+
private static RGB buttonhover;
19+
20+
public TextureEditor(){
21+
super("texture_editor");
22+
TextureManager.loadTexture("ui/pbwhite");
23+
final RGB rgb = new RGB(127, 127, 255);
24+
//
25+
for(int i = 0; i < 3; i++){
26+
final int j = i;
27+
this.elements.put("rgb" + i + "-", new Button(this, "rgb" + i + "-", 12, 26, 4 + (98 * i), 30, rgb){
28+
@Override protected boolean processButtonClick(int x, int y, boolean left){ return updateRGB(false, j); }
29+
}.setText(" < ", true).setTexture("ui/background").setLevel(-1));
30+
this.elements.put("rgb" + i, new TextField(this, "rgb" + i, 70, 16 + (98 * i), 30){
31+
@Override public void updateNumberField(){ updateRGB(null, j); }
32+
@Override protected boolean processScrollWheel(int wheel){ return updateRGB(wheel > 0, j); }
33+
}.setAsNumberfield(0, 255, true).setLevel(-1));
34+
this.elements.put("rgb" + i + "+", new Button(this, "rgb" + i + "+", 12, 26, 86 + (98 * i), 30, rgb){
35+
@Override protected boolean processButtonClick(int x, int y, boolean left){ return updateRGB(true, j); }
36+
}.setText(" > ", true).setTexture("ui/background").setLevel(-1));
37+
}
38+
//
39+
this.elements.put("large_color_palette", new LargePallette(this, 4, 80));
40+
this.elements.put("horizontal_color_palette", new HorizontalPallette(this, 4, 410));
41+
this.elements.put("button", new Button(this, "button", 294, 28, 4, 460, buttonhover = new RGB(CURRENTCOLOR)){
42+
@Override
43+
protected boolean processButtonClick(int x, int y, boolean left){
44+
toggleBucketMode(); return true;
45+
}
46+
}.setText("Paint Bucket [OFF]", true).setTexture("ui/pbwhite"));
47+
//
48+
this.updateFields();
49+
}
50+
51+
public static void toggleBucketMode(){
52+
BUCKETMODE = !BUCKETMODE; Editor.get("texture_editor").getButton("button").setText("Paint Bucket [" + (BUCKETMODE ? "ON" : "OFF") + "]", true);
53+
}
54+
55+
private void updateFields(){
56+
byte[] arr = CURRENTCOLOR.toByteArray();
57+
this.getField("rgb0").applyChange(arr[0] + 128);
58+
this.getField("rgb1").applyChange(arr[1] + 128);
59+
this.getField("rgb2").applyChange(arr[2] + 128);
60+
//
61+
for(int x = 0; x < rows; x++){
62+
for(int z = 0; z < rows; z++){
63+
int y = x * rows + z;
64+
float e = (1f / (rows * rows)) * y, f = (1f / rows) * z, h = (255 / rows) * x;
65+
int r = (int)Math.abs((e * (arr[0] + 128)) + ((1 - f) * h));
66+
int g = (int)Math.abs((e * (arr[1] + 128)) + ((1 - f) * h));
67+
int l = (int)Math.abs((e * (arr[2] + 128)) + ((1 - f) * h));
68+
pallete[x + (z * rows)] = new RGB(r, g, l);
69+
}
70+
}
71+
//
72+
buttonhover.packed = CURRENTCOLOR.packed;
73+
}
74+
75+
protected boolean updateRGB(Boolean apply, int j){
76+
TextField field = (TextField)getElement("rgb" + j);
77+
if(apply != null) field.applyChange(field.tryChange(apply, 8));
78+
if(CURRENTCOLOR == null) CURRENTCOLOR = new RGB(RGB.WHITE);
79+
byte[] arr = CURRENTCOLOR.toByteArray();
80+
byte colorr = (byte)(field.getIntegerValue() - 128);
81+
switch(j){
82+
case 0: CURRENTCOLOR = new RGB(colorr, arr[1], arr[2]); break;
83+
case 1: CURRENTCOLOR = new RGB(arr[0], colorr, arr[2]); break;
84+
case 2: CURRENTCOLOR = new RGB(arr[0], arr[1], colorr); break;
85+
} this.updateFields(); return true;
86+
}
87+
88+
@Override
89+
public void renderSelf(int rw, int rh){
90+
super.renderSelf(rw, rh); TextureManager.unbind();
91+
font.drawString(4, 40, "Manual RGB Input", Color.black);
92+
font.drawString(4, 90, "Large Palette", Color.black);
93+
font.drawString(4, 418, "Horizontal Palette", Color.black);
94+
RGB.glColorReset();
95+
}
96+
97+
public static class LargePallette extends Element {
98+
99+
public LargePallette(Element parent, int x, int y){
100+
super(parent, "large_color_palette"); this.height = width = 294;
101+
this.x = parent.x + x; this.y = parent.y + y; z = -1;
102+
}
103+
104+
@Override
105+
public void renderSelf(int rw, int rh){
106+
super.renderQuad(x, y, width, height, "white");
107+
for(int i = 0; i < rows; i++){
108+
for(int j = 0; j < rows; j++){
109+
pallete[i + (j * rows)].glColorApply();
110+
super.renderQuad(x + 3 + (i * colls), y + 3 + (j * colls), colls, colls, "white");
111+
RGB.glColorReset();
112+
}
113+
}
114+
}
115+
116+
@Override
117+
protected boolean processButtonClick(int x, int y, boolean left){
118+
int xx = (x - this.x - 3) / colls, yy = (y - this.y - 3) / colls; int zz = xx + (yy * rows);
119+
if(zz >= 0 && zz < pallete.length){
120+
CURRENTCOLOR = pallete[zz]; ((TextureEditor)parent).updateFields();
121+
} return true;
122+
}
123+
124+
}
125+
126+
public static class HorizontalPallette extends Element {
127+
128+
public HorizontalPallette(Element parent, int x, int y){
129+
super(parent, "horizontal_color_palette"); this.height = 40; this.width = 294;
130+
this.x = parent.x + x; this.y = parent.y + y; z = -1;
131+
}
132+
133+
@Override
134+
public void renderSelf(int rw, int rh){
135+
super.renderQuad(x, y, width, height, "white");
136+
if(hopall[0] == null){
137+
for(int i = 0; i < hopall.length; i ++){
138+
float c = i * (1f / hopall.length);
139+
int r, g, b;
140+
//
141+
if(c >= 0 && c <= (1/6.f)){
142+
r = 255;
143+
g = (int)(1530 * c);
144+
b = 0;
145+
}
146+
else if( c > (1/6.f) && c <= (1/3.f) ){
147+
r = (int)(255 - (1530 * (c - 1/6f)));
148+
g = 255;
149+
b = 0;
150+
}
151+
else if( c > (1/3.f) && c <= (1/2.f)){
152+
r = 0;
153+
g = 255;
154+
b = (int)(1530 * (c - 1/3f));
155+
}
156+
else if(c > (1/2f) && c <= (2/3f)) {
157+
r = 0;
158+
g = (int)(255 - ((c - 0.5f) * 1530));
159+
b = 255;
160+
}
161+
else if( c > (2/3f) && c <= (5/6f) ){
162+
r = (int)((c - (2/3f)) * 1530);
163+
g = 0;
164+
b = 255;
165+
}
166+
else if(c > (5/6f) && c <= 1 ){
167+
r = 255;
168+
g = 0;
169+
b = (int)(255 - ((c - (5/6f)) * 1530));
170+
}
171+
else{ r = 127; g = 127; b = 127; }
172+
hopall[i] = new RGB(r, g, b);
173+
}
174+
}
175+
for(int i = 0; i < hopall.length; i++){
176+
hopall[i].glColorApply(); super.renderQuad(x + 3 + (i * 8), y, 8, 40, "white"); RGB.glColorReset();
177+
}
178+
}
179+
180+
@Override
181+
protected boolean processButtonClick(int x, int y, boolean left){
182+
int xx = (x - this.x - 3) / 8;
183+
if(xx >= 0 && xx < hopall.length){
184+
CURRENTCOLOR = hopall[xx]; ((TextureEditor)parent).updateFields();
185+
} return true;
186+
}
187+
188+
}
189+
190+
}

src/net/fexcraft/app/fmt/ui/generic/Toolbar.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,13 @@ protected boolean processButtonClick(int x, int y, boolean left){
245245
Editor.toggle("model_editor"); return true;
246246
}
247247
}.setText("Model", false));
248+
//
249+
this.elements.put("texture", new Button(this, "texture", 100, 26, 2, 142, subhover){
250+
@Override
251+
protected boolean processButtonClick(int x, int y, boolean left){
252+
Editor.toggle("texture_editor"); return true;
253+
}
254+
}.setText("Texture (Plain)", false));
248255
}
249256
});
250257
break;

src/net/fexcraft/app/fmt/utils/GGR.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ private void acceptInputKeyboard(){
101101
if(key == Keyboard.KEY_3){ Editor.toggle("cylinder_editor", false); }
102102
if(key == Keyboard.KEY_4){ Editor.toggle("group_editor", false); }
103103
if(key == Keyboard.KEY_5){ Editor.toggle("model_editor", false); }
104+
if(key == Keyboard.KEY_6){ Editor.toggle("texture_editor", false); }
104105
if(key == Keyboard.KEY_F11){
105106
try{ Display.setFullscreen(Settings.toogleFullscreen()); }
106107
catch(Exception ex){ ex.printStackTrace(); }

src/net/fexcraft/app/fmt/utils/RayCoastAway.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import org.lwjgl.opengl.GL11;
1010

1111
import net.fexcraft.app.fmt.FMTB;
12+
import net.fexcraft.app.fmt.ui.editor.TextureEditor;
13+
import net.fexcraft.app.fmt.ui.generic.DialogBox;
14+
import net.fexcraft.app.fmt.utils.TextureManager.Texture;
1215
import net.fexcraft.app.fmt.wrappers.PolygonWrapper;
1316
import net.fexcraft.app.fmt.wrappers.TurboList;
1417

@@ -33,20 +36,40 @@ public static void doTest(boolean bool, boolean mouseoff){
3336
int id = new Color(((int) byteArray[0]) & 0xFF, ((int) byteArray[1]) & 0xFF, ((int) byteArray[2]) & 0xFF).getRGB() + 16777216;
3437
//Print.console(id + "-ID");
3538
buffer.clear(); PICKING = false; MOUSEOFF = false;
39+
PolygonWrapper wrapper = getSelected(id);
40+
if(wrapper == null) return;
41+
if(!TextureEditor.BUCKETMODE){
42+
boolean control = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL);
43+
boolean state = control ? wrapper.getList().selected : wrapper.selected;
44+
if(!Keyboard.isKeyDown(Keyboard.KEY_LMENU)) FMTB.MODEL.clearSelection();
45+
if(control){ wrapper.getList().selected = !state; }
46+
else{ wrapper.selected = !state; }
47+
FMTB.MODEL.updateFields();
48+
}
49+
else{
50+
Texture tex;
51+
if(FMTB.MODEL.texture == null || (tex = TextureManager.getTexture(FMTB.MODEL.texture, true)) == null){
52+
FMTB.showDialogbox("No Texture loaded.", "Cannot use Paint Bucket.", "ok", "toggle off", DialogBox.NOTHING, () -> { TextureEditor.toggleBucketMode(); });
53+
return;
54+
}
55+
if(wrapper.burnToTexture(tex, getSelectedFace(wrapper, id))){
56+
tex.rebind(); TextureManager.saveTexture(FMTB.MODEL.texture);
57+
}
58+
}
59+
}
60+
61+
private static int getSelectedFace(PolygonWrapper wrapper, int id){
62+
for(int i = 0; i < wrapper.color.length; i++) if(wrapper.color[i] == id) return i; return -1;
63+
}
64+
65+
private static PolygonWrapper getSelected(int id){
3666
for(TurboList list : FMTB.MODEL.getCompound().values()){
3767
for(PolygonWrapper wrapper : list){
3868
for(int col : wrapper.color){
39-
if(col == id){
40-
boolean control = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL);
41-
boolean state = control ? wrapper.getList().selected : wrapper.selected;
42-
if(!Keyboard.isKeyDown(Keyboard.KEY_LMENU)) FMTB.MODEL.clearSelection();
43-
if(control){ wrapper.getList().selected = !state; }
44-
else{ wrapper.selected = !state; }
45-
FMTB.MODEL.updateFields();
46-
}
69+
if(col == id) return wrapper;
4770
}
4871
}
49-
}
72+
} return null;
5073
}
5174

5275
}

src/net/fexcraft/app/fmt/wrappers/PolygonWrapper.java

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import com.google.gson.JsonObject;
99

10+
import net.fexcraft.app.fmt.ui.editor.TextureEditor;
1011
import net.fexcraft.app.fmt.utils.Settings;
1112
import net.fexcraft.app.fmt.utils.TextureManager.Texture;
1213
import net.fexcraft.lib.common.math.RGB;
@@ -234,20 +235,52 @@ public boolean burnToTexture(Texture tex, Integer face){
234235
Print.console("Polygon '" + turbolist.id + ":" + this.name() + "' has no texture data, skipping.");
235236
return false;
236237
}
237-
BufferedImage buff = tex.getImage(); int color = 0;
238-
for(int i = 0; i < texpos.length; i++){
239-
if(face != null && i != face) continue;
240-
float[][] ends = texpos[i]; if(ends == null || ends.length == 0) continue; color = new Color(something.getColor(i).packed).darker().darker().getRGB();
241-
for(float x = ends[0][0]; x < ends[1][0]; x += 0.5f){//double accuracy!
242-
for(float y = ends[0][1]; y < ends[1][1]; y += 0.5f){//double accuracy!
243-
if(x >= 0 && x <= buff.getWidth() && y >= 0 && y <= buff.getHeight()){
244-
buff.setRGB((int)x, (int)y, color);
245-
}
246-
else continue;
238+
BufferedImage buff = tex.getImage();
239+
if(face == null){
240+
for(int i = 0; i < texpos.length; i++){
241+
float[][] ends = texpos[i]; if(ends == null || ends.length == 0) continue;
242+
burn(buff, ends, new Color(something.getColor(i).packed).darker().darker().getRGB());
243+
}
244+
}
245+
else{
246+
if(this.getType().isCylinder()){
247+
int segs = (int)this.getFloat("cyl1", true, false, false);//segments
248+
float[][] ends = null;
249+
if(face < segs){
250+
ends = texpos[0];
251+
}
252+
else if(face < (segs * 2)){
253+
float per = (face - segs) * 100f / segs;
254+
//Print.console(false, new Object[]{ segs, face - segs, per });
255+
int i = 0; while((per -= 12.5f) > 0f) i++;
256+
//Print.console(false, new Object[]{ segs, face - segs, per, i });
257+
ends = i < 0 || i >= 8 ? null : texpos[i + 2];
247258
}
259+
else if(face < (segs * 3)){
260+
ends = texpos[1];
261+
} else return false;
262+
if(ends == null || ends.length == 0) return false;
263+
burn(buff, ends, new Color(TextureEditor.CURRENTCOLOR.packed).getRGB());
264+
}
265+
else if(this.getType().isCuboid()){
266+
float[][] ends = texpos[face]; if(ends == null || ends.length == 0) return false;
267+
burn(buff, ends, new Color(TextureEditor.CURRENTCOLOR.packed).getRGB());
268+
}
269+
else{
270+
Print.console("There is no known way of how to handle texture burning of '" + this.getType().name() + "'!");
248271
}
249272
}
250273
return true;
251274
}
252275

276+
private void burn(BufferedImage img, float[][] ends, int color){
277+
for(float x = ends[0][0]; x < ends[1][0]; x += 0.5f){
278+
for(float y = ends[0][1]; y < ends[1][1]; y += 0.5f){
279+
if(x >= 0 && x <= img.getWidth() && y >= 0 && y <= img.getHeight()){
280+
img.setRGB((int)x, (int)y, color);
281+
} else continue;
282+
}
283+
}
284+
}
285+
253286
}

src/net/fexcraft/app/fmt/wrappers/ShapeType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ public enum ShapeType {
55
BOX, SHAPEBOX, FLEXBOX, TRAPEZOID, FLEXTRAPEZOID, CYLINDER, SPHERE, OBJ;
66

77
public boolean isCuboid(){
8-
return this == BOX || this == SHAPEBOX || this== FLEXBOX || this==TRAPEZOID || this==FLEXTRAPEZOID;
8+
return this == BOX || this == SHAPEBOX || this == FLEXBOX || this == TRAPEZOID || this == FLEXTRAPEZOID;
99
}
1010

1111
public boolean isShapebox(){

0 commit comments

Comments
 (0)