1// Copyright (c) Akop Karapetyan
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#import "FBMainThread.h"
16
17#import "AppDelegate.h"
18
19#include "burner.h"
20#include "burnint.h"
21#include "driverlist.h"
22
23// Placing burner.h stuff in the NSThread file
24// messes with thread execution for some reason,
25// so I'm implementing it as a category - AK
26
27@implementation FBMainThread (Etc)
28
29- (BOOL) isPaused
30{
31    return bRunPause;
32}
33
34- (void) setPaused:(BOOL) isPaused
35{
36    if (!bDrvOkay || bRunPause == isPaused)
37        return;
38
39    bRunPause = isPaused;
40    if (isPaused)
41        AudSoundStop();
42    else
43        AudSoundPlay();
44}
45
46- (NSString *) setName
47{
48    return [NSString stringWithCString:BurnDrvGetText(DRV_NAME)
49                              encoding:NSASCIIStringEncoding];
50}
51
52- (NSString *) title
53{
54    if (!bDrvOkay)
55        return nil;
56
57    const wchar_t *unicodeName = pDriver[nBurnDrvActive]->szFullNameW;
58    if (unicodeName)
59        return [[NSString alloc] initWithBytes:unicodeName
60                                        length:sizeof(wchar_t) * wcslen(unicodeName)
61                                      encoding:NSUTF32LittleEndianStringEncoding];
62
63    const char *asciiName = pDriver[nBurnDrvActive]->szFullNameA;
64    if (asciiName)
65        return [NSString stringWithCString:asciiName
66                                  encoding:NSASCIIStringEncoding];
67
68    return nil;
69}
70
71#pragma mark - DIP switches
72
73- (NSArray<FBDipSetting *> *) dipSwitches
74{
75    if (!bDrvOkay)
76        return nil;
77
78    NSMutableArray *switches = [NSMutableArray new];
79    FBDipSetting *active;
80
81    int offset = 0;
82    BurnDIPInfo dipSwitch;
83    for (int i = 0; BurnDrvGetDIPInfo(&dipSwitch, i) == 0; i++) {
84        if (!dipSwitch.szText) // defaruto
85            continue;
86
87        if (dipSwitch.nFlags == 0xf0)
88            offset = dipSwitch.nInput;
89        if (dipSwitch.nFlags & 0x40) {
90            FBDipSetting *set = [FBDipSetting new];
91            set.name = [NSString stringWithCString:dipSwitch.szText
92                                          encoding:NSUTF8StringEncoding];
93
94            active = set;
95            set.selectedIndex = 0;
96            set.switches = [NSMutableArray new];
97            [switches addObject:set];
98        } else {
99            FBDipOption *opt = [FBDipOption new];
100            opt.name = [NSString stringWithCString:dipSwitch.szText
101                                          encoding:NSUTF8StringEncoding];
102            opt.start = dipSwitch.nInput + offset;
103            opt.mask = dipSwitch.nMask;
104            opt.setting = dipSwitch.nSetting;
105
106            // Default switch
107            BurnDIPInfo dsw2;
108            for (int j = 0; BurnDrvGetDIPInfo(&dsw2, j) == 0; j++)
109                if (dsw2.nFlags == 0xff && dsw2.nInput == dipSwitch.nInput
110                    && (dsw2.nSetting & dipSwitch.nMask) == dipSwitch.nSetting)
111                        active.defaultIndex = active.selectedIndex = active.switches.count;
112
113            // Active switch
114            struct GameInp *pgi = GameInp + opt.start;
115            if ((pgi->Input.Constant.nConst & opt.mask) == dipSwitch.nSetting)
116                active.selectedIndex = active.switches.count;
117
118            [(NSMutableArray *) active.switches addObject:opt];
119        }
120    }
121
122    return switches;
123}
124
125- (void) applyDip:(FBDipOption *) option
126{
127    if (bDrvOkay) {
128        struct GameInp *pgi = GameInp + option.start;
129        pgi->Input.Constant.nConst = (pgi->Input.Constant.nConst & ~option.mask) | (option.setting & option.mask);
130        self.dipSwitchesDirty = YES;
131    }
132}
133
134- (BOOL) saveDipState:(NSString *) path
135{
136    NSLog(@"saveDipState");
137
138    NSArray<FBDipSetting *> *switches = self.dipSwitches;
139    if (!switches || switches.count < 1)
140        return YES;
141
142    for (FBDipSetting *sw in switches)
143        if (sw.defaultIndex != sw.selectedIndex)
144            goto save;
145
146    return YES;
147
148save:
149    FILE *f = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "w");
150    if (!f)
151        return NO;
152
153    for (FBDipSetting *sw in switches) {
154        FBDipOption *opt = sw.switches[sw.selectedIndex];
155        fprintf(f, "%x %d %02x\n", opt.start, sw.selectedIndex, opt.setting);
156    }
157
158    fclose(f);
159    return YES;
160}
161
162- (BOOL) restoreDipState:(NSString *) path
163{
164    NSLog(@"restoreDipState");
165
166    NSArray<FBDipSetting *> *switches = self.dipSwitches;
167    if (!switches || switches.count < 1)
168        return YES;
169
170    FILE *f = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "r");
171    if (!f)
172        return NO;
173
174    int swIndex;
175    uint32 start;
176    uint32 setting;
177    for (int i = 0; fscanf(f, "%x %d %x", &start, &swIndex, &setting) == 3 && i < switches.count; i++) {
178        FBDipSetting *sw = switches[i];
179        if (sw.selectedIndex != swIndex && swIndex < sw.switches.count)
180            [self applyDip:sw.switches[swIndex]];
181    }
182
183    fclose(f);
184
185    [AppDelegate.sharedInstance.input simReset];
186    return YES;
187}
188
189@end
190
191#pragma mark - FBDipSetting
192
193@implementation FBDipSetting
194
195- (instancetype) init
196{
197    if (self = [super init]) {
198        _switches = [NSMutableArray new];
199    }
200    return self;
201}
202
203@end
204
205#pragma mark - FBDipOption
206
207@implementation FBDipOption
208
209@end
210