Skip to content

Commit 748341f

Browse files
authored
Merge pull request #2 from cortex-command-community/development
Merge v1.2 into Master
2 parents 552f9a2 + 2b779a1 commit 748341f

File tree

3 files changed

+193
-33
lines changed

3 files changed

+193
-33
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Arne's original bend code was used as base and has been modified and improved to
2121
- Frames number output setting.
2222
- Background color setting.
2323
- Automatic setting of background color to magenta on save.
24+
- Saving as PNG or Indexed BMP (CC Palette)
2425

2526
## How To
2627

@@ -32,16 +33,17 @@ Arne's original bend code was used as base and has been modified and improved to
3233
- **Warning:** When zooming the joint markers will reset to original positions. First zoom, then adjust.
3334
5. Use **Frames** setting to set number of bend frames.
3435
- Bend angle will adjust automatically. First/Last frames will always be fully bent/unbent.
35-
6. Hit save
36+
6. Decide whether you want to save as Indexed BMP or not - if yes, tick the "**Save as Indexed Bitmap**" checkbox.
37+
7. Hit save
3638
- Background color will automatically be set to magenta (255,0,255) when save is clicked and will revert back to previous color when finished.
37-
7. Slice the saved image into frames and apply palette.
39+
8. Slice the saved image into frames and apply palette.
3840
- Manually touch-up the exported frames if needed.
3941

4042
## Current Issues
4143

4244
- Joint adjustment is only on Y axis and adjusts upper/lower marker equally.
4345
- Works only with input files that are 24x24px tiled (for each limb part. Max input image size is 192x24px for 8 limb parts (4 limbs)).
44-
- Does not save files in .bmp format.
46+
- Files saved as Indexed BMPs have messed up thumbnails and do not open correctly in Photoshop. Tested to open correctly with MS Paint XP.
4547

4648
## Changelog
4749

assets/palette.act

768 Bytes
Binary file not shown.

cccp-bender-main.bmx

Lines changed: 188 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,144 @@ Import MaxGUI.Drivers
99
Import BRL.Max2D
1010
Import BRL.Pixmap
1111
Import BRL.PNGLoader
12+
Import BRL.Stream
13+
Import BRL.EndianStream
1214

1315
'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
16150

17151
Rem
18152
------- FILE IO -------------------------------------------------------------------------------------------------------
@@ -22,20 +156,23 @@ EndRem
22156
Global importedFile:String = Null
23157
Global exportedFile:String = Null
24158

159+
'File Filters
160+
Global fileFilters:String
161+
25162
Type TAppFileIO
26163
'Save Bools
164+
Global saveAsIndexed:Int = False
27165
Global prepForSave:Int = False
28166
Global rdyForSave:Int = False
29167
Global runOnce:Int = False
30-
'File Filters
31-
Global fileFilers:String = "Image Files:png,jpg,bmp"
168+
32169
'Output copy for saving
33170
Global tempOutputImage:TPixmap
34171

35172
'Load Source Image
36173
Function FLoadFile()
37174
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")
39176
'Foolproofing
40177
If importedFile = Null Then
41178
importedFile = oldImportedFile
@@ -67,13 +204,17 @@ Type TAppFileIO
67204

68205
'Save Output Content To File
69206
Function FSaveFile()
70-
exportedFile = RequestFile("Save graphic output",fileFilers,True)
207+
exportedFile = RequestFile("Save graphic output",fileFilters,True)
71208
'Foolproofing
72209
If exportedFile = importedFile Then
73210
Notify("Cannot overwrite source image!",True)
74211
ElseIf exportedFile <> importedFile Then
75212
'Writing new file
76-
SavePixmapPNG(tempOutputImage,exportedFile)
213+
If saveAsIndexed = True
214+
TBitmapIndex.FPixmapToIndexedBitmap(tempOutputImage,exportedFile)
215+
Else
216+
SavePixmapPNG(tempOutputImage,exportedFile)
217+
EndIf
77218
FRevertPrep()
78219
Else
79220
'On Cancel
@@ -86,9 +227,6 @@ Rem
86227
------- OUTPUT ELEMENTS -----------------------------------------------------------------------------------------------
87228
EndRem
88229

89-
'Output Window Title
90-
AppTitle = "CCCP Bender v"+appVersion+" - Output"
91-
92230
Type TAppOutput
93231
'Output Window
94232
Global outputWindow:TGraphics
@@ -252,7 +390,12 @@ Type TAppOutput
252390
Next
253391
SetRotation(0)
254392
'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
256399
Flip(1)
257400
If TAppFileIO.prepForSave
258401
TAppFileIO.FPrepForSave()
@@ -305,7 +448,7 @@ Type TAppGUI
305448
Global editSaveButton:TGadget
306449
Global editQuitButton:TGadget
307450
'Editor Window Settings
308-
Global editSettingsPalel:TGadget
451+
Global editSettingsPanel:TGadget
309452
Global editSettingsZoomTextbox:TGadget
310453
Global editSettingsFramesTextbox:TGadget
311454
Global editSettingsColorRTextbox:TGadget
@@ -317,12 +460,14 @@ Type TAppGUI
317460
Global editSettingsColorRLabel:TGadget
318461
Global editSettingsColorGLabel:TGadget
319462
Global editSettingsColorBLabel:TGadget
463+
Global editSettingsIndexedLabel:TGadget
464+
Global editSettingsIndexedCheckbox:TGadget
320465
'Editor Window Help
321466
Global editHelpPanel:TGadget
322467
Global editHelpTextbox:TGadget
323468
'Textboxes content
324469
Global aboutTextboxContent:String[7]
325-
Global helpTextboxContent:String[15]
470+
Global helpTextboxContent:String[17]
326471

327472
'Create Main App Window
328473
Function FAppMain()
@@ -353,19 +498,21 @@ Type TAppGUI
353498
editLoadButton = CreateButton("Load",6,0,80,30,editWindowButtonPanel,BUTTON_PUSH)
354499
editSaveButton = CreateButton("Save",96,0,80,30,editWindowButtonPanel,BUTTON_PUSH)
355500
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 : ")
369516
editHelpTextbox = CreateTextArea(7,5,GadgetWidth(editHelpPanel)-21,GadgetHeight(editHelpPanel)-32,editHelpPanel,TEXTAREA_WORDWRAP|TEXTAREA_READONLY)
370517
SetGadgetText(editSettingsZoomTextbox,TAppOutput.ZOOM)
371518
SetGadgetText(editSettingsFramesTextbox,TAppOutput.FRAMES)
@@ -387,8 +534,10 @@ Type TAppGUI
387534
helpTextboxContent[11] = "FRAMES: ~nThis sets the amount of frames output will generate. ~n~nAccepts values from 1 to 20. ~n~n"
388535
helpTextboxContent[12] = "- Note : ~nLimb bending will automatically adjust to number of frames. ~n~n"
389536
helpTextboxContent[13] = "BG COLOR R,G,B: ~nThis changes the background color of the output. ~n~nAccepts values from 0 to 255. ~n~n"
390-
helpTextboxContent[14] = "- Note : ~nWhen 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 : ~nWhen 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 : ~nWhen ticked the output will be saved as a BMP file indexed to the CC palette. ~nWhen not ticked, output will be saved as a non-indexed PNG. ~n~n"
539+
helpTextboxContent[16] = "- Warning : ~nTHE INDEXING PROCESS IS SLOW! ~nI've done my best to speed it up but it still isn't blazing fast like PNG saving. ~nWhen saving indexed, the app may hang and appear unresponsive but in fact it's doing what it's supposed to. ~nFor 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]);
392541
'Delete no longer used MainWindow
393542
FreeGadget(mainWindow)
394543
EndFunction
@@ -398,6 +547,7 @@ Type TAppGUI
398547
If Not mainToEdit And importedFile <> Null Then
399548
FAppEditor()
400549
TAppOutput.FOutputBoot()
550+
TBitmapIndex.FLoadPalette("assets/palette.act")
401551
mainToEdit = True
402552
EndIf
403553
EndFunction
@@ -410,6 +560,7 @@ EndRem
410560
New TAppGUI
411561
New TAppOutput
412562
New TAppFileIO
563+
New TBitmapIndex
413564
TAppGUI.FAppMain()
414565

415566
Rem
@@ -421,12 +572,19 @@ While True
421572
TAppGUI.FAppUpdate()
422573
Else
423574
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
424582
EndIf
425583

426584
WaitEvent
427585
'Print CurrentEvent.ToString()
428586

429-
'Event Responses
587+
'Event Responses
430588
'In Main Window
431589
If Not TAppGUI.mainToEdit Then
432590
Select EventID()
@@ -443,7 +601,7 @@ While True
443601
Case EVENT_WINDOWCLOSE, EVENT_APPTERMINATE
444602
Exit
445603
EndSelect
446-
'In Editor Window
604+
'In Editor Window
447605
ElseIf TAppGUI.mainToEdit Then
448606
Select EventID()
449607
Case EVENT_APPRESUME

0 commit comments

Comments
 (0)