@@ -9,10 +9,144 @@ Import MaxGUI.Drivers
9
9
Import BRL.Max2D
10
10
Import BRL.Pixmap
11
11
Import BRL.PNGLoader
12
+ Import BRL.Stream
13
+ Import BRL.EndianStream
12
14
13
15
'Version
14
- Global appVersion:String = " 1.1"
15
- Global appVersionDate:String = " 20 Sep 2019"
16
+ Global appVersion:String = " 1.2"
17
+ Global appVersionDate:String = " 21 Sep 2019"
18
+
19
+ Rem
20
+ ------- INDEXING ------------------------------------------------------------------------------------------------------
21
+ EndRem
22
+
23
+ Type TBitmapIndex
24
+ 'Color Value Bytes
25
+ Global palR:Byte [256 ]
26
+ Global palG:Byte [256 ]
27
+ Global palB:Byte [256 ]
28
+
29
+ 'Data Streams
30
+ Global dataStream:TStream
31
+
32
+ 'Load color table file
33
+ Function FLoadPalette (paletteFile:String )
34
+ Local index:Int
35
+ If FileSize(paletteFile) = 768
36
+ Local paletteStream:TStream = ReadFile(paletteFile)
37
+ For index = 0 To 255
38
+ palR[ index] = ReadByte(paletteStream)
39
+ palG[ index] = ReadByte(paletteStream)
40
+ palB[ index] = ReadByte(paletteStream)
41
+ Next
42
+ CloseStream paletteStream
43
+ EndIf
44
+ EndFunction
45
+
46
+ 'Indexed Bitmap File Writer
47
+ Function FPixmapToIndexedBitmap (image:TPixmap ,filename:String )
48
+ 'Foolproofing
49
+ If filename = " " Then
50
+ TAppFileIO.FRevertPrep()
51
+ Else
52
+ 'Variables
53
+ Local paletteIndex:Int
54
+ Local bmpWidth:Int , bmpWidthM4:Int
55
+ Local bmpHeight:Int
56
+ Local bmpSizeTotal:Int , bmpSizeTotalM4:Int
57
+
58
+ 'Dimensions calc
59
+ bmpWidth = PixmapWidth(image)
60
+ bmpWidthM4 = ((bmpWidth + 3 ) / 4 ) * 4
61
+ bmpHeight = PixmapHeight(image)
62
+
63
+ 'Filesize calc
64
+ bmpSizeTotal = (14 + 40 ) + (256 * 4 ) + (bmpWidthM4 * bmpHeight)
65
+ bmpSizeTotalM4 = ((bmpSizeTotal + 3 ) / 4 ) * 4
66
+
67
+ 'Begin writing BMP file manually
68
+ dataStream = WriteFile(filename)
69
+
70
+ '------ Bitmap File Header
71
+ 'Data is stored in little-endian format (least-significant byte first)
72
+ dataStream = LittleEndianStream(dataStream)
73
+
74
+ WriteShort(dataStream,19778 ) 'File ID (2 bytes (short)) - 19778 (deci) or 42 4D (hex) or BM (ascii) for bitmap
75
+ WriteInt(dataStream,bmpSizeTotalM4) 'File Size (4 bytes (signed int))
76
+ WriteShort(dataStream,0 ) 'Reserved (2 bytes)
77
+ WriteShort(dataStream,0 ) 'Reserved (2 bytes)
78
+ WriteInt(dataStream,54 ) 'Pixel Array Offset (4 bytes) - pixel array starts at 54th byte
79
+
80
+ '------ DIB Header (File Info)
81
+ WriteInt(dataStream,40 ) 'DIB Header Size (4 bytes) - 40 bytes
82
+ WriteInt(dataStream,bmpWidth) 'Bitmap Width (4 bytes)
83
+ WriteInt(dataStream,bmpHeight) 'Bitmap Height (4 bytes)
84
+ WriteShort(dataStream,1 ) 'Color Planes (2 bytes) - Must be 1
85
+ WriteShort(dataStream,8 ) 'Color Depth (2 bytes) - Bits Per Pixel
86
+ WriteInt(dataStream,0 ) 'Compression Method (4 bytes) - 0 equals BI_RGB (no compression)
87
+ WriteInt(dataStream,bmpSizeTotalM4) 'Size of the raw bitmap data (4 bytes) - 0 can be given for BI_RGB bitmaps
88
+ WriteInt(dataStream,2835 ) 'Horizontal resolution of the image (4 bytes) - Pixels Per Metre (2835 PPM equals 72.009 DPI/PPI)
89
+ WriteInt(dataStream,2835 ) 'Vertical resolution of the image (4 bytes) - Pixels Per Metre (2835 PPM equals 72.009 DPI/PPI)
90
+ WriteInt(dataStream,256 ) 'Number of colors in the color palette (4 bytes)
91
+ WriteInt(dataStream,0 ) 'Number of important colors (4 bytes) - 0 when every color is important
92
+
93
+ '------ Color Table
94
+ For paletteIndex = 0 To 255
95
+ WriteByte(dataStream,palB[ paletteIndex] ) 'Blue (4 bytes) - offset 54
96
+ WriteByte(dataStream,palG[ paletteIndex] ) 'Green (4 bytes) - offset 58
97
+ WriteByte(dataStream,palR[ paletteIndex] ) 'Red (4 bytes) - offset 62
98
+ WriteByte(dataStream,0 ) 'Alpha (4 bytes) - offset 66
99
+ Next
100
+
101
+ '------ Pixel Array
102
+ Local px:Int , py:Int
103
+ Local pixelData:Long
104
+ Local bestIndex:Int = 0
105
+ Local magenta:Int = 16711935
106
+ For py = bmpHeight - 1 To 0 Step - 1
107
+ For px = 0 To bmpWidthM4 - 1
108
+ 'if a valid pixel on canvas
109
+ If px < bmpWidth
110
+ 'Read pixel data
111
+ pixelData = ReadPixel(image,px,py)
112
+ 'skip diffing magenta
113
+ If pixelData = 16711935 Then
114
+ WriteByte(dataStream,1 )
115
+ Else
116
+ 'Check all color indexes for best match by pythagora
117
+ Local R:Int , G:Int , B:Int
118
+ Local RDIFF:Int , GDIFF:Int , BDIFF:Int
119
+ Local bestDistance:Int = 17000000
120
+ Local distance:Int = 0
121
+ For paletteIndex = 0 To 255
122
+ R = (pixelData & $00FF0000 ) Shr 16
123
+ G = (pixelData & $FF00 ) Shr 8
124
+ B = (pixelData & $FF )
125
+ RDIFF = Abs(R - palR[ paletteIndex] )
126
+ GDIFF = Abs(G - palG[ paletteIndex] )
127
+ BDIFF = Abs(B - palB[ paletteIndex] )
128
+ distance = (RDIFF^ 2 + GDIFF^ 2 + BDIFF^ 2 )
129
+ If distance <= bestDistance Then
130
+ bestIndex = paletteIndex
131
+ bestDistance = distance
132
+ EndIf
133
+ Next
134
+ EndIf
135
+ WriteByte(dataStream,bestIndex)
136
+ Else
137
+ WriteByte(dataStream,0 ) 'line padding
138
+ EndIf
139
+ Next
140
+ Next
141
+ 'eof padding
142
+ For paletteIndex = 1 To bmpSizeTotalM4 - bmpSizeTotal
143
+ WriteByte(dataStream,0 )
144
+ Next
145
+ 'Writing file finished, close stream
146
+ CloseStream(dataStream)
147
+ EndIf
148
+ EndFunction
149
+ EndType
16
150
17
151
Rem
18
152
------- FILE IO -------------------------------------------------------------------------------------------------------
@@ -22,20 +156,23 @@ EndRem
22
156
Global importedFile:String = Null
23
157
Global exportedFile:String = Null
24
158
159
+ 'File Filters
160
+ Global fileFilters:String
161
+
25
162
Type TAppFileIO
26
163
'Save Bools
164
+ Global saveAsIndexed:Int = False
27
165
Global prepForSave:Int = False
28
166
Global rdyForSave:Int = False
29
167
Global runOnce:Int = False
30
- 'File Filters
31
- Global fileFilers:String = " Image Files:png,jpg,bmp"
168
+
32
169
'Output copy for saving
33
170
Global tempOutputImage:TPixmap
34
171
35
172
'Load Source Image
36
173
Function FLoadFile ()
37
174
Local oldImportedFile:String = importedFile
38
- importedFile = RequestFile(" Select graphic file to open" ,fileFilers )
175
+ importedFile = RequestFile(" Select graphic file to open" ," Image Files:png,bmp,jpg " )
39
176
'Foolproofing
40
177
If importedFile = Null Then
41
178
importedFile = oldImportedFile
@@ -67,13 +204,17 @@ Type TAppFileIO
67
204
68
205
'Save Output Content To File
69
206
Function FSaveFile ()
70
- exportedFile = RequestFile(" Save graphic output" ,fileFilers ,True )
207
+ exportedFile = RequestFile(" Save graphic output" ,fileFilters ,True )
71
208
'Foolproofing
72
209
If exportedFile = importedFile Then
73
210
Notify(" Cannot overwrite source image!" ,True )
74
211
ElseIf exportedFile <> importedFile Then
75
212
'Writing new file
76
- SavePixmapPNG(tempOutputImage,exportedFile)
213
+ If saveAsIndexed = True
214
+ TBitmapIndex.FPixmapToIndexedBitmap(tempOutputImage,exportedFile)
215
+ Else
216
+ SavePixmapPNG(tempOutputImage,exportedFile)
217
+ EndIf
77
218
FRevertPrep()
78
219
Else
79
220
'On Cancel
86
227
------- OUTPUT ELEMENTS -----------------------------------------------------------------------------------------------
87
228
EndRem
88
229
89
- 'Output Window Title
90
- AppTitle = " CCCP Bender v" + appVersion+ " - Output"
91
-
92
230
Type TAppOutput
93
231
'Output Window
94
232
Global outputWindow:TGraphics
@@ -252,7 +390,12 @@ Type TAppOutput
252
390
Next
253
391
SetRotation(0 )
254
392
'Output copy for saving
255
- TAppFileIO.tempOutputImage = GrabPixmap(0 ,96 ,768 ,384 )
393
+ If TAppFileIO.saveAsIndexed = True Then
394
+ 'If saving indexed grab a smaller pixmap to speed up indexing
395
+ TAppFileIO.tempOutputImage = GrabPixmap(55 ,120 ,34 *FRAMES,210 )
396
+ Else
397
+ TAppFileIO.tempOutputImage = GrabPixmap(0 ,96 ,768 ,384 )
398
+ EndIf
256
399
Flip(1 )
257
400
If TAppFileIO.prepForSave
258
401
TAppFileIO.FPrepForSave()
@@ -305,7 +448,7 @@ Type TAppGUI
305
448
Global editSaveButton:TGadget
306
449
Global editQuitButton:TGadget
307
450
'Editor Window Settings
308
- Global editSettingsPalel :TGadget
451
+ Global editSettingsPanel :TGadget
309
452
Global editSettingsZoomTextbox:TGadget
310
453
Global editSettingsFramesTextbox:TGadget
311
454
Global editSettingsColorRTextbox:TGadget
@@ -317,12 +460,14 @@ Type TAppGUI
317
460
Global editSettingsColorRLabel:TGadget
318
461
Global editSettingsColorGLabel:TGadget
319
462
Global editSettingsColorBLabel:TGadget
463
+ Global editSettingsIndexedLabel:TGadget
464
+ Global editSettingsIndexedCheckbox:TGadget
320
465
'Editor Window Help
321
466
Global editHelpPanel:TGadget
322
467
Global editHelpTextbox:TGadget
323
468
'Textboxes content
324
469
Global aboutTextboxContent:String [7 ]
325
- Global helpTextboxContent:String [15 ]
470
+ Global helpTextboxContent:String [17 ]
326
471
327
472
'Create Main App Window
328
473
Function FAppMain ()
@@ -353,19 +498,21 @@ Type TAppGUI
353
498
editLoadButton = CreateButton(" Load" ,6 ,0 ,80 ,30 ,editWindowButtonPanel,BUTTON_PUSH)
354
499
editSaveButton = CreateButton(" Save" ,96 ,0 ,80 ,30 ,editWindowButtonPanel,BUTTON_PUSH)
355
500
editQuitButton = CreateButton(" Quit" ,186 ,0 ,80 ,30 ,editWindowButtonPanel,BUTTON_PUSH)
356
- editSettingsPalel = CreatePanel(10 ,73 ,280 ,87 ,editWindow,PANEL_GROUP," Settings : " )
357
- editSettingsZoomTextbox = CreateTextField(80 ,12 ,30 ,20 ,editSettingsPalel)
358
- editSettingsFramesTextbox = CreateTextField(190 ,12 ,30 ,20 ,editSettingsPalel)
359
- editSettingsColorRTextbox = CreateTextField(80 ,42 ,30 ,20 ,editSettingsPalel)
360
- editSettingsColorGTextbox = CreateTextField(135 ,42 ,30 ,20 ,editSettingsPalel)
361
- editSettingsColorBTextbox = CreateTextField(190 ,42 ,30 ,20 ,editSettingsPalel)
362
- editSettingsZoomLabel = CreateLabel(" Zoom:" ,10 ,15 ,50 ,20 ,editSettingsPalel,LABEL_LEFT)
363
- editSettingsFramesLabel = CreateLabel(" Frames:" ,120 ,15 ,50 ,20 ,editSettingsPalel,LABEL_LEFT)
364
- editSettingsColorLabel = CreateLabel(" BG Color:" ,10 ,45 ,50 ,20 ,editSettingsPalel,LABEL_LEFT)
365
- editSettingsColorRLabel = CreateLabel(" R:" ,65 ,45 ,50 ,20 ,editSettingsPalel,LABEL_LEFT)
366
- editSettingsColorGLabel = CreateLabel(" G:" ,120 ,45 ,50 ,20 ,editSettingsPalel,LABEL_LEFT)
367
- editSettingsColorBLabel = CreateLabel(" B:" ,175 ,45 ,50 ,20 ,editSettingsPalel,LABEL_LEFT)
368
- editHelpPanel = CreatePanel(10 ,170 ,280 ,250 ,editWindow,PANEL_GROUP," Help : " )
501
+ editSettingsPanel = CreatePanel(10 ,73 ,280 ,120 ,editWindow,PANEL_GROUP," Settings : " )
502
+ editSettingsZoomTextbox = CreateTextField(80 ,12 ,30 ,20 ,editSettingsPanel)
503
+ editSettingsFramesTextbox = CreateTextField(190 ,12 ,30 ,20 ,editSettingsPanel)
504
+ editSettingsColorRTextbox = CreateTextField(80 ,42 ,30 ,20 ,editSettingsPanel)
505
+ editSettingsColorGTextbox = CreateTextField(135 ,42 ,30 ,20 ,editSettingsPanel)
506
+ editSettingsColorBTextbox = CreateTextField(190 ,42 ,30 ,20 ,editSettingsPanel)
507
+ editSettingsZoomLabel = CreateLabel(" Zoom:" ,10 ,15 ,50 ,20 ,editSettingsPanel,LABEL_LEFT)
508
+ editSettingsFramesLabel = CreateLabel(" Frames:" ,120 ,15 ,50 ,20 ,editSettingsPanel,LABEL_LEFT)
509
+ editSettingsColorLabel = CreateLabel(" BG Color:" ,10 ,45 ,50 ,20 ,editSettingsPanel,LABEL_LEFT)
510
+ editSettingsColorRLabel = CreateLabel(" R:" ,65 ,45 ,50 ,20 ,editSettingsPanel,LABEL_LEFT)
511
+ editSettingsColorGLabel = CreateLabel(" G:" ,120 ,45 ,50 ,20 ,editSettingsPanel,LABEL_LEFT)
512
+ editSettingsColorBLabel = CreateLabel(" B:" ,175 ,45 ,50 ,20 ,editSettingsPanel,LABEL_LEFT)
513
+ editSettingsIndexedLabel = CreateLabel(" Save as Indexed Bitmap:" ,10 ,75 ,130 ,20 ,editSettingsPanel,LABEL_LEFT)
514
+ editSettingsIndexedCheckbox = CreateButton(" " ,140 ,73 ,20 ,20 ,editSettingsPanel,BUTTON_CHECKBOX)
515
+ editHelpPanel = CreatePanel(10 ,203 ,280 ,250 ,editWindow,PANEL_GROUP," Help : " )
369
516
editHelpTextbox = CreateTextArea(7 ,5 ,GadgetWidth(editHelpPanel)- 21 ,GadgetHeight(editHelpPanel)- 32 ,editHelpPanel,TEXTAREA_WORDWRAP| TEXTAREA_READONLY)
370
517
SetGadgetText(editSettingsZoomTextbox,TAppOutput.ZOOM)
371
518
SetGadgetText(editSettingsFramesTextbox,TAppOutput.FRAMES)
@@ -387,8 +534,10 @@ Type TAppGUI
387
534
helpTextboxContent[ 11 ] = " FRAMES: ~n This sets the amount of frames output will generate. ~n~n Accepts values from 1 to 20. ~n~n "
388
535
helpTextboxContent[ 12 ] = " - Note : ~n Limb bending will automatically adjust to number of frames. ~n~n "
389
536
helpTextboxContent[ 13 ] = " BG COLOR R,G,B: ~n This changes the background color of the output. ~n~n Accepts values from 0 to 255. ~n~n "
390
- helpTextboxContent[ 14 ] = " - Note : ~n When saving file, the output will automatically set background to magenta, so no manual setting before saving is needed."
391
- SetGadgetText(TAppGUI.editHelpTextbox,helpTextboxContent[ 0 ] + helpTextboxContent[ 1 ] + helpTextboxContent[ 2 ] + helpTextboxContent[ 3 ] + helpTextboxContent[ 4 ] + helpTextboxContent[ 5 ] + helpTextboxContent[ 6 ] + helpTextboxContent[ 7 ] + helpTextboxContent[ 8 ] + helpTextboxContent[ 9 ] + helpTextboxContent[ 10 ] + helpTextboxContent[ 11 ] + helpTextboxContent[ 12 ] + helpTextboxContent[ 13 ] + helpTextboxContent[ 14 ] );
537
+ helpTextboxContent[ 14 ] = " - Note : ~n When saving file, the output will automatically set background to magenta, so no manual setting before saving is needed. ~n~n "
538
+ helpTextboxContent[ 15 ] = " SAVE AS INDEXED BITMAP : ~n When ticked the output will be saved as a BMP file indexed to the CC palette. ~n When not ticked, output will be saved as a non-indexed PNG. ~n~n "
539
+ helpTextboxContent[ 16 ] = " - Warning : ~n THE INDEXING PROCESS IS SLOW! ~n I've done my best to speed it up but it still isn't blazing fast like PNG saving. ~n When saving indexed, the app may hang and appear unresponsive but in fact it's doing what it's supposed to. ~n For best results, DO NOT TOUCH ANYTHING until the background color reverts from magenta to whatever it was before!"
540
+ SetGadgetText(TAppGUI.editHelpTextbox,helpTextboxContent[ 0 ] + helpTextboxContent[ 1 ] + helpTextboxContent[ 2 ] + helpTextboxContent[ 3 ] + helpTextboxContent[ 4 ] + helpTextboxContent[ 5 ] + helpTextboxContent[ 6 ] + helpTextboxContent[ 7 ] + helpTextboxContent[ 8 ] + helpTextboxContent[ 9 ] + helpTextboxContent[ 10 ] + helpTextboxContent[ 11 ] + helpTextboxContent[ 12 ] + helpTextboxContent[ 13 ] + helpTextboxContent[ 14 ] + helpTextboxContent[ 15 ] + helpTextboxContent[ 16 ] );
392
541
'Delete no longer used MainWindow
393
542
FreeGadget(mainWindow)
394
543
EndFunction
@@ -398,6 +547,7 @@ Type TAppGUI
398
547
If Not mainToEdit And importedFile <> Null Then
399
548
FAppEditor()
400
549
TAppOutput.FOutputBoot()
550
+ TBitmapIndex.FLoadPalette(" assets/palette.act" )
401
551
mainToEdit = True
402
552
EndIf
403
553
EndFunction
@@ -410,6 +560,7 @@ EndRem
410
560
New TAppGUI
411
561
New TAppOutput
412
562
New TAppFileIO
563
+ New TBitmapIndex
413
564
TAppGUI.FAppMain()
414
565
415
566
Rem
@@ -421,12 +572,19 @@ While True
421
572
TAppGUI.FAppUpdate()
422
573
Else
423
574
TAppOutput.FOutputUpdate()
575
+ If ButtonState(TAppGUI.editSettingsIndexedCheckbox) = True Then
576
+ fileFilters = " Image Files:bmp"
577
+ TAppFileIO.saveAsIndexed = True
578
+ Else
579
+ fileFilters = " Image Files:png"
580
+ TAppFileIO.saveAsIndexed = False
581
+ EndIf
424
582
EndIf
425
583
426
584
WaitEvent
427
585
'Print CurrentEvent.ToString()
428
586
429
- 'Event Responses
587
+ 'Event Responses
430
588
'In Main Window
431
589
If Not TAppGUI.mainToEdit Then
432
590
Select EventID()
@@ -443,7 +601,7 @@ While True
443
601
Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE
444
602
Exit
445
603
EndSelect
446
- 'In Editor Window
604
+ 'In Editor Window
447
605
ElseIf TAppGUI.mainToEdit Then
448
606
Select EventID()
449
607
Case EVENT_APPRESUME
0 commit comments