1+ // GUICANVAS by @SalatielSauer (01/09/2023)
2+ // github.com/CubeScript/Sauer-GUICANVAS
3+ // the screen consists of a model with dozens of meshes, each mesh has an index that is used as a pixel;
4+ // the pixel color/texture is set using objskin <index>;
5+ // the model can be loaded in game with `mmodel guicanvas` or in a menu with `guimodelpreview " guicanvas" `;
6+ // this file must be executed (/exec guicanvas.cfg) at least once to enable the guicanvas.* commands.
7+
8+ guicanvas.previewMode = 0
9+ _guicanvasEditor = [
10+ notepadfile = $arg1
11+ newgui _ [ guistayopen [
12+ guinoautotab [
13+ guieditor $notepadfile -80 20
14+ textinit $notepadfile $notepadfile
15+ guilist [
16+ guilist [
17+ guifield notepadfile -25
18+ guilist [
19+ guibutton " ^f8save file" [textfocus $notepadfile; textsave $notepadfile] 0
20+ guibar
21+ guibutton " ^f1exec file" [textfocus $notepadfile; textexec $notepadfile] 0
22+ guibar
23+ guibutton " ^f8load file" [textfocus $notepadfile; textload $notepadfile] 0
24+ ]
25+ ]
26+ guibar
27+ guilist [
28+ guibutton " ^f1copy all" [textfocus $notepadfile; textselectall; textcopy] 0
29+ guibutton " ^f1paste" [textfocus $notepadfile; textpaste] 0
30+ ]
31+ guibar
32+ guilist [
33+ guibutton " ^f3clear all" [textfocus $notepadfile; textclear] 0
34+ ]
35+ guibar
36+ guilist [
37+ guicheckbox " ^f8show preview" guicanvas.previewMode
38+ guibutton " ^f1exec & preview" [textfocus $notepadfile; textexec $notepadfile; sleep 0 [guicanvas.refresh]; guicanvas.previewMode = 1] 0
39+ ]
40+ ]
41+ guistrut -2
42+ guialign 1 [guitextbox " GUICANVAS Editor 1.0" 0 0 0xccaacc]
43+
44+ if (guicanvas.previewMode) [
45+ guistrut -28
46+ guialign 1 [
47+ guistrut 10
48+ guimodelpreview " ../../packages/models/guicanvas" [] 1 10
49+ guistrut -8
50+ ]
51+ guistrut 8
52+ ]
53+ ]
54+ ]] 0
55+ showgui _
56+ ]
57+
58+ _guicanvas = [
59+ if (|| (! (getalias guicanvas)) (=s (getalias guicanvas) " " )) [
60+ guicanvas = [
61+ if (=s $arg1 " notepad" ) [_guicanvasEditor] [
62+ local canvas
63+ canvas = []
64+ loopfiles cfg " guicanvas" " cfg" [append canvas $cfg]
65+ inputcommand $arg1 [
66+ local isNum
67+ isNum = (&& (>= (strcode $commandbuf) 48) (<= (strcode $commandbuf) 57))
68+ if (! $isNum) [
69+ local newCanvas saveCanvas
70+ newCanvas = (concatword " guicanvas/" (strreplace $commandbuf " .cfg" " " ) " .cfg" )
71+ saveCanvas = [
72+ _filesystem.save @newCanvas (escape " exec ^" guicanvas.cfg^" ^n^nguicanvas.size 32 32 // this will try to use an existing screen or generate a new one^nguicanvas.background = ^" packages/textures/default.png^" ^n^nguicanvas.refreshRate = 0^nguicanvas.play [^n^t// your render commands go here^n^t// they will run every millisecond set by $guicanvas.refreshRate^n^n] [^n^t// this is the interface body^n^tguititle ^" my canvas^" ^n] 0 0^n^nguicanvas.refresh // this will draw the background and the pixels set with guicanvas.setPixel" ) [
73+ _guicanvasEditor @@newCanvas
74+ textfocus @@newCanvas
75+ textload @@newCanvas
76+ ]
77+ ]
78+ if (findfile $newCanvas) [
79+ inputcommand " 0" [
80+ if (= $commandbuf 0) [
81+ _guicanvasEditor @@newCanvas
82+ ] [
83+ @@saveCanvas
84+ ]
85+ ] (format " ^f8[GUICANVAS] ^f3warning^n^f7there is already a canvas with the same name in ^f5%1^f7^nuse ^f50 ^f~to load it or ^f51 ^f~to overwrite with preset.^n^f8>^f5" @newCanvas)
86+ ] [
87+ @saveCanvas
88+ ]
89+
90+ ] [
91+ exec (concatword " guicanvas/" (at (concat @@canvas) @commandbuf) " .cfg" )
92+ ]
93+ ] (concat " ^f8[GUICANVAS]^n^f7type a name to create a canvas, or a number to load:^n" (loopconcat i (listlen $canvas) [result (format " ^f1%1^f7: ^f8%2^n^f5" $i (at $canvas $i))]))
94+ ]
95+ ]
96+ guicanvas.width = 32
97+ guicanvas.height = 32
98+ guicanvas.pixels = []
99+ guicanvas.background = 1
100+ guicanvas.keepPixels = 0
101+ guicanvas.opacity = 1
102+ guicanvas.refreshRate = -1
103+
104+ // most of these are used only once and shouldn' t be changed accidentally,
105+ // but for the sake of variability options:
106+ _guicanvas.screenDir = "packages/models/guicanvas"
107+ _guicanvas.baseTextureBlack = "packages/skyboxes/black_up.jpg"
108+ _guicanvas.baseTextureWhite = "packages/skyboxes/white_ft.jpg"
109+ _guicanvas.baseTextureOpacity = "<grey>packages/skyboxes/cloud_ring.png"
110+
111+ _guicanvas.usedIndexes = []
112+ _guicanvas.lastRefresh = (getmillis)
113+
114+ guicanvas.resetPixels = [
115+ guicanvas.pixels = []
116+ _guicanvas.usedIndexes = []
117+ ]
118+
119+ guicanvas.setPixel = [
120+ local pixel_index pixel_texture
121+ pixel_index = (+ (* $arg2 $guicanvas.width) $arg1)
122+ if (= (indexof $_guicanvas.usedIndexes $pixel_index) -1) [
123+ // if arg3 is -1: arg3 is baseTextureOpacity, else: if arg4 is defined: arg3 arg4 arg5 are colors (baseTextureWhite), else: arg3 is custom texture path.
124+ pixel_texture = (? (= $arg3 -1) $_guicanvas.baseTextureOpacity (? (!=s $arg4 "") (concatword "<colorify:" $arg3 "/" $arg4 "/" $arg5 ">" $_guicanvas.baseTextureWhite) $arg3))
125+ guicanvas.pixels = (concatword $guicanvas.pixels "objskin " $pixel_index " ^"" $pixel_texture "^";")
126+ append _guicanvas.usedIndexes $pixel_index // prevents duplicate items in pixels list
127+ ]
128+ ]
129+
130+ guicanvas.refresh = [
131+ clearmodel (format "../../%1" $_guicanvas.screenDir)
132+ ]
133+
134+ guicanvas.fillRect = [
135+ local x y width height r g b
136+ x = $arg1
137+ y = $arg2
138+ width = $arg3
139+ height = $arg4
140+ r = $arg5
141+ g = $arg6
142+ b = $arg7
143+ loop i $width [
144+ loop j $height [
145+ guicanvas.setPixel (+ $x $i) (+ $y $j) $r $g $b
146+ ]
147+ ]
148+ ]
149+
150+ guicanvas.perspective = [
151+ modelpreviewpitch $arg1
152+ modelpreviewfov (max 10 $arg2)
153+ ]
154+
155+ guicanvas.onupdate = [
156+ if (!= $guicanvas.refreshRate -1) [
157+ if (>= (getmillis) $_guicanvas.lastRefresh) [
158+ _guicanvas.lastRefresh = (+ (getmillis) $guicanvas.refreshRate)
159+ do $arg1
160+ ]
161+ ]
162+ ]
163+
164+ guicanvas.play = [
165+ local onupdate action actionX actionY
166+ if (= $numargs 0) [
167+ arg1 = (getalias _guicanvas.playarg1)
168+ arg2 = (getalias _guicanvas.playarg2)
169+ arg3 = (getalias _guicanvas.playarg3)
170+ arg4 = (getalias _guicanvas.playarg4)
171+ ]
172+ onupdate = $arg1; _guicanvas.playarg1 = $arg1
173+ action = $arg2; _guicanvas.playarg2 = $arg2
174+ actionX = $arg3; _guicanvas.playarg3 = $arg3
175+ actionY = $arg4; _guicanvas.playarg4 = $arg4
176+
177+ _guicanvas.lastRefresh = (getmillis)
178+
179+ newgui guicanvas [
180+ guistrut -30
181+ guialign 0 [
182+ guistrut -35
183+ guialign 0 [
184+ guistrut 22
185+ guimodelpreview (format "../../%1" $_guicanvas.screenDir) "mapmodel" [] 15 0
186+ guistrut -10
187+ ]
188+ guistrut -35
189+ ]
190+
191+ guialign -1 [
192+ guilist [
193+ guistrut (+ -12 @@@actionY)
194+ guilist [
195+ guistrut @@@@actionX
196+ @@@@action
197+ guistrut (* @@@@actionX -1)
198+ ]
199+ guistrut (- 13 @@@actionY)
200+ ]
201+ guistrut 20
202+ ]
203+
204+ guicanvas.onupdate [
205+ @@onupdate
206+ ]
207+ ] 0
208+ showgui guicanvas
209+ ]
210+
211+ guicanvas.size = [
212+ if (= $numargs 0) [
213+ inputcommand (concat $guicanvas.width $guicanvas.height) [
214+ guicanvas.size (at $commandbuf 0) (at $commandbuf 1)
215+ sleep 0 [echo (concat "^f8[GUICANVAS] ^f1screen size set to" $guicanvas.width $guicanvas.height)]
216+ ] "^f8[GUICANVAS] ^f7screen size:^f5"
217+ ] [
218+ guicanvas.width = @arg1
219+ guicanvas.height = (? (=s @arg2 "") $guicanvas.width @arg2)
220+ ]
221+
222+ if (! (findfile (format "%1/canvas_%2x%3.obj" $_guicanvas.screenDir $guicanvas.width $guicanvas.height))) [
223+ sleep 0 [cleargui]
224+
225+ inputcommand " " [
226+ echo (format "^f8[GUICANVAS] ^f5generating file for screen %1x%2, this may take a while.." $guicanvas.width $guicanvas.height)
227+ sleep 0 [
228+ _guicanvas.genScreen $guicanvas.width $guicanvas.height 1 1 [
229+ local restart
230+ restart = [
231+ if (!=s (getalias _guicanvas.playarg1) "") [
232+ echo "^f8[GUICANVAS] ^f7restarting canvas"
233+ guicanvas.play $_guicanvas.playarg1 $_guicanvas.playarg2 $_guicanvas.playarg3 $_guicanvas.playarg4
234+ if (getalias guicanvas.onstart) [do $guicanvas.onstart; guicanvas.onstart = []]
235+ ]
236+ ]
237+ if (! (findfile (format "%1/obj.cfg" $_guicanvas.screenDir))) [
238+ _filesystem.save (format "%1/obj.cfg" $_guicanvas.screenDir) (escape $_guicanvas.screenCFG) [
239+ restart
240+ ]
241+ ] [restart]
242+
243+ ]
244+ ]
245+ ] (format "^f8[GUICANVAS]^t^n> ^f7The screen size ^f5%1^f7x^f5%2 ^f7is not yet available^npress ^f0enter ^f~to generate it or ^f3esc ^f~to cancel." $guicanvas.width $guicanvas.height)
246+ ] [if (getalias guicanvas.onstart) [do $guicanvas.onstart; guicanvas.onstart = []]]
247+ ]
248+
249+ guicanvas.genScreen = [
250+ local _obj warning checkobj
251+ _gscw = (? (=s $arg1 "") $guicanvas.width $arg1)
252+ _gsch = (? (=s $arg2 "") $guicanvas.height $arg2)
253+ _gscl = 1
254+ _gsct = 1
255+ _obj = (format "canvas_%1x%2.obj" $_gscw $_gsch)
256+ checkobj = [
257+ if (findfile (concatword $_guicanvas.screenDir "/" $_obj)) [
258+ warning = (concat "^f~The^f8" $_obj "^f~file ^f2is already in place^f~, are you sure you want to rewrite it? ")
259+ ] [
260+ warning = (format "You are about to ^f2create^f~ a ^f5%1^f~x^f5%2 ^f~screen, " $_gscw $_gsch)
261+ ]
262+ ]
263+ checkobj
264+ newgui _ [ guistayopen [
265+ guistrut -3
266+ guititle (format "^f8GUICANVAS screen generator^n^f5%1^f~x^f5%2 ^f~contains ^f5%3 ^f~pixels" $_gscw $_gsch (* $_gscw $_gsch))
267+ guistrut 2
268+ guialign 0 [
269+ guitext "^f5width: " 0
270+ guifield _gscw -5 [sleep 500 [guifadein @guifadein]; guifadein 0; guicanvas.genScreen $_gscw $_gsch]
271+ guistrut 1
272+ guitext "^f5height: " 0
273+ guifield _gsch -5 [sleep 500 [guifadein @guifadein]; guifadein 0; guicanvas.genScreen $_gscw $_gsch]
274+ guistrut 1
275+ guitext "^f5layers: " 0
276+ guifield _gscl -5
277+ ]
278+ guistrut 0.3
279+ guialign 0 [
280+ guicheckbox "textures support" _gsct 1 0
281+ ]
282+ guistrut 0.3
283+ guitextbox (concat @@warning "this operation may take a while depending on the screen size..") 45 0 0xffffff
284+ guialign 0 [
285+ guibutton (concat "^f8continue anyway") [
286+ _guicanvas.genScreen $_gscw $_gsch $_gscl $_gsct
287+ ]
288+ guistrut 1
289+ guibutton "^f3cancel" [cleargui] "exit"
290+ ]
291+ guistrut 1
292+ ]] 0
293+ showgui _
294+ ]
295+
296+ _guicanvas.genScreen = [
297+ local width height layers textures index x_offset y_offset buffer callback
298+ width = $arg1
299+ height = $arg2
300+ layers = $arg3
301+ textures = $arg4
302+ callback = $arg5
303+ // offsets for centering
304+ x_offset = (*f (+f (divf $width 2.0) 0.5) -1)
305+ y_offset = (-f (divf $height 2.0) 0.5)
306+ index = 0
307+ buffer = "# generated with GUICANVAS Screen Generator by @SalatielSauer^n"
308+ loop layer $layers [
309+ loop ri $height [
310+ local i
311+ i = (- $height $ri) // start from top row
312+ loop j $width [
313+ local v1 v2 v3 v4 uv start_vertex
314+
315+ // define the 4 vertices for the current plane, considering offsets for centering
316+ v1 = (format "v %1 %2 0.%3" (+f $j $x_offset) (+f $i $y_offset) $layer)
317+ v2 = (format "v %1 %2 0.%3" (+f (+f $j 1) $x_offset) (+f $i $y_offset) $layer)
318+ v3 = (format "v %1 %2 0.%3" (+f (+f $j 1) $x_offset) (+f (+f $i 1) $y_offset) $layer)
319+ v4 = (format "v %1 %2 0.%3" (+f $j $x_offset) (+f (+f $i 1) $y_offset) $layer)
320+
321+ // UV coordinates (standard plane unwrapping)
322+ uv = "vt 0 0^nvt 1 0^nvt 1 1^nvt 0 1^n"
323+
324+ // write the face (polygon) and UV using the above vertices
325+ // ' g' is equivalent to "export as groups" in Blender
326+ buffer = (format "%7g %1 ^n%2 ^n%3 ^n%4 ^n%5^n%6" $index $v1 $v2 $v3 $v4 (? $textures $uv "") $buffer)
327+ start_vertex = (+ (* $index 4) 1)
328+ index = (+ $index 1)
329+ buffer = (format "%5f %1/1 %2/2 %3/3 %4/4^n" $start_vertex (+ $start_vertex 1) (+ $start_vertex 2) (+ $start_vertex 3) $buffer)
330+ ]
331+ ]
332+ ]
333+
334+ _filesystem.save (format "%1/canvas_%2x%3.obj" $_guicanvas.screenDir $width $height) (escape $buffer) [
335+ if (findfile (format "%1/canvas_%2x%3.obj" $_guicanvas.screenDir @width @height)) [
336+ echo (format "^f8[GUICANVAS] ^f1screen saved successfully at ^f7%1/canvas_%2x%3.obj" $_guicanvas.screenDir @@width @@height)
337+ @@callback
338+ ] [
339+ error "^f8[GUICANVAS] ^f3could not save screen, try again"
340+ ]
341+ ]
342+ ]
343+
344+ _filesystem.write = [if (!=s $arg1 "") [append _filesystem.linesbuff (concatword "[" $arg1 "]")]]
345+ _filesystem.open = [_filesystem.linesbuff = []; newgui _ [guieditor @arg1 -1 1; textfocus @arg1; textload @arg1; cleargui]; showgui _; if $arg2 [sleep 0 [arg1 = (escape $textshow); arg2 = @arg1; nodebug [do (substr (strreplace (strreplace (strreplace (strreplace (concatword "^n" $textshow) ";" "^n") "//" "^^/^^/") "^n" "]^n _filesystem.write [") "[ ]" "^^n") 1)]; @arg2]]]
346+ _filesystem.save = [newgui _ [local content; content = @arg2; guifield content 1; textfocus content; textsave @arg1; cleargui];showgui _; sleep 0 [@arg3]]
347+
348+ _guicanvas.loadScreen = 1
349+ _guicanvas.screenCFG = [
350+ // the actual model configuration:
351+ objload (concatword "canvas_" $guicanvas.width "x" $guicanvas.height ".obj")
352+ mdlscale 100
353+ mdlspin -36
354+ mdlyaw -90
355+ mdlfullbright 1
356+ mdlalphatest $guicanvas.opacity
357+
358+ objcullface * 0
359+
360+ objdir "../.." // start at home/installation folder
361+ if (|| (!= $guicanvas.background 0) (!=s $guicanvas.background 0)) [
362+ objskin * (? (= $guicanvas.background 1) $_guicanvas.baseTextureBlack $guicanvas.background) // use black background as default (1)
363+ ] [
364+ objskin * $_guicanvas.baseTextureOpacity
365+ ]
366+
367+ do $guicanvas.pixels
368+ if (! $guicanvas.keepPixels) [
369+ guicanvas.pixels = []
370+ _guicanvas.usedIndexes = []
371+ ]
372+ ]
373+ ] [
374+ if (_guicanvas.loadScreen) [
375+ do $_guicanvas.screenCFG
376+ ] [_guicanvas.loadScreen = 1]
377+ ]
378+ ]
379+
380+ _guicanvas.loadScreen = 0
381+ _guicanvas
382+
383+ if (! (findfile (format "%1/obj.cfg" $_guicanvas.screenDir))) [
384+ // create model configuration file if not available
385+ _filesystem.save (format "%1/obj.cfg" $_guicanvas.screenDir) (escape $_guicanvas.screenCFG) [
386+ if (findfile (format "%1/obj.cfg" $_guicanvas.screenDir)) [
387+ echo "^f8[GUICANVAS] ^f7loaded successfully"
388+ ] [
389+ error (format "^f8[GUICANVAS] ^f3could not write ^f7%1/obj.cfg" $_guicanvas.screenDir)
390+ ]
391+ ]
392+ ] [echo "^f7GUICANVAS version: 1.0"]
0 commit comments