diff --git a/Android/.idea/compiler.xml b/Android/.idea/compiler.xml index 96cc43ef..1f2af519 100644 --- a/Android/.idea/compiler.xml +++ b/Android/.idea/compiler.xml @@ -11,7 +11,6 @@ - diff --git a/Android/.idea/misc.xml b/Android/.idea/misc.xml index 1a3eaffb..4a7d11e1 100644 --- a/Android/.idea/misc.xml +++ b/Android/.idea/misc.xml @@ -27,6 +27,25 @@ + + + + + + + + + Spelling + + + + + Spelling + + + + + @@ -37,10 +56,38 @@ - + + + + + + deadc0de.org + + + + + + + + Android API 21 Platform + + + + + + + \ No newline at end of file diff --git a/Android/app/build.gradle b/Android/app/build.gradle index 4693d283..53689ead 100644 --- a/Android/app/build.gradle +++ b/Android/app/build.gradle @@ -27,8 +27,8 @@ android { applicationId "org.deadc0de.apple2ix.basic" minSdkVersion 10 targetSdkVersion 23 - versionCode 7 - versionName "1.0.4" + versionCode 15 + versionName "1.1.5" ndk { moduleName "apple2ix" } diff --git a/Android/app/src/main/java/com/example/inputmanagercompat/InputManagerCompat.java b/Android/app/src/main/java/com/example/inputmanagercompat/InputManagerCompat.java new file mode 100644 index 00000000..f1678ddf --- /dev/null +++ b/Android/app/src/main/java/com/example/inputmanagercompat/InputManagerCompat.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.inputmanagercompat; + +import android.content.Context; +import android.os.Build; +import android.os.Handler; +import android.view.InputDevice; +import android.view.MotionEvent; + +public interface InputManagerCompat { + /** + * Gets information about the input device with the specified id. + * + * @param id The device id + * @return The input device or null if not found + */ + public InputDevice getInputDevice(int id); + + /** + * Gets the ids of all input devices in the system. + * + * @return The input device ids. + */ + public int[] getInputDeviceIds(); + + /** + * Registers an input device listener to receive notifications about when + * input devices are added, removed or changed. + * + * @param listener The listener to register. + * @param handler The handler on which the listener should be invoked, or + * null if the listener should be invoked on the calling thread's + * looper. + */ + public void registerInputDeviceListener(InputManagerCompat.InputDeviceListener listener, + Handler handler); + + /** + * Unregisters an input device listener. + * + * @param listener The listener to unregister. + */ + public void unregisterInputDeviceListener(InputManagerCompat.InputDeviceListener listener); + + /* + * The following three calls are to simulate V16 behavior on pre-Jellybean + * devices. If you don't call them, your callback will never be called + * pre-API 16. + */ + + /** + * Pass the motion events to the InputManagerCompat. This is used to + * optimize for polling for controllers. If you do not pass these events in, + * polling will cause regular object creation. + * + * @param event the motion event from the app + */ + public void onGenericMotionEvent(MotionEvent event); + + /** + * Tell the V9 input manager that it should stop polling for disconnected + * devices. You can call this during onPause in your activity, although you + * might want to call it whenever your game is not active (or whenever you + * don't care about being notified of new input devices) + */ + public void onPause(); + + /** + * Tell the V9 input manager that it should start polling for disconnected + * devices. You can call this during onResume in your activity, although you + * might want to call it less often (only when the gameplay is actually + * active) + */ + public void onResume(); + + public interface InputDeviceListener { + /** + * Called whenever the input manager detects that a device has been + * added. This will only be called in the V9 version when a motion event + * is detected. + * + * @param deviceId The id of the input device that was added. + */ + void onInputDeviceAdded(int deviceId); + + /** + * Called whenever the properties of an input device have changed since + * they were last queried. This will not be called for the V9 version of + * the API. + * + * @param deviceId The id of the input device that changed. + */ + void onInputDeviceChanged(int deviceId); + + /** + * Called whenever the input manager detects that a device has been + * removed. For the V9 version, this can take some time depending on the + * poll rate. + * + * @param deviceId The id of the input device that was removed. + */ + void onInputDeviceRemoved(int deviceId); + } + + /** + * Use this to construct a compatible InputManager. + */ + public static class Factory { + + /** + * Constructs and returns a compatible InputManger + * + * @param context the Context that will be used to get the system + * service from + * @return a compatible implementation of InputManager + */ + public static InputManagerCompat getInputManager(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + return new InputManagerV16(context); + } else { + return null; + } + } + } +} diff --git a/Android/app/src/main/java/com/example/inputmanagercompat/InputManagerV16.java b/Android/app/src/main/java/com/example/inputmanagercompat/InputManagerV16.java new file mode 100644 index 00000000..d26581e6 --- /dev/null +++ b/Android/app/src/main/java/com/example/inputmanagercompat/InputManagerV16.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.inputmanagercompat; + +import android.annotation.TargetApi; +import android.content.Context; +import android.hardware.input.InputManager; +import android.os.Build; +import android.os.Handler; +import android.view.InputDevice; +import android.view.MotionEvent; + +import java.util.HashMap; +import java.util.Map; + +@TargetApi(Build.VERSION_CODES.JELLY_BEAN) +public class InputManagerV16 implements InputManagerCompat { + + private final InputManager mInputManager; + private final Map mListeners; + + public InputManagerV16(Context context) { + mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); + mListeners = new HashMap(); + } + + @Override + public InputDevice getInputDevice(int id) { + return mInputManager.getInputDevice(id); + } + + @Override + public int[] getInputDeviceIds() { + return mInputManager.getInputDeviceIds(); + } + + static class V16InputDeviceListener implements InputManager.InputDeviceListener { + final InputManagerCompat.InputDeviceListener mIDL; + + public V16InputDeviceListener(InputDeviceListener idl) { + mIDL = idl; + } + + @Override + public void onInputDeviceAdded(int deviceId) { + mIDL.onInputDeviceAdded(deviceId); + } + + @Override + public void onInputDeviceChanged(int deviceId) { + mIDL.onInputDeviceChanged(deviceId); + } + + @Override + public void onInputDeviceRemoved(int deviceId) { + mIDL.onInputDeviceRemoved(deviceId); + } + + } + + @Override + public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { + V16InputDeviceListener v16Listener = new V16InputDeviceListener(listener); + mInputManager.registerInputDeviceListener(v16Listener, handler); + mListeners.put(listener, v16Listener); + } + + @Override + public void unregisterInputDeviceListener(InputDeviceListener listener) { + V16InputDeviceListener curListener = mListeners.remove(listener); + if (null != curListener) + { + mInputManager.unregisterInputDeviceListener(curListener); + } + + } + + @Override + public void onGenericMotionEvent(MotionEvent event) { + // unused in V16 + } + + @Override + public void onPause() { + // unused in V16 + } + + @Override + public void onResume() { + // unused in V16 + } + +} diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Activity.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Activity.java index cb2106b8..f1873e35 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Activity.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Activity.java @@ -11,17 +11,17 @@ package org.deadc0de.apple2ix; +import android.Manifest; import android.app.Activity; import android.app.AlertDialog; -import android.content.DialogInterface; import android.content.Intent; -import android.media.AudioManager; +import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.StrictMode; import android.util.Log; import android.view.KeyEvent; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -39,7 +39,6 @@ import org.deadc0de.apple2ix.basic.R; public class Apple2Activity extends Activity { private final static String TAG = "Apple2Activity"; - private final static int MAX_FINGERS = 32;// HACK ... private static volatile boolean DEBUG_STRICT = false; private Apple2View mView = null; @@ -54,9 +53,6 @@ public class Apple2Activity extends Activity { private AtomicBoolean mPausing = new AtomicBoolean(false); - private float[] mXCoords = new float[MAX_FINGERS]; - private float[] mYCoords = new float[MAX_FINGERS]; - // non-null if we failed to load/link the native code ... likely we are running on some bizarre 'droid variant private static Throwable sNativeBarfedThrowable = null; private static boolean sNativeBarfed = false; @@ -70,44 +66,33 @@ public class Apple2Activity extends Activity { } } - public final static long NATIVE_TOUCH_HANDLED = (1 << 0); - public final static long NATIVE_TOUCH_REQUEST_SHOW_MENU = (1 << 1); + public final static int REQUEST_PERMISSION_RWSTORE = 42; - public final static long NATIVE_TOUCH_KEY_TAP = (1 << 4); - public final static long NATIVE_TOUCH_KBD = (1 << 5); - public final static long NATIVE_TOUCH_JOY = (1 << 6); - public final static long NATIVE_TOUCH_MENU = (1 << 7); - public final static long NATIVE_TOUCH_JOY_KPAD = (1 << 8); + private static native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize); - public final static long NATIVE_TOUCH_INPUT_DEVICE_CHANGED = (1 << 16); - public final static long NATIVE_TOUCH_CPU_SPEED_DEC = (1 << 17); - public final static long NATIVE_TOUCH_CPU_SPEED_INC = (1 << 18); + private static native void nativeOnKeyDown(int keyCode, int metaState); - public final static long NATIVE_TOUCH_ASCII_SCANCODE_SHIFT = 32; - public final static long NATIVE_TOUCH_ASCII_SCANCODE_MASK = 0xFFFFL; - public final static long NATIVE_TOUCH_ASCII_MASK = 0xFF00L; - public final static long NATIVE_TOUCH_SCANCODE_MASK = 0x00FFL; + private static native void nativeOnKeyUp(int keyCode, int metaState); - private native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize); + private static native void nativeSaveState(String path); - private native void nativeOnKeyDown(int keyCode, int metaState); + private static native String nativeLoadState(String path); - private native void nativeOnKeyUp(int keyCode, int metaState); + private static native void nativeEmulationResume(); - public native void nativeEmulationResume(); + private static native void nativeEmulationPause(); - public native void nativeEmulationPause(); + private static native void nativeOnQuit(); - public native void nativeOnQuit(); + private static native void nativeReboot(); - public native long nativeOnTouch(int action, int pointerCount, int pointerIndex, float[] xCoords, float[] yCoords); + private static native void nativeChooseDisk(String path, boolean driveA, boolean readOnly); - public native void nativeReboot(); - - public native void nativeChooseDisk(String path, boolean driveA, boolean readOnly); - - public native void nativeEjectDisk(boolean driveA); + private static native void nativeEjectDisk(boolean driveA); + public final static boolean isNativeBarfed() { + return sNativeBarfed; + } @Override public void onCreate(Bundle savedInstanceState) { @@ -148,12 +133,37 @@ public class Apple2Activity extends Activity { String dataDir = Apple2DisksMenu.getDataDir(this); nativeOnCreate(dataDir, sampleRate, monoBufferSize, stereoBufferSize); - final boolean firstTime = !Apple2Preferences.FIRST_TIME_CONFIGURED.booleanValue(this); - Apple2Preferences.FIRST_TIME_CONFIGURED.saveBoolean(this, true); + final boolean firstTime = (Apple2Preferences.EMULATOR_VERSION.intValue(this) != BuildConfig.VERSION_CODE); + if (firstTime) { + // allow for primitive migrations as needed + Apple2Preferences.EMULATOR_VERSION.saveInt(this, BuildConfig.VERSION_CODE); + Log.v(TAG, "Triggering migration to Apple2ix version : " + BuildConfig.VERSION_NAME); + } showSplashScreen(!firstTime); Apple2CrashHandler.getInstance().checkForCrashes(this); + boolean extperm = true; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + // On Marshmallow+ specifically ask for permission to read/write storage + String readPermission = Manifest.permission.READ_EXTERNAL_STORAGE; + String writePermission = Manifest.permission.WRITE_EXTERNAL_STORAGE; + int hasReadPermission = checkSelfPermission(readPermission); + int hasWritePermission = checkSelfPermission(writePermission); + ArrayList permissions = new ArrayList(); + if (hasReadPermission != PackageManager.PERMISSION_GRANTED) { + permissions.add(readPermission); + } + if (hasWritePermission != PackageManager.PERMISSION_GRANTED) { + permissions.add(writePermission); + } + if (!permissions.isEmpty()) { + extperm = false; + String[] params = permissions.toArray(new String[permissions.size()]); + requestPermissions(params, REQUEST_PERMISSION_RWSTORE); + } + } + mGraphicsInitializedRunnable = new Runnable() { @Override public void run() { @@ -165,11 +175,15 @@ public class Apple2Activity extends Activity { }; // first-time initializations + final boolean externalStoragePermission = extperm; if (firstTime) { new Thread(new Runnable() { @Override public void run() { - Apple2DisksMenu.firstTime(Apple2Activity.this); + Apple2DisksMenu.exposeAPKAssets(Apple2Activity.this); + if (externalStoragePermission) { + Apple2DisksMenu.exposeAPKAssetsToExternal(Apple2Activity.this); + } mSplashScreen.setDismissable(true); Log.d(TAG, "Finished first time copying..."); } @@ -192,6 +206,26 @@ public class Apple2Activity extends Activity { } } + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + // We should already be gracefully handling the case where user denies access. + if (requestCode == REQUEST_PERMISSION_RWSTORE) { + boolean grantedPermissions = true; + for (int grant : grantResults) { + if (grant == PackageManager.PERMISSION_DENIED) { + grantedPermissions = false; + break; + } + } + if (grantedPermissions) { + // this will force copying APK files (now that we have permission + Apple2DisksMenu.exposeAPKAssetsToExternal(Apple2Activity.this); + } // else ... we keep nagging on app startup ... + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + } + @Override protected void onResume() { super.onResume(); @@ -234,21 +268,23 @@ public class Apple2Activity extends Activity { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (sNativeBarfed) { - return true; + if (Apple2Activity.isNativeBarfed()) { + return super.onKeyDown(keyCode, event); } if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) || (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) || (keyCode == KeyEvent.KEYCODE_VOLUME_UP)) { - return false; + return super.onKeyDown(keyCode, event); } + nativeOnKeyDown(keyCode, event.getMetaState()); return true; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - if (sNativeBarfed) { - return true; + if (Apple2Activity.isNativeBarfed()) { + return super.onKeyUp(keyCode, event); } + if (keyCode == KeyEvent.KEYCODE_BACK) { Apple2MenuView apple2MenuView = peekApple2View(); if (apple2MenuView == null) { @@ -261,106 +297,11 @@ public class Apple2Activity extends Activity { showMainMenu(); return true; } else if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) || (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) || (keyCode == KeyEvent.KEYCODE_VOLUME_UP)) { - return false; - } else { - nativeOnKeyUp(keyCode, event.getMetaState()); - return true; + return super.onKeyUp(keyCode, event); } - } - @Override - public boolean onTouchEvent(MotionEvent event) { - do { - - if (sNativeBarfed) { - break; - } - if (mMainMenu == null) { - break; - } - - Apple2MenuView apple2MenuView = peekApple2View(); - if ((apple2MenuView != null) && (!apple2MenuView.isCalibrating())) { - break; - } - - //printSamples(event); - int action = event.getActionMasked(); - int pointerIndex = event.getActionIndex(); - int pointerCount = event.getPointerCount(); - for (int i = 0; i < pointerCount/* && i < MAX_FINGERS */; i++) { - mXCoords[i] = event.getX(i); - mYCoords[i] = event.getY(i); - } - - long nativeFlags = nativeOnTouch(action, pointerCount, pointerIndex, mXCoords, mYCoords); - - if ((nativeFlags & NATIVE_TOUCH_HANDLED) == 0) { - break; - } - - if ((nativeFlags & NATIVE_TOUCH_REQUEST_SHOW_MENU) != 0) { - mMainMenu.show(); - } - - if ((nativeFlags & NATIVE_TOUCH_KEY_TAP) != 0) { - if (Apple2Preferences.KEYBOARD_CLICK_ENABLED.booleanValue(this)) { - AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE); - if (am != null) { - am.playSoundEffect(AudioManager.FX_KEY_CLICK); - } - } - - if ((apple2MenuView != null) && apple2MenuView.isCalibrating()) { - long asciiScancodeLong = nativeFlags & (NATIVE_TOUCH_ASCII_SCANCODE_MASK << NATIVE_TOUCH_ASCII_SCANCODE_SHIFT); - int asciiInt = (int) (asciiScancodeLong >> (NATIVE_TOUCH_ASCII_SCANCODE_SHIFT + 8)); - int scancode = (int) ((asciiScancodeLong >> NATIVE_TOUCH_ASCII_SCANCODE_SHIFT) & 0xFFL); - char ascii = (char) asciiInt; - apple2MenuView.onKeyTapCalibrationEvent(ascii, scancode); - } - } - - if ((nativeFlags & NATIVE_TOUCH_MENU) == 0) { - break; - } - - // handle menu-specific actions - - if ((nativeFlags & NATIVE_TOUCH_INPUT_DEVICE_CHANGED) != 0) { - Apple2Preferences.TouchDeviceVariant nextVariant; - if ((nativeFlags & NATIVE_TOUCH_KBD) != 0) { - nextVariant = Apple2Preferences.TouchDeviceVariant.KEYBOARD; - } else if ((nativeFlags & NATIVE_TOUCH_JOY) != 0) { - nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK; - } else if ((nativeFlags & NATIVE_TOUCH_JOY_KPAD) != 0) { - nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD; - } else { - int touchDevice = Apple2Preferences.nativeGetCurrentTouchDevice(); - nextVariant = Apple2Preferences.TouchDeviceVariant.next(touchDevice); - } - Apple2Preferences.CURRENT_TOUCH_DEVICE.saveTouchDevice(this, nextVariant); - } else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_DEC) != 0) { - int percentSpeed = Apple2Preferences.nativeGetCPUSpeed(); - if (percentSpeed > 400) { // HACK: max value from native side - percentSpeed = 375; - } else if (percentSpeed > 100) { - percentSpeed -= 25; - } else { - percentSpeed -= 5; - } - Apple2Preferences.CPU_SPEED_PERCENT.saveInt(this, percentSpeed); - } else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_INC) != 0) { - int percentSpeed = Apple2Preferences.nativeGetCPUSpeed(); - if (percentSpeed >= 100) { - percentSpeed += 25; - } else { - percentSpeed += 5; - } - Apple2Preferences.CPU_SPEED_PERCENT.saveInt(this, percentSpeed); - } - } while (false); - - return super.onTouchEvent(event); + nativeOnKeyUp(keyCode, event.getMetaState()); + return true; } public void showMainMenu() { @@ -410,7 +351,7 @@ public class Apple2Activity extends Activity { /* ... */ } - File storageDir = Apple2DisksMenu.getExternalStorageDirectory(); + File storageDir = Apple2DisksMenu.getExternalStorageDirectory(Apple2Activity.this); if (storageDir != null) { String storagePath = storageDir.getAbsolutePath(); if (diskPath.contains(storagePath)) { @@ -472,23 +413,13 @@ public class Apple2Activity extends Activity { } public synchronized void pushApple2View(Apple2MenuView apple2MenuView) { + // mMenuStack.add(apple2MenuView); View menuView = apple2MenuView.getView(); nativeEmulationPause(); addContentView(menuView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); } - public synchronized Apple2MenuView popApple2View() { - int lastIndex = mMenuStack.size() - 1; - if (lastIndex < 0) { - return null; - } - - Apple2MenuView apple2MenuView = mMenuStack.remove(lastIndex); - _disposeApple2View(apple2MenuView); - return apple2MenuView; - } - public synchronized Apple2MenuView peekApple2View() { int lastIndex = mMenuStack.size() - 1; if (lastIndex < 0) { @@ -565,44 +496,55 @@ public class Apple2Activity extends Activity { } } - public void maybeResumeCPU() { + public boolean isEmulationPaused() { + boolean mainMenuShowing = (mMainMenu != null && mMainMenu.isShowing()); + boolean menusShowing = (mMenuStack.size() > 0); + return mainMenuShowing || menusShowing; + } + + public void maybeResumeEmulation() { if (mMenuStack.size() == 0 && !mPausing.get()) { nativeEmulationResume(); } } - public void maybeQuitApp() { + public void pauseEmulation() { nativeEmulationPause(); - AlertDialog quitDialog = new AlertDialog.Builder(this).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_really).setMessage(R.string.quit_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - nativeOnQuit(); - Apple2Activity.this.finish(); - new Runnable() { - @Override - public void run() { - try { - Thread.sleep(2000); - } catch (InterruptedException ex) { - // ... - } - System.exit(0); - } - }.run(); - } - }).setNegativeButton(R.string.no, null).create(); - registerAndShowDialog(quitDialog); } - public void maybeReboot() { - nativeEmulationPause(); - AlertDialog rebootDialog = new AlertDialog.Builder(this).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.reboot_really).setMessage(R.string.reboot_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void rebootEmulation() { + nativeReboot(); + } + + public void saveState(String stateFile) { + nativeSaveState(stateFile); + } + + public String loadState(String stateFile) { + return Apple2Activity.nativeLoadState(stateFile); + } + + public void chooseDisk(String path, boolean driveA, boolean readOnly) { + nativeChooseDisk(path, driveA, readOnly); + } + + public void ejectDisk(boolean driveA) { + nativeEjectDisk(driveA); + } + + public void quitEmulator() { + nativeOnQuit(); + finish(); + new Runnable() { @Override - public void onClick(DialogInterface dialog, int which) { - nativeReboot(); - Apple2Activity.this.mMainMenu.dismiss(); + public void run() { + try { + Thread.sleep(2000); + } catch (InterruptedException ex) { + // ... + } + System.exit(0); } - }).setNegativeButton(R.string.no, null).create(); - registerAndShowDialog(rebootDialog); + }.run(); } } diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AudioSettingsMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AudioSettingsMenu.java index ffb41101..84599f58 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AudioSettingsMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AudioSettingsMenu.java @@ -50,25 +50,6 @@ public class Apple2AudioSettingsMenu extends Apple2AbstractMenu { } enum SETTINGS implements Apple2AbstractMenu.IMenuEnum { - SPEAKER_ENABLED { - @Override - public final String getTitle(Apple2Activity activity) { - return activity.getResources().getString(R.string.speaker_enable); - } - - @Override - public final String getSummary(Apple2Activity activity) { - return activity.getResources().getString(R.string.speaker_enable_summary); - } - - @Override - public View getView(final Apple2Activity activity, View convertView) { - convertView = _basicView(activity, this, convertView); - CheckBox cb = _addCheckbox(activity, this, convertView, true); - cb.setEnabled(false); - return convertView; - } - }, SPEAKER_VOLUME { @Override public final String getTitle(Apple2Activity activity) { diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2CrashHandler.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2CrashHandler.java index 79d27124..956e4c2b 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2CrashHandler.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2CrashHandler.java @@ -14,6 +14,8 @@ package org.deadc0de.apple2ix; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Environment; @@ -210,6 +212,7 @@ public class Apple2CrashHandler { summary.append("MODEL: ").append(Build.MODEL).append("\n"); summary.append("MANUFACTURER: ").append(Build.MANUFACTURER).append("\n"); summary.append("DEVICE: ").append(Build.DEVICE).append("\n"); + summary.append("SDK: ").append(Build.VERSION.SDK_INT).append("\n"); summary.append("SAMPLE RATE: ").append(sampleRate).append("\n"); summary.append("MONO BUFSIZE: ").append(monoBufferSize).append("\n"); summary.append("STEREO BUFSIZE: ").append(stereoBufferSize).append("\n"); @@ -217,6 +220,13 @@ public class Apple2CrashHandler { summary.append("GPU RENDERER: ").append(Apple2Preferences.GL_RENDERER.stringValue(activity)).append("\n"); summary.append("GPU VERSION: ").append(Apple2Preferences.GL_VERSION.stringValue(activity)).append("\n"); + try { + PackageInfo pInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), 0); + summary.append("APP VERSION: ").append(pInfo.versionName).append("\n"); + } catch (PackageManager.NameNotFoundException e) { + // ... + } + allCrashData.append(summary); File[] nativeCrashes = _nativeCrashFiles(activity); diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2DisksMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2DisksMenu.java index be3d4476..031410a4 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2DisksMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2DisksMenu.java @@ -42,8 +42,10 @@ import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.zip.GZIPOutputStream; import org.deadc0de.apple2ix.basic.R; @@ -75,10 +77,10 @@ public class Apple2DisksMenu implements Apple2MenuView { } }); - getExternalStorageDirectory(); + getExternalStorageDirectory(activity); } - public static File getExternalStorageDirectory() { + public static File getExternalStorageDirectory(Apple2Activity activity) { do { if (sExternalFilesDir != null) { @@ -135,29 +137,27 @@ public class Apple2DisksMenu implements Apple2MenuView { return sDataDir; } - public static void firstTime(Apple2Activity activity) { + public static void exposeAPKAssetsToExternal(Apple2Activity activity) { + getExternalStorageDirectory(activity); + if (sExternalFilesDir == null) { + return; + } + final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar); - try { - bar.setVisibility(View.VISIBLE); - bar.setIndeterminate(true); - } catch (NullPointerException npe) { - Log.v(TAG, "Whoa, avoided NPE in first time #1"); - } + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + try { + bar.setVisibility(View.VISIBLE); + bar.setIndeterminate(true); + } catch (NullPointerException npe) { + Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #1"); + } + } + }); - getDataDir(activity); - - Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access..."); - - getExternalStorageDirectory(); - - recursivelyCopyAPKAssets(activity, /*from APK directory:*/"disks", /*to location:*/new File(sDataDir, "disks").getAbsolutePath()); - recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/new File(sDataDir, "keyboards").getAbsolutePath()); - recursivelyCopyAPKAssets(activity, /*from APK directory:*/"shaders", /*to location:*/new File(sDataDir, "shaders").getAbsolutePath()); - - // expose keyboards to modding - if (sExternalFilesDir != null) { - recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath()); - } + Log.v(TAG, "Overwriting system files in /sdcard/apple2ix/ (external storage) ..."); + recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/sExternalFilesDir.getAbsolutePath(), false); activity.runOnUiThread(new Runnable() { @Override @@ -166,14 +166,57 @@ public class Apple2DisksMenu implements Apple2MenuView { bar.setVisibility(View.INVISIBLE); bar.setIndeterminate(false); } catch (NullPointerException npe) { - Log.v(TAG, "Whoa, avoided NPE in first time #2"); + Log.v(TAG, "Avoid NPE in exposeAPKAssetsToExternal #2"); + } + } + }); + } + + public static void exposeAPKAssets(Apple2Activity activity) { + final ProgressBar bar = (ProgressBar) activity.findViewById(R.id.crash_progressBar); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + try { + bar.setVisibility(View.VISIBLE); + bar.setIndeterminate(true); + } catch (NullPointerException npe) { + Log.v(TAG, "Avoid NPE in exposeAPKAssets #1"); + } + } + }); + + getDataDir(activity); + + // FIXME TODO : Heavy-handed migration to 1.1.3 ... + recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "blanks")); + recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "demo")); + recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "eamon")); + recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "logo")); + recursivelyDelete(new File(new File(sDataDir, "disks").getAbsolutePath(), "miscgame")); + + Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access..."); + + getExternalStorageDirectory(activity); + recursivelyCopyAPKAssets(activity, /*from APK directory:*/"disks", /*to location:*/new File(sDataDir, "disks").getAbsolutePath(), true); + recursivelyCopyAPKAssets(activity, /*from APK directory:*/"keyboards", /*to location:*/new File(sDataDir, "keyboards").getAbsolutePath(), false); + recursivelyCopyAPKAssets(activity, /*from APK directory:*/"shaders", /*to location:*/new File(sDataDir, "shaders").getAbsolutePath(), false); + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + try { + bar.setVisibility(View.INVISIBLE); + bar.setIndeterminate(false); + } catch (NullPointerException npe) { + Log.v(TAG, "Avoid NPE in exposeAPKAssets #1"); } } }); } public static void exposeSymbols(Apple2Activity activity) { - recursivelyCopyAPKAssets(activity, /*from APK directory:*/"symbols", /*to location:*/new File(sDataDir, "symbols").getAbsolutePath()); + recursivelyCopyAPKAssets(activity, /*from APK directory:*/"symbols", /*to location:*/new File(sDataDir, "symbols").getAbsolutePath(), false); } public static void unexposeSymbols(Apple2Activity activity) { @@ -317,6 +360,7 @@ public class Apple2DisksMenu implements Apple2MenuView { return pathBuffer.toString(); } + // TODO FIXME : WARNING : this is super dangerous if there are symlinks !!! private static void recursivelyDelete(File file) { if (file.isDirectory()) { for (File f : file.listFiles()) { @@ -328,7 +372,7 @@ public class Apple2DisksMenu implements Apple2MenuView { } } - private static void recursivelyCopyAPKAssets(Apple2Activity activity, String srcFileOrDir, String dstFileOrDir) { + private static void recursivelyCopyAPKAssets(Apple2Activity activity, String srcFileOrDir, String dstFileOrDir, boolean shouldGzip) { AssetManager assetManager = activity.getAssets(); final int maxAttempts = 5; @@ -368,19 +412,23 @@ public class Apple2DisksMenu implements Apple2MenuView { } for (String filename : files) { // iterate on files and subdirectories - recursivelyCopyAPKAssets(activity, srcFileOrDir + File.separator + filename, dstFileOrDir + File.separator + filename); + recursivelyCopyAPKAssets(activity, srcFileOrDir + File.separator + filename, dstFileOrDir + File.separator + filename, shouldGzip); } return; } // presumably this is a file, not a subdirectory InputStream is = null; - FileOutputStream os = null; + OutputStream os = null; attempts = 0; do { try { is = assetManager.open(srcFileOrDir); - os = new FileOutputStream(dstFileOrDir); + if (shouldGzip) { + os = new GZIPOutputStream(new FileOutputStream(dstFileOrDir + ".gz")); + } else { + os = new FileOutputStream(dstFileOrDir); + } copyFile(is, os); break; } catch (InterruptedIOException e) { @@ -412,7 +460,7 @@ public class Apple2DisksMenu implements Apple2MenuView { } while (attempts < maxAttempts); } - private static void copyFile(InputStream is, FileOutputStream os) throws IOException { + private static void copyFile(InputStream is, OutputStream os) throws IOException { final int BUF_SZ = 4096; byte[] buf = new byte[BUF_SZ]; while (true) { @@ -463,7 +511,7 @@ public class Apple2DisksMenu implements Apple2MenuView { Arrays.sort(files); - getExternalStorageDirectory(); + getExternalStorageDirectory(mActivity); final boolean includeExternalStoragePath = (sExternalFilesDir != null && isRootPath); final boolean includeDownloadsPath = (sDownloadFilesDir != null && isRootPath); final int offset = includeExternalStoragePath ? (includeDownloadsPath ? 2 : 1) : (includeDownloadsPath ? 1 : 0); @@ -528,7 +576,7 @@ public class Apple2DisksMenu implements Apple2MenuView { ejectButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mActivity.nativeEjectDisk(/*driveA:*/true); + mActivity.ejectDisk(/*driveA:*/true); Apple2Preferences.CURRENT_DISK_A.saveString(mActivity, ""); dynamicSetup(); } @@ -540,7 +588,7 @@ public class Apple2DisksMenu implements Apple2MenuView { ejectButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mActivity.nativeEjectDisk(/*driveA:*/false); + mActivity.ejectDisk(/*driveA:*/false); Apple2Preferences.CURRENT_DISK_B.saveString(mActivity, ""); dynamicSetup(); } @@ -582,17 +630,16 @@ public class Apple2DisksMenu implements Apple2MenuView { final String imageName = str; if (imageName.equals(Apple2Preferences.CURRENT_DISK_A.stringValue(mActivity))) { - mActivity.nativeEjectDisk(/*driveA:*/true); + mActivity.ejectDisk(/*driveA:*/true); Apple2Preferences.CURRENT_DISK_A.saveString(mActivity, ""); dynamicSetup(); return; } if (imageName.equals(Apple2Preferences.CURRENT_DISK_B.stringValue(mActivity))) { - mActivity.nativeEjectDisk(/*driveA:*/false); + mActivity.ejectDisk(/*driveA:*/false); Apple2Preferences.CURRENT_DISK_B.saveString(mActivity, ""); dynamicSetup(); return; - } String title = mActivity.getResources().getString(R.string.header_disks); diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2JoystickSettingsMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2JoystickSettingsMenu.java index c217bf03..fe17949f 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2JoystickSettingsMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2JoystickSettingsMenu.java @@ -329,6 +329,30 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu { return convertView; } }, + JOYSTICK_AZIMUTH_VISIBILITY { + @Override + public final String getTitle(Apple2Activity activity) { + return activity.getResources().getString(R.string.joystick_azimuth_visible); + } + + @Override + public final String getSummary(Apple2Activity activity) { + return activity.getResources().getString(R.string.joystick_azimuth_visible_summary); + } + + @Override + public View getView(final Apple2Activity activity, View convertView) { + convertView = _basicView(activity, this, convertView); + CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.JOYSTICK_AZIMUTH_VISIBILITY.booleanValue(activity)); + cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + Apple2Preferences.JOYSTICK_AZIMUTH_VISIBILITY.saveBoolean(activity, isChecked); + } + }); + return convertView; + } + }, JOYSTICK_AXIS_ON_LEFT { @Override public final String getTitle(Apple2Activity activity) { @@ -415,7 +439,7 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu { @Override public void showValue(int progress, final TextView seekBarValue) { - int threshold = progress * Apple2Preferences.JOYSTICK_BUTTON_THRESHOLD_STEP; + int threshold = progress * Apple2Preferences.getJoystickButtonSwitchThresholdScale(activity); seekBarValue.setText("" + threshold + " pts"); } }); diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeyboardSettingsMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeyboardSettingsMenu.java index 8c6fe7b3..1a329767 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeyboardSettingsMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeyboardSettingsMenu.java @@ -91,10 +91,34 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu { if (position < 0 || position >= SETTINGS.size) { throw new ArrayIndexOutOfBoundsException(); } - return true; + return (position != SETTINGS.KEYBOARD_VISIBILITY_INACTIVE.ordinal() && position != SETTINGS.KEYBOARD_VISIBILITY_ACTIVE.ordinal()); } protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum { + TOUCH_MENU_ENABLED { + @Override + public final String getTitle(Apple2Activity activity) { + return activity.getResources().getString(R.string.touch_menu_enable); + } + + @Override + public final String getSummary(Apple2Activity activity) { + return activity.getResources().getString(R.string.touch_menu_enable_summary); + } + + @Override + public View getView(final Apple2Activity activity, View convertView) { + convertView = _basicView(activity, this, convertView); + CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.TOUCH_MENU_ENABLED.booleanValue(activity)); + cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + Apple2Preferences.TOUCH_MENU_ENABLED.saveBoolean(activity, isChecked); + } + }); + return convertView; + } + }, KEYBOARD_VISIBILITY_INACTIVE { @Override public final String getTitle(Apple2Activity activity) { @@ -226,7 +250,7 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu { @Override public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) { - File extKeyboardDir = Apple2DisksMenu.getExternalStorageDirectory(); + File extKeyboardDir = Apple2DisksMenu.getExternalStorageDirectory(activity); FilenameFilter kbdJsonFilter = new FilenameFilter() { public boolean accept(File dir, String name) { @@ -289,6 +313,31 @@ public class Apple2KeyboardSettingsMenu extends Apple2AbstractMenu { } }); } + }, + KEYBOARD_GLYPH_SCALE { + @Override + public final String getTitle(Apple2Activity activity) { + return activity.getResources().getString(R.string.keyboard_glyph_scale); + } + + @Override + public final String getSummary(Apple2Activity activity) { + return activity.getResources().getString(R.string.keyboard_glyph_scale_summary); + } + + @Override + public View getView(final Apple2Activity activity, View convertView) { + convertView = _basicView(activity, this, convertView); + int glyphScale = Apple2Preferences.KEYBOARD_GLYPH_SCALE.intValue(activity); + CheckBox cb = _addCheckbox(activity, this, convertView, glyphScale > 1); + cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + Apple2Preferences.KEYBOARD_GLYPH_SCALE.saveInt(activity, isChecked ? 2 : 1); + } + }); + return convertView; + } }; public static final int size = SETTINGS.values().length; diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeypadChooser.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeypadChooser.java index 0c7acfed..18cc0552 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeypadChooser.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2KeypadChooser.java @@ -65,18 +65,18 @@ public class Apple2KeypadChooser implements Apple2MenuView { mCurrentChoicePrompt.setText(getNextChoiceString() + asciiStr); switch (mChooserState) { case CHOOSE_TAP: - mActivity.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f}); - mActivity.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{400.f}); + Apple2View.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f}); + Apple2View.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{400.f}); break; case CHOOSE_SWIPEDOWN: - mActivity.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f}); - mActivity.nativeOnTouch(MotionEvent.ACTION_MOVE, 1, 0, new float[]{400.f}, new float[]{600.f}); - mActivity.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{600.f}); + Apple2View.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f}); + Apple2View.nativeOnTouch(MotionEvent.ACTION_MOVE, 1, 0, new float[]{400.f}, new float[]{600.f}); + Apple2View.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{600.f}); break; case CHOOSE_SWIPEUP: - mActivity.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f}); - mActivity.nativeOnTouch(MotionEvent.ACTION_MOVE, 1, 0, new float[]{400.f}, new float[]{200.f}); - mActivity.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{200.f}); + Apple2View.nativeOnTouch(MotionEvent.ACTION_DOWN, 1, 0, new float[]{400.f}, new float[]{400.f}); + Apple2View.nativeOnTouch(MotionEvent.ACTION_MOVE, 1, 0, new float[]{400.f}, new float[]{200.f}); + Apple2View.nativeOnTouch(MotionEvent.ACTION_UP, 1, 0, new float[]{400.f}, new float[]{200.f}); break; default: break; diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2MainMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2MainMenu.java index e3c27d96..40852d05 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2MainMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2MainMenu.java @@ -11,7 +11,9 @@ package org.deadc0de.apple2ix; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.graphics.drawable.BitmapDrawable; import android.os.Build; import android.util.Log; @@ -27,16 +29,24 @@ import android.widget.PopupWindow; import android.widget.TextView; import org.deadc0de.apple2ix.basic.R; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; public class Apple2MainMenu { - private final static int MENU_INSET = 20; + private final static String SAVE_FILE = "emulator.state"; private final static String TAG = "Apple2MainMenu"; private Apple2Activity mActivity = null; private Apple2View mParentView = null; private PopupWindow mMainMenuPopup = null; + private AtomicBoolean mShowingRebootQuit = new AtomicBoolean(false); + private AtomicBoolean mShowingSaveRestore = new AtomicBoolean(false); + public Apple2MainMenu(Apple2Activity activity, Apple2View parent) { mActivity = activity; mParentView = parent; @@ -45,52 +55,82 @@ public class Apple2MainMenu { enum SETTINGS { SHOW_SETTINGS { - @Override public String getTitle(Context ctx) { + @Override + public String getTitle(Context ctx) { return ctx.getResources().getString(R.string.menu_settings); } - @Override public String getSummary(Context ctx) { + + @Override + public String getSummary(Context ctx) { return ctx.getResources().getString(R.string.menu_settings_summary); } - @Override public void handleSelection(Apple2MainMenu mainMenu) { + + @Override + public void handleSelection(Apple2MainMenu mainMenu) { mainMenu.showSettings(); } }, LOAD_DISK { - @Override public String getTitle(Context ctx) { + @Override + public String getTitle(Context ctx) { return ctx.getResources().getString(R.string.menu_disks); } - @Override public String getSummary(Context ctx) { + + @Override + public String getSummary(Context ctx) { return ctx.getResources().getString(R.string.menu_disks_summary); } - @Override public void handleSelection(Apple2MainMenu mainMenu) { + + @Override + public void handleSelection(Apple2MainMenu mainMenu) { mainMenu.showDisksMenu(); } }, - REBOOT_EMULATOR { - @Override public String getTitle(Context ctx) { - return ctx.getResources().getString(R.string.reboot); + SAVE_RESTORE { + @Override + public String getTitle(Context ctx) { + return ctx.getResources().getString(R.string.saverestore); } - @Override public String getSummary(Context ctx) { - return ctx.getResources().getString(R.string.reboot_summary); + + @Override + public String getSummary(Context ctx) { + return ctx.getResources().getString(R.string.saverestore_summary); } - @Override public void handleSelection(Apple2MainMenu mainMenu) { - mainMenu.mActivity.maybeReboot(); + + @Override + public void handleSelection(Apple2MainMenu mainMenu) { + if (!mainMenu.mShowingSaveRestore.compareAndSet(false, true)) { + Log.v(TAG, "OMG, avoiding nasty UI race around save/restore"); + return; + } + mainMenu.maybeSaveRestore(); } }, - QUIT_EMULATOR { - @Override public String getTitle(Context ctx) { - return ctx.getResources().getString(R.string.quit); + REBOOT_QUIT_EMULATOR { + @Override + public String getTitle(Context ctx) { + return ctx.getResources().getString(R.string.quit_reboot); } - @Override public String getSummary(Context ctx) { - return ctx.getResources().getString(R.string.quit_summary); + + @Override + public String getSummary(Context ctx) { + return ""; } - @Override public void handleSelection(Apple2MainMenu mainMenu) { - mainMenu.mActivity.maybeQuitApp(); + + @Override + public void handleSelection(Apple2MainMenu mainMenu) { + if (!mainMenu.mShowingRebootQuit.compareAndSet(false, true)) { + Log.v(TAG, "OMG, avoiding nasty UI race around quit/reboot"); + return; + } + mainMenu.maybeRebootQuit(); } }; public abstract String getTitle(Context ctx); + public abstract String getSummary(Context ctx); + public abstract void handleSelection(Apple2MainMenu mainMenu); public static String[] titles(Context ctx) { @@ -105,11 +145,11 @@ public class Apple2MainMenu { private void setup() { - LayoutInflater inflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View listLayout=inflater.inflate(R.layout.activity_main_menu, null, false); - ListView mainMenuView = (ListView)listLayout.findViewById(R.id.main_popup_menu); + LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View listLayout = inflater.inflate(R.layout.activity_main_menu, null, false); + ListView mainMenuView = (ListView) listLayout.findViewById(R.id.main_popup_menu); mainMenuView.setEnabled(true); - LinearLayout mainPopupContainer = (LinearLayout)listLayout.findViewById(R.id.main_popup_container); + LinearLayout mainPopupContainer = (LinearLayout) listLayout.findViewById(R.id.main_popup_container); final String[] values = SETTINGS.titles(mActivity); @@ -118,10 +158,11 @@ public class Apple2MainMenu { public boolean areAllItemsEnabled() { return true; } + @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); - TextView tv = (TextView)view.findViewById(android.R.id.text2); + TextView tv = (TextView) view.findViewById(android.R.id.text2); SETTINGS setting = SETTINGS.values()[position]; tv.setText(setting.getSummary(mActivity)); return view; @@ -131,7 +172,7 @@ public class Apple2MainMenu { mainMenuView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - Log.d(TAG, "position:"+position+" tapped..."); + Log.d(TAG, "position:" + position + " tapped..."); SETTINGS setting = SETTINGS.values()[position]; setting.handleSelection(Apple2MainMenu.this); } @@ -153,7 +194,7 @@ public class Apple2MainMenu { maxWidth = width; } } - mMainMenuPopup = new PopupWindow(mainPopupContainer, maxWidth+TOTAL_MARGINS, totalHeight, true); + mMainMenuPopup = new PopupWindow(mainPopupContainer, maxWidth + TOTAL_MARGINS, totalHeight, true); } // This kludgery allows touching the outside or back-buttoning to dismiss @@ -162,7 +203,7 @@ public class Apple2MainMenu { mMainMenuPopup.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { - Apple2MainMenu.this.mActivity.maybeResumeCPU(); + Apple2MainMenu.this.mActivity.maybeResumeEmulation(); } }); } @@ -184,7 +225,10 @@ public class Apple2MainMenu { return; } - mActivity.nativeEmulationPause(); + mShowingRebootQuit.set(false); + mShowingSaveRestore.set(false); + + mActivity.pauseEmulation(); mMainMenuPopup.showAtLocation(mParentView, Gravity.CENTER, 0, 0); } @@ -199,4 +243,82 @@ public class Apple2MainMenu { public boolean isShowing() { return mMainMenuPopup.isShowing(); } + + + public void maybeRebootQuit() { + mActivity.pauseEmulation(); + + final AtomicBoolean selectionAlreadyHandled = new AtomicBoolean(false); + + AlertDialog rebootQuitDialog = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_reboot).setMessage(R.string.quit_reboot_choice).setPositiveButton(R.string.reboot, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (!selectionAlreadyHandled.compareAndSet(false, true)) { + Log.v(TAG, "OMG, avoiding nasty UI race in reboot/quit onClick()"); + return; + } + mActivity.rebootEmulation(); + Apple2MainMenu.this.dismiss(); + } + }).setNeutralButton(R.string.quit, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (!selectionAlreadyHandled.compareAndSet(false, true)) { + Log.v(TAG, "OMG, avoiding nasty UI race in reboot/quit onClick()"); + return; + } + mActivity.quitEmulator(); + } + }).setNegativeButton(R.string.cancel, null).create(); + + mActivity.registerAndShowDialog(rebootQuitDialog); + } + + + public void maybeSaveRestore() { + mActivity.pauseEmulation(); + + final String quickSavePath = Apple2DisksMenu.getDataDir(mActivity) + File.separator + SAVE_FILE; + + final AtomicBoolean selectionAlreadyHandled = new AtomicBoolean(false); + + AlertDialog saveRestoreDialog = new AlertDialog.Builder(mActivity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.saverestore).setMessage(R.string.saverestore_choice).setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (!selectionAlreadyHandled.compareAndSet(false, true)) { + Log.v(TAG, "OMG, avoiding nasty UI race in save/restore onClick()"); + return; + } + mActivity.saveState(quickSavePath); + Apple2MainMenu.this.dismiss(); + } + }).setNeutralButton(R.string.restore, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (!selectionAlreadyHandled.compareAndSet(false, true)) { + Log.v(TAG, "OMG, avoiding nasty UI race in save/restore onClick()"); + return; + } + + String jsonData = mActivity.loadState(quickSavePath); + try { + JSONObject map = new JSONObject(jsonData); + String diskPath1 = map.getString("disk1"); + boolean readOnly1 = map.getBoolean("readOnly1"); + Apple2Preferences.CURRENT_DISK_A.setPath(mActivity, diskPath1); + Apple2Preferences.CURRENT_DISK_A_RO.saveBoolean(mActivity, readOnly1); + + String diskPath2 = map.getString("disk2"); + boolean readOnly2 = map.getBoolean("readOnly2"); + Apple2Preferences.CURRENT_DISK_B.setPath(mActivity, diskPath2); + Apple2Preferences.CURRENT_DISK_B_RO.saveBoolean(mActivity, readOnly2); + } catch (JSONException je) { + Log.v(TAG, "OOPS : " + je); + } + Apple2MainMenu.this.dismiss(); + } + }).setNegativeButton(R.string.cancel, null).create(); + + mActivity.registerAndShowDialog(saveRestoreDialog); + } } diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java index 1f38423b..c43fc674 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java @@ -14,6 +14,7 @@ package org.deadc0de.apple2ix; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; +import android.util.DisplayMetrics; import android.util.Log; import java.io.File; @@ -21,15 +22,15 @@ import java.io.File; import org.deadc0de.apple2ix.basic.R; public enum Apple2Preferences { - FIRST_TIME_CONFIGURED { + EMULATOR_VERSION { @Override public void load(Apple2Activity activity) { /* ... */ } @Override - public void saveBoolean(Apple2Activity activity, boolean ignored) { - activity.getPreferences(Context.MODE_PRIVATE).edit().putBoolean(toString(), true).apply(); + public void saveInt(Apple2Activity activity, int version) { + activity.getPreferences(Context.MODE_PRIVATE).edit().putInt(toString(), version).apply(); } }, CURRENT_DISK_PATH { @@ -99,6 +100,11 @@ public enum Apple2Preferences { activity.getPreferences(Context.MODE_PRIVATE).edit().putString(toString(), str).apply(); load(activity); } + + @Override + public void setPath(Apple2Activity activity, String str) { + activity.getPreferences(Context.MODE_PRIVATE).edit().putString(toString(), str).apply(); + } }, CURRENT_DISK_A_RO { @Override @@ -133,6 +139,11 @@ public enum Apple2Preferences { activity.getPreferences(Context.MODE_PRIVATE).edit().putString(toString(), str).apply(); load(activity); } + + @Override + public void setPath(Apple2Activity activity, String str) { + activity.getPreferences(Context.MODE_PRIVATE).edit().putString(toString(), str).apply(); + } }, CURRENT_DISK_B_RO { @Override @@ -173,22 +184,6 @@ public enum Apple2Preferences { return activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), HiresColor.INTERPOLATED.ordinal()); } }, - SPEAKER_ENABLED { - @Override - public void load(Apple2Activity activity) { - boolean enabled = booleanValue(activity); - boolean result = nativeSetSpeakerEnabled(enabled); - if (enabled && !result) { - warnError(activity, R.string.speaker_disabled_title, R.string.speaker_disabled_mesg); - activity.getPreferences(Context.MODE_PRIVATE).edit().putBoolean(toString(), false).apply(); - } - } - - @Override - public boolean booleanValue(Apple2Activity activity) { - return activity.getPreferences(Context.MODE_PRIVATE).getBoolean(toString(), true); - } - }, SPEAKER_VOLUME { @Override public void load(Apple2Activity activity) { @@ -282,17 +277,16 @@ public enum Apple2Preferences { return activity.getPreferences(Context.MODE_PRIVATE).getBoolean(toString(), true); } }, - TOUCH_MENU_VISIBILITY { + SHOW_DISK_OPERATIONS { @Override public void load(Apple2Activity activity) { - int setting = intValue(activity); - float alpha = (float) setting / AUDIO_LATENCY_NUM_CHOICES; - nativeSetTouchMenuVisibility(alpha); + boolean enabled = booleanValue(activity); + nativeSetShowDiskOperationAnimation(enabled); } @Override - public int intValue(Apple2Activity activity) { - return activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), 5); + public boolean booleanValue(Apple2Activity activity) { + return activity.getPreferences(Context.MODE_PRIVATE).getBoolean(toString(), true); } }, JOYSTICK_AXIS_SENSITIVIY { @@ -327,7 +321,8 @@ public enum Apple2Preferences { @Override public void load(Apple2Activity activity) { int tick = intValue(activity); - nativeSetTouchJoystickButtonSwitchThreshold(tick * JOYSTICK_BUTTON_THRESHOLD_STEP); + tick *= getJoystickButtonSwitchThresholdScale(activity); + nativeSetTouchJoystickButtonSwitchThreshold(tick); } @Override @@ -355,7 +350,7 @@ public enum Apple2Preferences { @Override public int intValue(Apple2Activity activity) { - int defaultLatency = 3; // /TAPDELAY_NUM_CHOICES * TAPDELAY_SCALE -> 0.075f + int defaultLatency = 8; // /TAPDELAY_NUM_CHOICES * TAPDELAY_SCALE -> 0.2f return activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), defaultLatency); } }, @@ -415,6 +410,17 @@ public enum Apple2Preferences { return activity.getPreferences(Context.MODE_PRIVATE).getBoolean(toString(), true); } }, + JOYSTICK_AZIMUTH_VISIBILITY { + @Override + public void load(Apple2Activity activity) { + nativeSetTouchJoystickAzimuthVisibility(booleanValue(activity)); + } + + @Override + public boolean booleanValue(Apple2Activity activity) { + return activity.getPreferences(Context.MODE_PRIVATE).getBoolean(toString(), true); + } + }, KEYPAD_KEYS { @Override public void load(Apple2Activity activity) { @@ -582,6 +588,41 @@ public enum Apple2Preferences { return activity.getPreferences(Context.MODE_PRIVATE).getBoolean(toString(), true); } }, + KEYBOARD_GLYPH_SCALE { + @Override + public void load(Apple2Activity activity) { + int scale = intValue(activity); + if (scale == 0) { + scale = 1; + } + nativeSetTouchKeyboardGlyphScale(scale); + } + + @Override + public int intValue(Apple2Activity activity) { + int scale = activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), 0); + + if (scale == 0) { + scale = 2; + DisplayMetrics dm = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(dm); + + /* calculating actual physical diagonal size appears to be problematic -- Samsung Galaxy Y reports 15" with this method + double x = Math.pow(dm.widthPixels / dm.xdpi, 2); + double y = Math.pow(dm.heightPixels / dm.ydpi, 2); + double screenInches = Math.sqrt(x + y); + Log.d(TAG, "Screen inches:" + screenInches + " w:" + dm.widthPixels + " h:" + dm.heightPixels); + */ + if (dm.widthPixels <= 480 || dm.heightPixels <= 480) { + scale = 1; + } + + saveInt(activity, scale); + } + + return scale; + } + }, CRASH_CHECK { @Override public void load(Apple2Activity activity) { @@ -853,7 +894,6 @@ public enum Apple2Preferences { public final static String TAG = "Apple2Preferences"; public final static int JOYSTICK_BUTTON_THRESHOLD_NUM_CHOICES = DECENT_AMOUNT_OF_CHOICES; - public final static int JOYSTICK_BUTTON_THRESHOLD_STEP = 5; public final static float JOYSTICK_AXIS_SENSITIVITY_MIN = 0.25f; public final static float JOYSTICK_AXIS_SENSITIVITY_DEFAULT = 1.f; @@ -911,6 +951,10 @@ public enum Apple2Preferences { load(activity); } + public void setPath(Apple2Activity activity, String path) { + /* ... */ + } + // accessors public boolean booleanValue(Apple2Activity activity) { @@ -941,13 +985,13 @@ public enum Apple2Preferences { for (Apple2Preferences pref : Apple2Preferences.values()) { pref.load(activity); } + // HACK FIXME TODO 2015/12/13 : native GLTouchDevice is conflating various things ... forcefully reset the current touch device here for now + Apple2Preferences.CURRENT_TOUCH_DEVICE.load(activity); } public static void resetPreferences(Apple2Activity activity) { activity.getPreferences(Context.MODE_PRIVATE).edit().clear().commit(); - FIRST_TIME_CONFIGURED.saveBoolean(activity, true); - KeypadPreset.IJKM_SPACE.apply(activity); - loadPreferences(activity); + activity.quitEmulator(); } public String asciiString() { @@ -958,6 +1002,18 @@ public enum Apple2Preferences { return toString() + "_SCAN"; } + public static int getJoystickButtonSwitchThresholdScale(Apple2Activity activity) { + + DisplayMetrics dm = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(dm); + + int smallScreenAxis = dm.widthPixels < dm.heightPixels ? dm.widthPixels : dm.heightPixels; + int oneThirdScreenAxis = smallScreenAxis/3; + + // largest switch threshold value is 1/3 small dimension of screen + return oneThirdScreenAxis/JOYSTICK_BUTTON_THRESHOLD_NUM_CHOICES; + } + // ------------------------------------------------------------------------ // internals ... @@ -1023,7 +1079,7 @@ public enum Apple2Preferences { file = new File(fullPath); } if (file.exists()) { - activity.nativeChooseDisk(fullPath, isDriveA, isReadOnly); + activity.chooseDisk(fullPath, isDriveA, isReadOnly); } else { Log.d(TAG, "Cannot insert: " + fullPath); } @@ -1055,14 +1111,18 @@ public enum Apple2Preferences { private static native void nativeSetTouchJoystickVisibility(boolean visibility); + private static native void nativeSetTouchJoystickAzimuthVisibility(boolean visibility); + public static native void nativeSetTouchMenuEnabled(boolean enabled); - private static native void nativeSetTouchMenuVisibility(float alpha); + public static native void nativeSetShowDiskOperationAnimation(boolean enabled); private static native void nativeSetTouchKeyboardVisibility(float inactiveAlpha, float activeAlpha); private static native void nativeSetTouchKeyboardLowercaseEnabled(boolean enabled); + private static native void nativeSetTouchKeyboardGlyphScale(int scale); + public static native int nativeGetCurrentTouchDevice(); public static native int nativeGetCPUSpeed(); diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2SettingsMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2SettingsMenu.java index f2dc14be..cfb48018 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2SettingsMenu.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2SettingsMenu.java @@ -52,7 +52,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu { if (position < 0 || position >= SETTINGS.size) { throw new ArrayIndexOutOfBoundsException(); } - return position != SETTINGS.TOUCH_MENU_VISIBILITY.ordinal(); + return true; } enum SETTINGS implements Apple2AbstractMenu.IMenuEnum { @@ -194,61 +194,30 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu { }); } }, - TOUCH_MENU_ENABLED { + SHOW_DISK_OPERATIONS { @Override public final String getTitle(Apple2Activity activity) { - return activity.getResources().getString(R.string.touch_menu_enable); + return activity.getResources().getString(R.string.disk_show_operation); } @Override public final String getSummary(Apple2Activity activity) { - return activity.getResources().getString(R.string.touch_menu_enable_summary); + return activity.getResources().getString(R.string.disk_show_operation_summary); } @Override public View getView(final Apple2Activity activity, View convertView) { convertView = _basicView(activity, this, convertView); - CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.TOUCH_MENU_ENABLED.booleanValue(activity)); + CheckBox cb = _addCheckbox(activity, this, convertView, Apple2Preferences.SHOW_DISK_OPERATIONS.booleanValue(activity)); cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - Apple2Preferences.TOUCH_MENU_ENABLED.saveBoolean(activity, isChecked); + Apple2Preferences.SHOW_DISK_OPERATIONS.saveBoolean(activity, isChecked); } }); return convertView; } }, - TOUCH_MENU_VISIBILITY { - @Override - public final String getTitle(Apple2Activity activity) { - return activity.getResources().getString(R.string.touch_menu_visibility); - } - - @Override - public final String getSummary(Apple2Activity activity) { - return activity.getResources().getString(R.string.touch_menu_visibility_summary); - } - - @Override - public View getView(final Apple2Activity activity, View convertView) { - return _sliderView(activity, this, Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES, new IPreferenceSlider() { - @Override - public void saveInt(int progress) { - Apple2Preferences.TOUCH_MENU_VISIBILITY.saveInt(activity, progress); - } - - @Override - public int intValue() { - return Apple2Preferences.TOUCH_MENU_VISIBILITY.intValue(activity); - } - - @Override - public void showValue(int progress, final TextView seekBarValue) { - seekBarValue.setText("" + ((float) progress / Apple2Preferences.ALPHA_SLIDER_NUM_CHOICES)); - } - }); - } - }, ABOUT { @Override public final String getTitle(Apple2Activity activity) { diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2View.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2View.java index f198217d..d5cb0d6f 100644 --- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2View.java +++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2View.java @@ -15,43 +15,57 @@ package org.deadc0de.apple2ix; +import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.media.AudioManager; import android.opengl.GLES20; import android.opengl.GLSurfaceView; +import android.os.Build; import android.util.Log; +import android.view.InputDevice; +import android.view.MotionEvent; import android.view.ViewTreeObserver; +import com.example.inputmanagercompat.InputManagerCompat; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.opengles.GL10; -/** - * A simple GLSurfaceView sub-class that demonstrate how to perform - * OpenGL ES 2.0 rendering into a GL Surface. Note the following important - * details: - * - * - The class must use a custom context factory to enable 2.0 rendering. - * See ContextFactory class definition below. - * - * - The class must use a custom EGLConfigChooser to be able to select - * an EGLConfig that supports 2.0. This is done by providing a config - * specification to eglChooseConfig() that has the attribute - * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag - * set. See ConfigChooser class definition below. - * - * - The class must select the surface's format, then choose an EGLConfig - * that matches it exactly (with regards to red/green/blue/alpha channels - * bit depths). Failure to do so would result in an EGL_BAD_MATCH error. - */ -class Apple2View extends GLSurfaceView { +class Apple2View extends GLSurfaceView implements InputManagerCompat.InputDeviceListener { private final static String TAG = "Apple2View"; private final static boolean DEBUG = false; + private final static int MAX_FINGERS = 32;// HACK ... + + public final static long NATIVE_TOUCH_HANDLED = (1 << 0); + public final static long NATIVE_TOUCH_REQUEST_SHOW_MENU = (1 << 1); + + public final static long NATIVE_TOUCH_KEY_TAP = (1 << 4); + public final static long NATIVE_TOUCH_KBD = (1 << 5); + public final static long NATIVE_TOUCH_JOY = (1 << 6); + public final static long NATIVE_TOUCH_MENU = (1 << 7); + public final static long NATIVE_TOUCH_JOY_KPAD = (1 << 8); + + public final static long NATIVE_TOUCH_INPUT_DEVICE_CHANGED = (1 << 16); + public final static long NATIVE_TOUCH_CPU_SPEED_DEC = (1 << 17); + public final static long NATIVE_TOUCH_CPU_SPEED_INC = (1 << 18); + + public final static long NATIVE_TOUCH_ASCII_SCANCODE_SHIFT = 32; + public final static long NATIVE_TOUCH_ASCII_SCANCODE_MASK = 0xFFFFL; + public final static long NATIVE_TOUCH_ASCII_MASK = 0xFF00L; + public final static long NATIVE_TOUCH_SCANCODE_MASK = 0x00FFL; + + + private Apple2Activity mActivity; + private Runnable mGraphicsInitializedRunnable; + private final InputManagerCompat mInputManager; + + private float[] mXCoords = new float[MAX_FINGERS]; + private float[] mYCoords = new float[MAX_FINGERS]; - private Apple2Activity mActivity = null; - private Runnable mGraphicsInitializedRunnable = null; private static native void nativeGraphicsInitialized(int width, int height); @@ -59,11 +73,24 @@ class Apple2View extends GLSurfaceView { private static native void nativeRender(); + private static native void nativeOnJoystickMove(int x, int y); + + public static native long nativeOnTouch(int action, int pointerCount, int pointerIndex, float[] xCoords, float[] yCoords); + + public Apple2View(Apple2Activity activity, Runnable graphicsInitializedRunnable) { super(activity.getApplication()); mActivity = activity; mGraphicsInitializedRunnable = graphicsInitializedRunnable; + setFocusable(true); + setFocusableInTouchMode(true); + + mInputManager = InputManagerCompat.Factory.getInputManager(this.getContext()); + if (mInputManager != null) { + mInputManager.registerInputDeviceListener(this, null); + } + /* By default, GLSurfaceView() creates a RGB_565 opaque surface. * If we want a translucent one, we should change the surface's * format here, using PixelFormat.TRANSLUCENT for GL Surfaces @@ -114,7 +141,7 @@ class Apple2View extends GLSurfaceView { public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { Log.w(TAG, "creating OpenGL ES 2.0 context"); checkEglError("Before eglCreateContext", egl); - int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; + int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); checkEglError("After eglCreateContext", egl); return context; @@ -149,12 +176,12 @@ class Apple2View extends GLSurfaceView { */ private static int EGL_OPENGL_ES2_BIT = 4; private static int[] s_configAttribs2 = { - EGL10.EGL_RED_SIZE, 4, - EGL10.EGL_GREEN_SIZE, 4, - EGL10.EGL_BLUE_SIZE, 4, - EGL10.EGL_ALPHA_SIZE, 4, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL10.EGL_NONE + EGL10.EGL_RED_SIZE, 4, + EGL10.EGL_GREEN_SIZE, 4, + EGL10.EGL_BLUE_SIZE, 4, + EGL10.EGL_ALPHA_SIZE, 4, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_NONE }; public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { @@ -174,7 +201,7 @@ class Apple2View extends GLSurfaceView { egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); if (DEBUG) { - printConfigs(egl, display, configs); + printConfigs(egl, display, configs); } // Now return the "best" one @@ -303,11 +330,11 @@ class Apple2View extends GLSurfaceView { for (int i = 0; i < attributes.length; i++) { int attribute = attributes[i]; String name = names[i]; - if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { + if (egl.eglGetConfigAttrib(display, config, attribute, value)) { Log.w(TAG, String.format(" %s: %d\n", name, value[0])); } else { // Log.w(TAG, String.format(" %s: failed\n", name)); - while (egl.eglGetError() != EGL10.EGL_SUCCESS); + while (egl.eglGetError() != EGL10.EGL_SUCCESS) ; } } } @@ -351,7 +378,7 @@ class Apple2View extends GLSurfaceView { Apple2View.this.mGraphicsInitializedRunnable = null; } - Apple2View.this.mActivity.maybeResumeCPU(); + Apple2View.this.mActivity.maybeResumeEmulation(); } @Override @@ -359,4 +386,193 @@ class Apple2View extends GLSurfaceView { // Do nothing. } } + + // -------------------------------------------------------------------------- + // Event handling, touch, keyboard, gamepad + + @Override + public void onInputDeviceAdded(int deviceId) { + } + + @Override + public void onInputDeviceChanged(int deviceId) { + } + + @Override + public void onInputDeviceRemoved(int deviceId) { + } + + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { + return super.onGenericMotionEvent(event); + } + + if (mActivity.isEmulationPaused()) { + return super.onGenericMotionEvent(event); + } + + // Check that the event came from a joystick or gamepad since a generic + // motion event could be almost anything. + int eventSource = event.getSource(); + if ((event.getAction() == MotionEvent.ACTION_MOVE) && (((eventSource & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((eventSource & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK))) { + int id = event.getDeviceId(); + if (id != -1) { + + InputDevice device = event.getDevice(); + + float x = getCenteredAxis(event, device, MotionEvent.AXIS_X); + if (x == 0) { + x = getCenteredAxis(event, device, MotionEvent.AXIS_HAT_X); + } + if (x == 0) { + x = getCenteredAxis(event, device, MotionEvent.AXIS_Z); + } + + float y = getCenteredAxis(event, device, MotionEvent.AXIS_Y); + if (y == 0) { + y = getCenteredAxis(event, device, MotionEvent.AXIS_HAT_Y); + } + if (y == 0) { + y = getCenteredAxis(event, device, MotionEvent.AXIS_RZ); + } + + int normal_x = (int) ((x + 1.f) * 128.f); + if (normal_x < 0) { + normal_x = 0; + } + if (normal_x > 255) { + normal_x = 255; + } + int normal_y = (int) ((y + 1.f) * 128.f); + if (normal_y < 0) { + normal_y = 0; + } + if (normal_y > 255) { + normal_y = 255; + } + + nativeOnJoystickMove(normal_x, normal_y); + + return true; + } + } + + return super.onGenericMotionEvent(event); + } + + private static float getCenteredAxis(MotionEvent event, InputDevice device, int axis) { + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { + return 0; + } + + final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource()); + if (range != null) { + final float flat = range.getFlat(); + final float value = event.getAxisValue(axis); + + // Ignore axis values that are within the 'flat' region of the joystick axis center. + // A joystick at rest does not always report an absolute position of (0,0). + if (Math.abs(value) > flat) { + return value; + } + } + + return 0; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + do { + + if (Apple2Activity.isNativeBarfed()) { + break; + } + if (mActivity.getMainMenu() == null) { + break; + } + + Apple2MenuView apple2MenuView = mActivity.peekApple2View(); + if ((apple2MenuView != null) && (!apple2MenuView.isCalibrating())) { + break; + } + + //printSamples(event); + int action = event.getActionMasked(); + int pointerIndex = event.getActionIndex(); + int pointerCount = event.getPointerCount(); + for (int i = 0; i < pointerCount/* && i < MAX_FINGERS */; i++) { + mXCoords[i] = event.getX(i); + mYCoords[i] = event.getY(i); + } + + long nativeFlags = nativeOnTouch(action, pointerCount, pointerIndex, mXCoords, mYCoords); + + if ((nativeFlags & NATIVE_TOUCH_HANDLED) == 0) { + break; + } + + if ((nativeFlags & NATIVE_TOUCH_REQUEST_SHOW_MENU) != 0) { + mActivity.getMainMenu().show(); + } + + if ((nativeFlags & NATIVE_TOUCH_KEY_TAP) != 0) { + if (Apple2Preferences.KEYBOARD_CLICK_ENABLED.booleanValue(mActivity)) { + AudioManager am = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE); + if (am != null) { + am.playSoundEffect(AudioManager.FX_KEY_CLICK); + } + } + + if ((apple2MenuView != null) && apple2MenuView.isCalibrating()) { + long asciiScancodeLong = nativeFlags & (NATIVE_TOUCH_ASCII_SCANCODE_MASK << NATIVE_TOUCH_ASCII_SCANCODE_SHIFT); + int asciiInt = (int) (asciiScancodeLong >> (NATIVE_TOUCH_ASCII_SCANCODE_SHIFT + 8)); + int scancode = (int) ((asciiScancodeLong >> NATIVE_TOUCH_ASCII_SCANCODE_SHIFT) & 0xFFL); + char ascii = (char) asciiInt; + apple2MenuView.onKeyTapCalibrationEvent(ascii, scancode); + } + } + + if ((nativeFlags & NATIVE_TOUCH_MENU) == 0) { + break; + } + + // handle menu-specific actions + + if ((nativeFlags & NATIVE_TOUCH_INPUT_DEVICE_CHANGED) != 0) { + Apple2Preferences.TouchDeviceVariant nextVariant; + if ((nativeFlags & NATIVE_TOUCH_KBD) != 0) { + nextVariant = Apple2Preferences.TouchDeviceVariant.KEYBOARD; + } else if ((nativeFlags & NATIVE_TOUCH_JOY) != 0) { + nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK; + } else if ((nativeFlags & NATIVE_TOUCH_JOY_KPAD) != 0) { + nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD; + } else { + int touchDevice = Apple2Preferences.nativeGetCurrentTouchDevice(); + nextVariant = Apple2Preferences.TouchDeviceVariant.next(touchDevice); + } + Apple2Preferences.CURRENT_TOUCH_DEVICE.saveTouchDevice(mActivity, nextVariant); + } else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_DEC) != 0) { + int percentSpeed = Apple2Preferences.nativeGetCPUSpeed(); + if (percentSpeed > 400) { // HACK: max value from native side + percentSpeed = 375; + } else if (percentSpeed > 100) { + percentSpeed -= 25; + } else { + percentSpeed -= 5; + } + Apple2Preferences.CPU_SPEED_PERCENT.saveInt(mActivity, percentSpeed); + } else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_INC) != 0) { + int percentSpeed = Apple2Preferences.nativeGetCPUSpeed(); + if (percentSpeed >= 100) { + percentSpeed += 25; + } else { + percentSpeed += 5; + } + Apple2Preferences.CPU_SPEED_PERCENT.saveInt(mActivity, percentSpeed); + } + } while (false); + + return true; + } } diff --git a/Android/app/src/main/res/values-de/strings.xml b/Android/app/src/main/res/values-de/strings.xml new file mode 100644 index 00000000..fca90b94 --- /dev/null +++ b/Android/app/src/main/res/values-de/strings.xml @@ -0,0 +1,162 @@ + + + + #000000 + #ffffff + + + Test crash generation + Crash emulator + NULL-deref + Java NPE + stack call overflow + stack buffer overflow + + + Ãœber Apple2ix… + Ãœber diese Software + Apple2ix + Audio-Konfiguration… + Lautstärke, Mockingboard, etc + Audio Latency + Audio Latency in Sek. + Abbrechen + Schwarz/Weiss + Farbe + Interpolierte Farben + Abstürze + Prüfe auf Absturz-Berichte + Prüfe auf Absturz-Berichte zum Versand an den Entwickler + Sende Absturz-Bericht? + Entschuldigung. es gab ein Problemm. Möchten Sie einen Absturz-Bericht an den Entwickler senden? + Laufwerk 1 + Laufwerk 2 + Auswerfen + Die eingelegte Diskette ist schreibgeschützt + Entschuldigung, das Diskettenabbild konnte nicht gelesen werden! + Schreibgeschützt + Lesen/Schreiben + Zeige Disk ][ Aktivität + Zeigt wenn die Laufwerke lesen oder schreiben + Fortsetzen… + Einstellungen… + Lade Disk-Image… + Diskette einlegen: + Aktuelles Touch Device + Wähle ein aktuelles Touch Device + Joystick + Empfindlichkeiteinstellung der Joystickachsen (verlangsamen or beschleunigen) + Button 1 (Offener Apfel) + Button 2 (Geschlossener Apfel) + Beide + Keine + Drücke den Feuerknopf + Ausgewählter Feuerknopf + Joystickknopf-Zeitverzögerung in Sek. + Aufwärts wischen zum feuern + Feuerknopf zum feuern beim aufwärts wischen + Abwärts wischen zum feuern + Feuerknopf zum feuern beim abwärts wischen + Joystick/Keypad Knopf Schaltschwellwert in pts + Kalibrieren… + Konfiguriere und teste die aktuellen Einstellungen + Joystickkonfiguration… + Achsen Touch, Knöpfe, etc + Joystick/Keypad Achse links + Joystick/Keypad Achse links (Knöpfe rechts) + Sichtbarkeit Joystick/Keypad + Zeige die Kontrollen als Overlay wenn aktiviert + [GeschlossenerApfel] + [Strg] + + [ESC] + + [Keine] + [OffenerApfel] + [Return] + + [Space] + + Tastatur + Wähle alternative Tastatur… + Wähle alternativ konfiguriertes Layout + Tastenton einschalten + Aktiviert Tastenton wenn verfügbar + Tastatur-Konfiguration… + Transparenz, Kleinbuchstaben, eigene Tasten + Tastatur-Glyphenskalierung 2x + (Lässt die Tastaur weniger pixelig erscheinen auf grossen Bildschirmen) + Kleinbuchstaben aktivieren + Aktiviren der Tasten für Kleinbuchstaben + Sichtbarkeit wenn aktiviert + Sichtbarkeit des Keyboard und Touch Menüs wenn aktiviert + Sichtbarkeit wenn deaktiviert + Sichtbarkeit des Keyboard und Touch Menüs wenn deaktiviert + Keypad Joystick + @string/joystick_calibrate + @string/joystick_calibrate + Auswahl der Keypad Tasten… + Auswahl der Achsen und Knopf Tasten + Achse & Knöpfe + Wähle XXX Taste: + Konfiguration Joystick Keypad… + @string/joystick_configure_summary + Mitte + Unten + Unten und Links + Unten und Rechts + Links + Rechts + Oben und Links + Oben + Oben und Rechts + antippen + Nach oben wischen + Nach unten wischen + Seafox Tasten ;-)… + Auswahl einer Anpassung… + ↑,←,→,↓, tippe auf die Leerstaste + A,Z,←,→, tippe auf die Leertaste + I,J,K,M, tippe auf die Leertaste + ←,→, tippe auf die Leertaste + W,A,D,X, tippe auf die Leertaste + Tastenwiederholungsschwellwert in Sek. + Lade Disk-Image… + Einlegen eines Disk ][ Image + Emulator Einstellungen… + Allgemeine Einstellungen, Joystick, Tastatur + Mockingboard deaktiviert + Mockingboard konnte nicht aktiviert werden + Aktiviere Mockingboard + Revision C in Slot 4/5 (evtl. wird ein Restart benötigt) + Mockingboard Lautstärke + Einstellen der Mockingboard Lautstärke + Nein + OK + Einstellungen zurücksetzen + Einstellungen auf Standard zurücksetzen und Emulator beenden + Wollen Sie wirklich resetten und beenden? + Sie werden alle Ihre Einstellungen verlieren + Beenden + Neustart oder beenden des Emulators… + Neustart oder beenden? + Neustart + Schnelle Wiederherstellung + Schnelle Speicherung + Speichern & wiederherstellen… + Aktuellen Status sichern oder vorherigen wiederherstellen? + Schnellspeicherung und Wiederherstellung + Ãœberspringen→ + Lautsprecherlautstärke + Lautsprecherlautstärke einstellen + Apple2ix Emulator Einstellungen + Erweiterte Einstellungen + Warnung: diese Einstellungen verschlechtern die Performance + Erweiterte Joystick/Keypad Einstellungen + Erweiterte Einstellungen für das Performance-Tuning + Aktiviere Touch Menüs + Aktiviere Softmenü Knöpfe in den oberen Ecken des Bildschirms + Video-Konfiguration… + Farbeinstellungen + + diff --git a/Android/app/src/main/res/values-es/strings.xml b/Android/app/src/main/res/values-es/strings.xml new file mode 100644 index 00000000..4158c519 --- /dev/null +++ b/Android/app/src/main/res/values-es/strings.xml @@ -0,0 +1,160 @@ + + + + #000000 + #ffffff + + + Test crash generation + Crash emulator + NULL-deref + Java NPE + stack call overflow + stack buffer overflow + + + Acerca de Apple2ix… + Acerca de este software + Apple2ix + Configurar audio… + Ajustar el volumen del altavoz, "Mockingboard", etc + La latencia de audio + La latencia de audio en segundos + Cancelar + Blanco/negro + Color + Color interpolado + Fallos del software + Fallos del software + Verificar la presencia de fallos del software + ¿Enviar informe de error? + Lo sentimos, ha habido un problema. ¿Desea enviar informe de error para el programador de software? + Disquetera 1 + Disquetera 2 + Eyectar + Disco insertado en la disquetera de sólo lectura + Lo sentimos, no se puede leer la imagen de disquete! + Sólo leer + Leer y escribir + Mostrar las operaciones de "Disk ][" + Shows when disk drives are reading or writing + Continuar… + Configuración… + Insertar imagen de disquete… + Insertar imagen de disquete: + Unidad de entrada actual + Elija unidad de entrada + "Joystick" + Afinar la sensibilidad del eje del joystick (desacelerar o acelerar) + Botón 1 + Botón 2 + Los dos + Ninguno + Toque para disparar + Botón para disparar sobre toque abajo + Toque retardo del joystick en segundos + Pase hacia arriba + Botón para disparar sobre pase el dedo hacia arriba + Pase hacia abajo + Botón para disparar sobre pase el dedo hacia abajo + Umbral del joystick en puntos + Calibrar… + Calibrar el joystick + Configurar el joystick… + Eje táctil, los botónes, etc + Eje del joystick a la izquierda + Eje del joystick a la izquierda (los botónes de la derecha) + Visibilidad del joystick + Mostrar controles cuando se utiliza + [Botón 2] + [Ctrl] + + [ESC] + + [Ninguno] + [Botón 1] + [Retorno] + + [Espaciadora] + + Teclado + Elija teclado alternativo… + Elija el diseño de teclado alternativo + Habilitar la tecla de sonido de clic + Haga clic en sonido de clave permite si está disponible + Configurar el teclado… + Transparencia, minúsculas, teclado personalizado + Habilitar minúsculas + Utilice las teclas minúsculas + Visibilidad cuando está activo + Visibilidad del teclado y menú cuando está activo + Visibilidad cuando está inactivo + Visibilidad del teclado y menú cuando está inactivo + Joystick como teclado numérico + @string/joystick_calibrate + @string/joystick_calibrate + Teclas del teclado numérico… + Elegir las teclas del joystick del teclado numérico + Ejes y botones + Elija [XXX] tecla del teclado: + Configurar el joystick del teclado numérico… + @string/joystick_configure_summary + Centro + Abajo + Abajo y a la izquierda + Abajo y a la derecha + Izquierda + Derecha + Arriba y a la izquierda + Arriba + Arriba y a la derecha + Toque + Desliza el dedo hacia arriba + Desliza el dedo hacia abajo + Seafox keys ;-)… + Elija personalizado… + ↑,←,→,↓, pulse espaciadora + A,Z,←,→, pulse espaciadora + I,J,K,M, pulse espaciadora + ←,→, pulse espaciadora + W,A,D,X, pulse espaciadora + Umbral de repetición de teclas en segundos + Insertar imagen de disco… + Insertar imagen de "Disk ][" + Configuración del emulador… + Configuración general, joystick, teclado + Mockingboard desactivado + Mockingboard no pudo ser habilitado + Activar Mockingboard + Revisión C en la ranura 4/5 puede requerir reinicio + Volumen de Mockingboard + Adjustar el volumen del Mockingboard + No + Sí + Restablecer preferencias + Restablecer preferencias y salir + ¿Restablecer realmente y salir? + Usted perderá su configuración + Salir + Reiniciar o salir el emulador… + ¿Reiniciar o salir? + Reiniciar + Restauración rápida + Guardar rápido + Guardar y restaurar… + ¿Guardar el estado actual o anterior de restauración? + Guardar y restaurar rápida + Saltar→ + El volumen del altavoz + Ajustar el volumen del altavoz + Configuración Apple2ix + Configuración avanzada + Advertencia: estos valores puede degradar el rendimiento + Configuración de teclado y joystick avanzados + Configuración avanzada y optimización del rendimiento + Activar menús táctiles + Los botones del menú en la parte superior de la pantalla + Configurar el video… + Ajustes de color + + diff --git a/Android/app/src/main/res/values-fr/strings.xml b/Android/app/src/main/res/values-fr/strings.xml new file mode 100644 index 00000000..3b628cf0 --- /dev/null +++ b/Android/app/src/main/res/values-fr/strings.xml @@ -0,0 +1,160 @@ + + + + #000000 + #ffffff + + + Génération du "Test crash" + Plantage de l\'émulateur + NULL-deref + Java NPE + stack call overflow + stack buffer overflow + + + A propos d\'Apple2ix… + A propos de ce logiciel + Apple2ix + Configuration audio… + Volume du haut-parleur, Mockingboard, etc + Délai audio + Délai audio en secs + Annulation + Noir/blanc + Couleurs + Interpolation couleurs + Plantages + Vérifier les logs de plantage + Vérifier les logs de plantage avec email au développeur + Envoyer le log de plantage ? + Désolé, il y a eu un problème. Voulez-vous envoyer le log du plantage au développeur ? + Lecteur 1 + Lecteur 2 + Ejecter + Insérer la disquette dans le drive en lecture seulement + Désolé, impossible de lire l\'image disque! + Lecture seulement + Lecture/Ecriture + Afficher les opérations (disque) ][ + Indique si les disques sont en lecture ou en écriture + Continuer… + Configurations… + Chargement de l\'image disque… + Insérer la disquettte : + Tactile + Choisir l\'appareil courant + Joystick + Calibrer le joystick (décélérer/accélérer) + Bouton 1 (Pomme ouverte) + Bouton 2 (Pomme fermée) + Les deux + Rien + Sélectionner l\'action + Bouton à activer lors d\'une pression vers le bas + Délai de pression du bouton Joystick en secondes + Lancement du swipe up + Bouton à lancer sur swipe up + Lancement du swipe down + Bouton à lancer sur swipe down + Limite en pts pour switcher sur les bouton Joystick/keypad + Calibrer… + Configuration et test des paramètres courants + Configuration du joystick… + Ajustements tactiles, boutons, etc + Ajustement du joystick/keypad sur gauche + Ajustement du Joystick/keypad sur gauche (boutons sur droite) + Visibilité Joystick/keypad + Montre les controles quand occupé + [PommeFermée] + [Ctrl] + + [ESC] + + [Rien] + [PommeOuverte] + [Entrée] + + [Espace] + + Clavier + Choisir clavier "alt"… + Choisir une configuration clavier customisée + Permettre le click sur une touche + Si disponible, son du click sur une touche + Configuration clavier… + Transparence, minuscules, touches customisées + Permettre les minuscules + Permettre les touches en minuscules + Visibilité quand actif + Clavier et menu tactile visible quand actif + Visibilité quand inactif + Clavier et menu tactile visible quand inactif + Keypad Joystick + @string/joystick_calibrate + @string/joystick_calibrate + Sélection des touches du keypad… + Sélection des touches pour les axes et boutons + Axis & boutons + Choisir XXX Key: + Configuration du "keypad joystick"… + @string/joystick_configure_summary + Centre + Bas + Bas et Gauche + Bas et Droite + Gauche + Droite + Haut et Gauche + Haut + Haut et Droite + Presser + Slider vers le haut + Slider vers le bas + Touches Seafox ;-)… + Choisir customisation… + ↑,←,→,↓, pressez barre d\'espace + A,Z,←,→, pressez barre d\'espace + I,J,K,M, pressez barre d\'espace + ←,→, pressez barre d\'espace + W,A,D,X, pressez barre d\'espace + Répétition des touches en secs + Chargement de l\'image disque… + Insérer un fichier image (disque) ][ + Paramètres de l\'émulateur… + Paramètres généraux, joystick, keyboard + Mockingboard désactivé + Le Mockingboard ne peut être activé + Activer le Mockingboard + Révision C dans Slot 4/5 (redémarrage possible) + Volume du Mockingboard + Placer le volume du Mockingboard + Non + OK + Reset des préférences + Restaurer les préférences par défaut et quitter l\'émulateur + Etes-vous sûr de vouloir faire un reset? + Vous perdrez toutes vos options de configuration + Quitter + Rebooter ou quitter l\'émulateur… + Rebooter ou quitter? + Rebooter + Restauration rapide + Sauvegarde rapide + Sauvegarde & restauration… + Sauvegarde de l\'état courant ou restaurer un état précédent? + Sauvegarde/restauration rapide + Ignorer→ + Volume du haut-parleur + Placer le volume du haut-parleur + Options de configuration de l\'émulateur Apple2ix + Configuration avancée + Attention: ces options peuvent dégrader les performances + Configuration avancée du joystick/keypad + Configuration avancée et tuning de performance + Activation des menus tactiles + Activation soft des bouton du menu dans les coins en haut de l\'écran + Configuration de la vidéo… + Configuration des couleurs + + diff --git a/Android/app/src/main/res/values/strings.xml b/Android/app/src/main/res/values/strings.xml index 55409483..bd4f53e1 100644 --- a/Android/app/src/main/res/values/strings.xml +++ b/Android/app/src/main/res/values/strings.xml @@ -4,11 +4,17 @@ #000000 #ffffff + + Test crash generation + Crash emulator + NULL-deref + Java NPE + stack call overflow + stack buffer overflow + + About Apple2ix… About this software - About Apple //e… - More information about the Apple //e computer - Settings Apple2ix Configure audio… Speaker volume, Mockingboard, etc @@ -18,43 +24,30 @@ Black/white Color Interpolated color - Crasher + Crashes Check for crash reports - Check for crash reports to email developer) - Processing… - Processing crash reports… + Check for crash reports to email developer Send crash report? Sorry there has been a problem. Do you want to send a crash report to the developer? - Test crash generation - Crash emulator - NULL-deref - Java NPE - stack call overflow - stack buffer overflow Drive 1 Drive 2 Eject - Inserted disk in drive 1 read-only - OOPS, could not read the disk image! + Inserted disk in drive read-only + Sorry, could not read the disk image! Read only Read/write + Show Disk ][ operations + Shows when disk drives are reading or writing Continue… Settings… Load disk image… Insert disk: - Configure input devices… - Keyboard, joystick, etc Current touch device Choose current touch device - Touch joystick - Touch keyboard Joystick - Touch Joystick Tune joystick axis sensitivity (decelerate or accelerate) - Enable button axis - Enable button axis - Button1 (Open Apple) - Button2 (Closed Apple) + Button 1 (Open Apple) + Button 2 (Closed Apple) Both None Tap fire @@ -64,15 +57,15 @@ Button to fire on swipe up Swipe down fire Button to fire on swipe down - Joystick/keypad button switch threshold in pts + Joystick/keypad button switch threshold in pts (max: ⅓ screen height) Calibrate… Configure and test current settings Configure joystick… Axis touch, buttons, etc - Current joystick flavor - Emulated physical joystick or keypad Joystick/keypad axis on left Joystick/keypad axis on left (buttons on right) + Show joystick/keypad heading + Shows current axis direction and magnitude Joystick/keypad visibility Show controls overlay when engaged [ClosedApple] @@ -93,25 +86,21 @@ Enables key click sound if available Configure keyboard… Transparency, lowercase, custom keys + Keyboard glyphs scaled 2x + (Makes keyboard appear less pixelated on large screens) Enable lowercase Enable lowercase keys - Default Visibility when active - Keyboard visibility when active + Keyboard and touch menu visibility when active Visibility when inactive - Keyboard visibility when inactive + Keyboard and touch menu visibility when inactive Keypad Joystick - Touch Keypad Joystick - Tap key: - Swipe up key: - Swipe down key: - Calibrate… - Configure and test current settings + @string/joystick_calibrate + @string/joystick_calibrate Choose keypad keys… Choose axis and button keys Axis & buttons Choose XXX Key: - I,J,K,M [Space] Configure keypad joystick… @string/joystick_configure_summary Center @@ -130,58 +119,45 @@ Choose custom… ↑,←,→,↓, tap spacebar A,Z,←,→, tap spacebar - I,J,L,K, tap U, swipe down O I,J,K,M, tap spacebar ←,→, tap spacebar W,A,D,X, tap spacebar Key repeat threshold in secs - Max Load disk image… Insert a Disk ][ image file Emulator settings… - General, CPU, Joystick + General settings, joystick, keyboard Mockingboard disabled Mockingboard could not be enabled Enable Mockingboard Revision C in Slot 4/5 (may require restart) Mockingboard volume - Set the Mockingboard(s) volume + Set the Mockingboard volume No OK Reset preferences - Reset preferences to defaults - Really reset? + Reset preferences to defaults and quit emulator + Really reset and quit? You will lose your settings - Quit emulator… - - Quit emulator? - You will lose unsaved progress - Reboot emulator… - Reboot emulator? - - You will lose unsaved progress + Quit + Reboot or quit emulator… + Reboot or quit? + Reboot + Quick restore + Quick save + Save & restore… + Save current state or restore previous? + Quick save and restore Skip→ - - Speaker disabled - Speaker could not be enabled - Enable speaker - (Speaker cannot be disabled) Speaker volume Set the speaker volume - Alternate CPU speed - CPU Speed Apple2ix emulator settings - Apple2ix audio settings Advanced settings - Warning: these settings may potentially degrade emulation performance + Warning: these settings may degrade performance Advanced joystick/keypad settings Advanced settings and performance tuning - General - Joystick Enable touch menus Enables soft menu buttons in top screen corners - Touch menu visibility - Touch menu visibility when inactive Configure video… Color settings diff --git a/Android/assets/keyboards/00default.kbd.json b/Android/assets/keyboards/00default.kbd.json index 73828dbc..4e407b6c 100644 --- a/Android/assets/keyboards/00default.kbd.json +++ b/Android/assets/keyboards/00default.kbd.json @@ -5,7 +5,6 @@ "_comment" : "hex code for special glyphs", "_AA" : "b5", "_CTRL": "b3", - "_XX" : "9b", "_ESC" : "bc", "_OA" : "81", "_CA" : "80", @@ -20,7 +19,7 @@ ["_AA", "", "_CTRL", "", "_ESC", "", "_OA", "", "_CA", ""], [ "", "", "", "", "", "", "", "", "", ""], [ "", "", "", "", "", "_UP", "", "", "", ""], - [ "", "", "", "", "_LT", "_XX", "_RT", "", "", ""], + [ "", "", "", "", "_LT", "_AA", "_RT", "", "", ""], [ "", "", "", "", "", "_DN", "", "", "", ""], [ "", "", "", "", "", "", "", "", "", ""] ] diff --git a/Android/assets/keyboards/conan.kbd.json b/Android/assets/keyboards/conan.kbd.json index e4a2a676..09f2d192 100644 --- a/Android/assets/keyboards/conan.kbd.json +++ b/Android/assets/keyboards/conan.kbd.json @@ -9,11 +9,11 @@ "_SP" : "b1" }, - [ "reserved for future use" ], - [ "reserved for future use" ], + [ "", "", "", "", "", "", "", "", "", "" ], [ "_AA", "", "", "", "", "", "", "", "", "" ], [ "", "", "", "", "", "", "", "", "", "" ], [ "", "", "", "", "", "", "", "", "", "" ], + [ "", "", "", "", "", "", "", "", "", "" ], [ "Q", "", "", "", "", "", "", "", "A", "" ], [ "", "", "", "", "", "", "", "_LT", "", "_RT" ], [ "_SP", "", "", "", "", "", "", "", "Z", "" ] diff --git a/Android/assets/keyboards/moebius.kbd.json b/Android/assets/keyboards/moebius.kbd.json new file mode 100644 index 00000000..709857c6 --- /dev/null +++ b/Android/assets/keyboards/moebius.kbd.json @@ -0,0 +1,19 @@ +[ + "Alt keyboard optimized for Moebius", + + { + "_comment" : "hex code for special glyphs", + "_AA" : "b5", + "_ESC" : "bc", + "_SP" : "b1" + }, + + [ "Q", "", "", "", "", "", "", "", "", "" ], + [ "", "", "", "", "", "", "", "", "", "V"], + [ "_AA", "", "", "", "", "", "", "", "", "D"], + [ "_ESC", "", "", "", "", "", "", "", "", "G"], + [ "Y", "", "", "", "", "", "", "", "", "" ], + [ "N", "", "", "", "", "", "", "I", "O", "P"], + [ "U", "A", "S", "E", "F", "M", "", "K", "L", ";"], + [ "C", "Z", "X", "B", "H", "T", "_SP",",", ".", "/"] +] diff --git a/Android/assets/keyboards/u4.kbd.json b/Android/assets/keyboards/u4.kbd.json index 0faa4be4..8440fc35 100644 --- a/Android/assets/keyboards/u4.kbd.json +++ b/Android/assets/keyboards/u4.kbd.json @@ -5,19 +5,19 @@ "_comment" : "hex code for special glyphs", "_AA" : "b5", "_ESC" : "bc", - "_UP" : "8b", + "_UP" : "8d", "_LT" : "88", "_RT" : "95", "_DN" : "8a", "_SP" : "b1" }, - ["reserved for future use"], - ["reserved for future use"], + [ "Q", "", "", "", "", "", "", "", "K", "X"], + [ "P", "", "", "", "", "", "", "", "D", "B"], ["_AA", "", "", "", "", "", "1", "2", "3", "4"], [ "N", "", "", "", "", "", "5", "6", "7", "8"], [ "Y", "", "", "", "", "", "Z", "G", "", "_ESC"], [ "S", "", "", "", "", "", "C", "", "_UP", "" ], - [ "", "", "", "", "", "", "", "_LT", "", "_RT"], - [ "A", "", "T", "O", "", "", "_SP", "", "_DN", ""] + [ "", "", "", "", "", "", "", "_LT", "", "_RT"], + [ "A", "", "T", "O", "F", "E", "_SP", "", "_DN", ""] ] diff --git a/Android/assets/shaders/SolidColor.fsh b/Android/assets/shaders/SolidColor.fsh new file mode 120000 index 00000000..addfd835 --- /dev/null +++ b/Android/assets/shaders/SolidColor.fsh @@ -0,0 +1 @@ +../../../src/video/SolidColor.fsh \ No newline at end of file diff --git a/Android/assets/shaders/SolidColor.vsh b/Android/assets/shaders/SolidColor.vsh new file mode 120000 index 00000000..c6d58707 --- /dev/null +++ b/Android/assets/shaders/SolidColor.vsh @@ -0,0 +1 @@ +../../../src/video/SolidColor.vsh \ No newline at end of file diff --git a/Android/assets/symbols/x86/.blank b/Android/assets/symbols/x86/.blank new file mode 100644 index 00000000..e69de29b diff --git a/Android/jni/androidkeys.c b/Android/jni/androidkeys.c index 0ccebfaf..82d42734 100644 --- a/Android/jni/androidkeys.c +++ b/Android/jni/androidkeys.c @@ -40,6 +40,19 @@ void android_keycode_to_emulator(int keyCode, int metaState, bool pressed) { break; } + switch (keyCode) { + case KEYCODE_BUTTON_A: + case KEYCODE_BUTTON_X: + case KEYCODE_BUTTON_L1: + joydriver_setButton0Pressed(pressed); + return; + case KEYCODE_BUTTON_B: + case KEYCODE_BUTTON_Y: + case KEYCODE_BUTTON_R1: + joydriver_setButton1Pressed(pressed); + return; + } + switch (keyCode) { case KEYCODE_0: key = _is_shifted(metaState) ? ')' : keyCode + ASCII_0_OFFSET; diff --git a/Android/jni/androidkeys.h b/Android/jni/androidkeys.h index 5d97710b..c222386a 100644 --- a/Android/jni/androidkeys.h +++ b/Android/jni/androidkeys.h @@ -98,6 +98,8 @@ #define KEYCODE_BUTTON_L2 0x68 #define KEYCODE_BUTTON_R1 0x67 #define KEYCODE_BUTTON_R2 0x69 +#define KEYCODE_BUTTON_X 0x63 +#define KEYCODE_BUTTON_Y 0x64 #define META_ALT_LEFT_ON 0x00000010 #define META_ALT_RIGHT_ON 0x00000020 diff --git a/Android/jni/apple2ix.mk b/Android/jni/apple2ix.mk index fde2cf69..a40d488d 100644 --- a/Android/jni/apple2ix.mk +++ b/Android/jni/apple2ix.mk @@ -35,6 +35,12 @@ else LOCAL_SRC_FILES += $(APPLE2_ARM_SRC) endif +ifeq ($(BUILD_MODE),release) + LOCAL_CFLAGS += -DNDEBUG=1 +else + LOCAL_CFLAGS += -g +endif + ifeq ($(EMBEDDED_STACKWALKER),1) LOCAL_CPPFLAGS += -DEMBEDDED_STACKWALKER=1 else diff --git a/Android/jni/build.sh b/Android/jni/build.sh index e9ed4af8..f5f3a006 100755 --- a/Android/jni/build.sh +++ b/Android/jni/build.sh @@ -12,7 +12,7 @@ usage() { echo "$0" echo " # uninstalls $package_id" else - echo "$0 [build] [load|debug]" + echo "$0 [build|release] [load|debug]" echo " # default builds $package_id and then load or debug" fi exit 0 @@ -22,6 +22,14 @@ export EMBEDDED_STACKWALKER=1 while test "x$1" != "x"; do case "$1" in + "build") + do_build=1 + ;; + + "release") + do_release=1 + ;; + "debug") do_debug=1 ;; @@ -45,6 +53,11 @@ while test "x$1" != "x"; do shift done +if test "x$do_build" = "x1" -a "x$do_release" = "x1" ; then + echo "Must specify either build or release" + usage +fi + set -x if test "$(basename $0)" = "clean" ; then @@ -74,22 +87,6 @@ if test "$(basename $0)" = "uninstall" ; then exit 0 fi -#CC=`which clang` -CC=`which gcc` -CFLAGS="-std=gnu11" - -# ROMz -$CC $CFLAGS -o $apple2_src_path/genrom $apple2_src_path/genrom.c && \ - $apple2_src_path/genrom $apple2_src_path/rom/apple_IIe.rom $apple2_src_path/rom/slot6.rom > $apple2_src_path/rom.c - -# font -$CC $CFLAGS -o $apple2_src_path/genfont $apple2_src_path/genfont.c && \ - $apple2_src_path/genfont < $apple2_src_path/font.txt > $apple2_src_path/font.c - -# glue -$apple2_src_path/x86/genglue $glue_srcs > $apple2_src_path/x86/glue.S -$apple2_src_path/arm/genglue $glue_srcs > $apple2_src_path/arm/glue.S - if test "$(basename $0)" = "testcpu" ; then ln -s testcpu.mk Android.mk elif test "$(basename $0)" = "testvm" ; then @@ -104,61 +101,91 @@ fi ############################################################################### # build native sources -ndk-build V=1 NDK_MODULE_PATH=. NDK_DEBUG=1 # NDK_TOOLCHAIN_VERSION=clang -ret=$? -if test "x$ret" != "x0" ; then - exit $ret + +if test "x$do_build" = "x1" -o "x$do_release" = "x1" ; then + + #CC=`which clang` + CC=`which gcc` + CFLAGS="-std=gnu11" + + # ROMz + $CC $CFLAGS -o $apple2_src_path/genrom $apple2_src_path/genrom.c && \ + $apple2_src_path/genrom $apple2_src_path/rom/apple_IIe.rom $apple2_src_path/rom/slot6.rom > $apple2_src_path/rom.c + + # font + $CC $CFLAGS -o $apple2_src_path/genfont $apple2_src_path/genfont.c && \ + $apple2_src_path/genfont < $apple2_src_path/font.txt > $apple2_src_path/font.c + + # glue + $apple2_src_path/x86/genglue $glue_srcs > $apple2_src_path/x86/glue.S + $apple2_src_path/arm/genglue $glue_srcs > $apple2_src_path/arm/glue.S + + if test "x$do_build" = "x1" ; then + export BUILD_MODE=debug + ndk-build V=1 NDK_MODULE_PATH=. NDK_DEBUG=1 # NDK_TOOLCHAIN_VERSION=clang + ret=$? + if test "x$ret" != "x0" ; then + exit $ret + fi + else + export BUILD_MODE=release + ndk-build V=1 NDK_MODULE_PATH=. # NDK_TOOLCHAIN_VERSION=clang + ret=$? + if test "x$ret" != "x0" ; then + exit $ret + fi + fi + + # Symbolicate and move symbols file into location to be deployed on device + + SYMFILE=libapple2ix.so.sym + ARCHES_TO_SYMBOLICATE='armeabi armeabi-v7a x86' + + for arch in $ARCHES_TO_SYMBOLICATE ; do + SYMDIR=../assets/symbols/$arch/libapple2ix.so + + # remove old symbols (if any) + /bin/rm -rf $SYMDIR + + # Run Breakpad's dump_syms + ../../externals/bin/dump_syms ../obj/local/$arch/libapple2ix.so > $SYMFILE + + ret=$? + if test "x$ret" != "x0" ; then + echo "OOPS, dump_syms failed for $arch" + exit $ret + fi + + # strip to the just the numeric id in the .sym header and verify it makes sense + sym_id=$(head -1 $SYMFILE | cut -d ' ' -f 4) + sym_id_check=$(echo $sym_id | wc -c) + if test "x$sym_id_check" != "x34" ; then + echo "OOPS symbol header not expected size, meat-space intervention needed =P" + exit 1 + fi + sym_id_check=$(echo $sym_id | tr -d 'A-Fa-f0-9' | wc -c) + if test "x$sym_id_check" != "x1" ; then + echo "OOPS unexpected characters in symbol header, meat-space intervention needed =P" + exit 1 + fi + + mkdir -p $SYMDIR/$sym_id + ret=$? + if test "x$ret" != "x0" ; then + echo "OOPS, could not create symbols directory for arch:$arch and sym_id:$sym_id" + exit $ret + fi + + /bin/mv $SYMFILE $SYMDIR/$sym_id/ + ret=$? + if test "x$ret" != "x0" ; then + echo "OOPS, could not move $SYMFILE to $SYMDIR/$sym_id/" + exit $ret + fi + done + fi -############################################################################### -# Symbolicate and move symbols file into location to be deployed on device - -SYMFILE=libapple2ix.so.sym -ARCHES_TO_SYMBOLICATE='armeabi armeabi-v7a x86' - -for arch in $ARCHES_TO_SYMBOLICATE ; do - SYMDIR=../assets/symbols/$arch/libapple2ix.so - - # remove old symbols (if any) - /bin/rm -rf $SYMDIR - - # Run Breakpad's dump_syms - ../../externals/bin/dump_syms ../obj/local/$arch/libapple2ix.so > $SYMFILE - - ret=$? - if test "x$ret" != "x0" ; then - echo "OOPS, dump_syms failed for $arch" - exit $ret - fi - - # strip to the just the numeric id in the .sym header and verify it makes sense - sym_id=$(head -1 $SYMFILE | cut -d ' ' -f 4) - sym_id_check=$(echo $sym_id | wc -c) - if test "x$sym_id_check" != "x34" ; then - echo "OOPS symbol header not expected size, meat-space intervention needed =P" - exit 1 - fi - sym_id_check=$(echo $sym_id | tr -d 'A-Fa-f0-9' | wc -c) - if test "x$sym_id_check" != "x1" ; then - echo "OOPS unexpected characters in symbol header, meat-space intervention needed =P" - exit 1 - fi - - mkdir -p $SYMDIR/$sym_id - ret=$? - if test "x$ret" != "x0" ; then - echo "OOPS, could not create symbols directory for arch:$arch and sym_id:$sym_id" - exit $ret - fi - - /bin/mv $SYMFILE $SYMDIR/$sym_id/ - ret=$? - if test "x$ret" != "x0" ; then - echo "OOPS, could not move $SYMFILE to $SYMDIR/$sym_id/" - exit $ret - fi -done - ############################################################################### # usually we should build the Java stuff from within Android Studio if test "x$do_load" = "x1" ; then diff --git a/Android/jni/jnicrash.c b/Android/jni/jnicrash.c index 2745687e..92c2d95a 100644 --- a/Android/jni/jnicrash.c +++ b/Android/jni/jnicrash.c @@ -113,6 +113,8 @@ void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativeProcessCrash(JNIEnv *en if (android_armArchV7A) { asprintf(&symbolsPath, "%s/symbols/armeabi-v7a", data_dir); + } else if (android_x86) { + asprintf(&symbolsPath, "%s/symbols/x86", data_dir); } else /*if (android_armArch)*/ { asprintf(&symbolsPath, "%s/symbols/armeabi", data_dir); } /*else { moar archs ... } */ @@ -129,7 +131,7 @@ void Java_org_deadc0de_apple2ix_Apple2CrashHandler_nativeProcessCrash(JNIEnv *en } if (symbolsPath) { - FREE(symbolsPath); + ASPRINTF_FREE(symbolsPath); } (*env)->ReleaseStringUTFChars(env, jCrashPath, crashPath); diff --git a/Android/jni/jnihooks.c b/Android/jni/jnihooks.c index 41d3c097..225c8777 100644 --- a/Android/jni/jnihooks.c +++ b/Android/jni/jnihooks.c @@ -47,6 +47,7 @@ typedef enum lifecycle_seq_t { static lifecycle_seq_t appState = APP_RUNNING; #if TESTING +static bool running_tests = false; static void _run_tests(void) { char *local_argv[] = { "-f", @@ -102,6 +103,7 @@ static void discover_cpu_family(void) { AndroidCpuFamily family = android_getCpuFamily(); uint64_t features = android_getCpuFeatures(); if (family == ANDROID_CPU_FAMILY_X86) { + android_x86 = true; if (features & ANDROID_CPU_X86_FEATURE_SSSE3) { LOG("nANDROID_CPU_X86_FEATURE_SSSE3"); android_x86SSSE3Enabled = true; @@ -141,7 +143,7 @@ static void discover_cpu_family(void) { // ---------------------------------------------------------------------------- // JNI functions -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobject obj, jstring j_dataDir, jint sampleRate, jint monoBufferSize, jint stereoBufferSize) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jclass cls, jstring j_dataDir, jint sampleRate, jint monoBufferSize, jint stereoBufferSize) { const char *dataDir = (*env)->GetStringUTFChars(env, j_dataDir, 0); // Android lifecycle can call onCreate() multiple times... @@ -169,11 +171,9 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobje android_monoBufferSubmitSizeSamples = (unsigned long)monoBufferSize; android_stereoBufferSubmitSizeSamples = (unsigned long)stereoBufferSize; -#if TESTING - assert(cpu_thread_id == 0 && "CPU thread must not be initialized yet..."); - _run_tests(); - // CPU thread is started from testsuite (if needed) -#else + joydriver_setClampBeyondRadius(true); + +#if !TESTING cpu_pause(); emulator_start(); #endif @@ -186,29 +186,38 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsChanged(JNIEnv *env, jc } void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsInitialized(JNIEnv *env, jclass cls, jint width, jint height) { - // WANRING : this needs to happen on the GL thread only + // WARNING : this needs to happen on the GL thread only LOG("width:%d height:%d", width, height); video_shutdown(); video_backend->reshape(width, height); video_backend->init((void *)0); } -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume(JNIEnv *env, jobject obj) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationResume(JNIEnv *env, jclass cls) { +#if TESTING + // test driver thread is managing CPU + if (!running_tests) { + running_tests = true; + assert(cpu_thread_id == 0 && "CPU thread must not be initialized yet..."); + _run_tests(); + } +#else if (!cpu_isPaused()) { return; } LOG("..."); -#if TESTING - // test driver thread is managing CPU -#else cpu_resume(); #endif } -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause(JNIEnv *env, jobject obj) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause(JNIEnv *env, jclass cls) { if (appState != APP_RUNNING) { return; } + + disk6_flush(0); + disk6_flush(1); + if (cpu_isPaused()) { return; } @@ -252,12 +261,12 @@ void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls) video_backend->render(); } -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jobject obj) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeReboot(JNIEnv *env, jclass cls) { LOG("..."); cpu65_reboot(); } -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit(JNIEnv *env, jobject obj) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit(JNIEnv *env, jclass cls) { #if TESTING // test driver thread is managing CPU #else @@ -272,21 +281,25 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnQuit(JNIEnv *env, jobject #endif } -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyDown(JNIEnv *env, jobject obj, jint keyCode, jint metaState) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyDown(JNIEnv *env, jclass cls, jint keyCode, jint metaState) { if (UNLIKELY(appState != APP_RUNNING)) { return; } android_keycode_to_emulator(keyCode, metaState, true); } -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyUp(JNIEnv *env, jobject obj, jint keyCode, jint metaState) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnKeyUp(JNIEnv *env, jclass cls, jint keyCode, jint metaState) { if (UNLIKELY(appState != APP_RUNNING)) { return; } android_keycode_to_emulator(keyCode, metaState, false); } -jlong Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnTouch(JNIEnv *env, jobject obj, jint action, jint pointerCount, jint pointerIndex, jfloatArray xCoords, jfloatArray yCoords) { +void Java_org_deadc0de_apple2ix_Apple2View_nativeOnJoystickMove(JNIEnv *env, jclass cls, jint x, jint y) { + joydriver_setAxisValue((uint8_t)x, (uint8_t)y); +} + +jlong Java_org_deadc0de_apple2ix_Apple2View_nativeOnTouch(JNIEnv *env, jclass cls, jint action, jint pointerCount, jint pointerIndex, jfloatArray xCoords, jfloatArray yCoords) { //LOG(": %d/%d/%d :", action, pointerCount, pointerIndex); SCOPE_TRACE_TOUCH("nativeOnTouch"); @@ -311,7 +324,7 @@ jlong Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnTouch(JNIEnv *env, jobje return flags; } -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, jobject obj, jstring jPath, jboolean driveA, jboolean readOnly) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, jclass cls, jstring jPath, jboolean driveA, jboolean readOnly) { const char *path = (*env)->GetStringUTFChars(env, jPath, NULL); int drive = driveA ? 0 : 1; int ro = readOnly ? 1 : 0; @@ -329,18 +342,60 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, job } else { video_backend->animation_showDiskChosen(drive); } - FREE(gzPath); + ASPRINTF_FREE(gzPath); } else { video_backend->animation_showDiskChosen(drive); } (*env)->ReleaseStringUTFChars(env, jPath, path); } -void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEjectDisk(JNIEnv *env, jobject obj, jboolean driveA) { +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEjectDisk(JNIEnv *env, jclass cls, jboolean driveA) { LOG("..."); disk6_eject(!driveA); } +void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSaveState(JNIEnv *env, jclass cls, jstring jPath) { + const char *path = (*env)->GetStringUTFChars(env, jPath, NULL); + + assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running"); + + LOG(": (%s)", path); + if (!emulator_saveState(path)) { + LOG("OOPS, could not save emulator state"); + } + + (*env)->ReleaseStringUTFChars(env, jPath, path); +} + +jstring Java_org_deadc0de_apple2ix_Apple2Activity_nativeLoadState(JNIEnv *env, jclass cls, jstring jPath) { + const char *path = (*env)->GetStringUTFChars(env, jPath, NULL); + + assert(cpu_isPaused() && "considered dangerous to save state when CPU thread is running"); + + LOG(": (%s)", path); + if (!emulator_loadState(path)) { + LOG("OOPS, could not load emulator state"); + } + + (*env)->ReleaseStringUTFChars(env, jPath, path); + + // restoring state may cause a change in disk paths, so we need to notify the Java/Android menu system of the change + // (normally we drive state from the Java/menu side...) + char *disk1 = disk6.disk[0].file_name; + bool readOnly1 = disk6.disk[0].is_protected; + char *disk2 = disk6.disk[1].file_name; + bool readOnly2 = disk6.disk[1].is_protected; + char *str = NULL; + jstring jstr = NULL; + asprintf(&str, "{ disk1 = \"%s\"; readOnly1 = %s; disk2 = \"%s\"; readOnly2 = %s }", (disk1 ?: ""), readOnly1 ? "true" : "false", (disk2 ?: ""), readOnly2 ? "true" : "false"); + if (str) { + jstr = (*env)->NewStringUTF(env, str); + ASPRINTF_FREE(str); + } + + return jstr; +} + // ---------------------------------------------------------------------------- // Constructor diff --git a/Android/jni/jniprefs.c b/Android/jni/jniprefs.c index 428f10ab..54c5b274 100644 --- a/Android/jni/jniprefs.c +++ b/Android/jni/jniprefs.c @@ -110,6 +110,11 @@ void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickVisibili joydriver_setShowControls(visibility); } +void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickAzimuthVisibility(JNIEnv *env, jclass cls, jboolean visibility) { + LOG("visibility: %d", visibility); + joydriver_setShowAzimuth(visibility); +} + jint Java_org_deadc0de_apple2ix_Apple2Preferences_nativeGetCurrentTouchDevice(JNIEnv *env, jclass cls) { LOG("%s", ""); if (joydriver_ownsScreen()) { @@ -130,19 +135,28 @@ void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchMenuEnabled(JNIE interface_setTouchMenuEnabled(enabled); } +void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetShowDiskOperationAnimation(JNIEnv *env, jclass cls, jboolean enabled) { + LOG("enabled : %d", enabled); + if (video_backend && video_backend->animation_setEnableShowTrackSector) { + video_backend->animation_setEnableShowTrackSector(enabled); + } +} + void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchKeyboardLowercaseEnabled(JNIEnv *env, jclass cls, jboolean enabled) { LOG("enabled : %d", enabled); keydriver_setLowercaseEnabled(enabled); } -void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchMenuVisibility(JNIEnv *env, jclass cls, jfloat alpha) { - LOG("visibility : %f", alpha); - interface_setTouchMenuVisibility(alpha); -} - void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchKeyboardVisibility(JNIEnv *env, jclass cls, jfloat inactiveAlpha, jfloat activeAlpha) { LOG("inactive:%f active:%f", inactiveAlpha, activeAlpha); keydriver_setVisibilityWhenOwnsScreen(inactiveAlpha, activeAlpha); + interface_setTouchMenuVisibility(inactiveAlpha, activeAlpha); +} + +void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchKeyboardGlyphScale(JNIEnv *env, jclass cls, jint glyphScale) { + LOG("glyphScale:%d", glyphScale); + keydriver_setGlyphScale(glyphScale); + interface_setGlyphScale(glyphScale); } void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickButtonTypes(JNIEnv *env, jclass cls, jint touchDownButton, jint northButton, jint southButton) { @@ -170,7 +184,7 @@ void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeSetTouchJoystickButtonTy rosetteChars[ROSETTE_NORTH] = (uint8_t)MOUSETEXT_UP; rosetteScancodes[ROSETTE_NORTH] = -1; rosetteChars[ROSETTE_NORTHEAST] = ' '; rosetteScancodes[ROSETTE_NORTHEAST] = -1; rosetteChars[ROSETTE_WEST] = (uint8_t)MOUSETEXT_LEFT; rosetteScancodes[ROSETTE_WEST] = -1; - rosetteChars[ROSETTE_CENTER] = '+'; rosetteScancodes[ROSETTE_CENTER] = -1; + rosetteChars[ROSETTE_CENTER] = ICONTEXT_MENU_TOUCHJOY; rosetteScancodes[ROSETTE_CENTER] = -1; rosetteChars[ROSETTE_EAST] = (uint8_t)MOUSETEXT_RIGHT; rosetteScancodes[ROSETTE_EAST] = -1; rosetteChars[ROSETTE_SOUTHWEST] = ' '; rosetteScancodes[ROSETTE_SOUTHWEST] = -1; rosetteChars[ROSETTE_SOUTH] = (uint8_t)MOUSETEXT_DOWN; rosetteScancodes[ROSETTE_SOUTH] = -1; @@ -227,6 +241,9 @@ void Java_org_deadc0de_apple2ix_Apple2Preferences_nativeTouchJoystickSetKeypadTy for (unsigned int i=0; i<(ROSETTE_ROWS * ROSETTE_COLS); i++) { actualChars[i] = (uint8_t)rosetteChars[i]; } + if (actualChars[4] == ICONTEXT_NONACTIONABLE) { + actualChars[4] = ICONTEXT_MENU_TOUCHJOY; + } joydriver_setTouchAxisTypes(actualChars, rosetteScans); joydriver_setTouchButtonTypes( (touchjoy_button_type_t)buttonsChars[0], buttonsScans[0], diff --git a/Android/jni/sources.mk b/Android/jni/sources.mk index 19f2ef0c..45bde6e7 100644 --- a/Android/jni/sources.mk +++ b/Android/jni/sources.mk @@ -39,7 +39,7 @@ APPLE2_MAIN_SRC = \ $(APPLE2_SRC_PATH)/interface.c $(APPLE2_SRC_PATH)/disk.c $(APPLE2_SRC_PATH)/cpu-supp.c \ jnihooks.c jniprefs.c androidkeys.c -APPLE2_OPTIM_CFLAGS := -g -O2 +APPLE2_OPTIM_CFLAGS := -O2 APPLE2_BASE_CFLAGS := -DAPPLE2IX=1 -DINTERFACE_TOUCH=1 -DMOBILE_DEVICE=1 -DVIDEO_OPENGL=1 -DDEBUGGER=1 -DAUDIO_ENABLED=1 -std=gnu11 -DPREVENT_TEXTREL=1 -fPIC $(APPLE2_OPTIM_CFLAGS) -I$(APPLE2_SRC_PATH) APPLE2_BASE_LDLIBS := -llog -landroid -lGLESv2 -lz -lOpenSLES diff --git a/Android/jni/testcpu.mk b/Android/jni/testcpu.mk index 507c56a7..e21cee67 100644 --- a/Android/jni/testcpu.mk +++ b/Android/jni/testcpu.mk @@ -12,12 +12,13 @@ include $(COMMON_SOURCES_MK) LOCAL_MODULE := libapple2ix LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testcpu.c -LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_CPU -DTESTING=1 +LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_CPU -DTESTING=1 LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS) # Add assembly files first ... mostly for the benefit of the ARM assembler ... ifeq ($(TARGET_ARCH_ABI),x86) LOCAL_SRC_FILES += $(APPLE2_X86_SRC) + LOCAL_CFLAGS += -DNO_UNDERSCORES=1 else LOCAL_SRC_FILES += $(APPLE2_ARM_SRC) endif diff --git a/Android/jni/testdisk.mk b/Android/jni/testdisk.mk index 191ba9c3..cee8bc07 100644 --- a/Android/jni/testdisk.mk +++ b/Android/jni/testdisk.mk @@ -12,12 +12,13 @@ include $(COMMON_SOURCES_MK) LOCAL_MODULE := libapple2ix LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testdisk.c -LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_DISK -DTESTING=1 -DDISK_TRACING=1 +LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_DISK -DTESTING=1 -DDISK_TRACING=1 LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS) # Add assembly files first ... mostly for the benefit of the ARM assembler ... ifeq ($(TARGET_ARCH_ABI),x86) LOCAL_SRC_FILES += $(APPLE2_X86_SRC) + LOCAL_CFLAGS += -DNO_UNDERSCORES=1 else LOCAL_SRC_FILES += $(APPLE2_ARM_SRC) endif diff --git a/Android/jni/testdisplay.mk b/Android/jni/testdisplay.mk index a58867a2..54655743 100644 --- a/Android/jni/testdisplay.mk +++ b/Android/jni/testdisplay.mk @@ -12,12 +12,13 @@ include $(COMMON_SOURCES_MK) LOCAL_MODULE := libapple2ix LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testdisplay.c -LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_DISPLAY -DTESTING=1 +LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_DISPLAY -DTESTING=1 LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS) # Add assembly files first ... mostly for the benefit of the ARM assembler ... ifeq ($(TARGET_ARCH_ABI),x86) LOCAL_SRC_FILES += $(APPLE2_X86_SRC) + LOCAL_CFLAGS += -DNO_UNDERSCORES=1 else LOCAL_SRC_FILES += $(APPLE2_ARM_SRC) endif diff --git a/Android/jni/testvm.mk b/Android/jni/testvm.mk index 5dc4c282..a6f0ca10 100644 --- a/Android/jni/testvm.mk +++ b/Android/jni/testvm.mk @@ -12,12 +12,13 @@ include $(COMMON_SOURCES_MK) LOCAL_MODULE := libapple2ix LOCAL_SRC_FILES := $(APPLE2_SRC_PATH)/test/testcommon.c $(APPLE2_SRC_PATH)/test/testvm.c -LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -DTEST_VM -DTESTING=1 +LOCAL_CFLAGS := $(APPLE2_BASE_CFLAGS) -g -DTEST_VM -DTESTING=1 LOCAL_LDLIBS := $(APPLE2_BASE_LDLIBS) # Add assembly files first ... mostly for the benefit of the ARM assembler ... ifeq ($(TARGET_ARCH_ABI),x86) LOCAL_SRC_FILES += $(APPLE2_X86_SRC) + LOCAL_CFLAGS += -DNO_UNDERSCORES=1 else LOCAL_SRC_FILES += $(APPLE2_ARM_SRC) endif diff --git a/Android/toolchain_edits/adb_sanitize.c b/Android/toolchain_edits/adb_sanitize.c index 2123ab12..340f6ff6 100644 --- a/Android/toolchain_edits/adb_sanitize.c +++ b/Android/toolchain_edits/adb_sanitize.c @@ -56,26 +56,31 @@ static int _convert_crlf_to_lf(void) { // convert CRLF -> LF - ssize_t outlen=0; + ssize_t outmax=0; for (ssize_t i=0; i 0); } if (sawCR) { diff --git a/Apple2Mac/Apple2Mac-Prefix.pch b/Apple2Mac/Apple2Mac-Prefix.pch new file mode 100644 index 00000000..8080f30f --- /dev/null +++ b/Apple2Mac/Apple2Mac-Prefix.pch @@ -0,0 +1,17 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#if TARGET_OS_IPHONE +# ifdef __OBJC__ +# import +# endif +#else +# ifdef __OBJC__ +# import +# endif +#endif diff --git a/Apple2Mac/Apple2Mac.xcodeproj/project.pbxproj b/Apple2Mac/Apple2Mac.xcodeproj/project.pbxproj index cc6033b2..0d4fd03c 100644 --- a/Apple2Mac/Apple2Mac.xcodeproj/project.pbxproj +++ b/Apple2Mac/Apple2Mac.xcodeproj/project.pbxproj @@ -3,15 +3,12 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 47; objects = { /* Begin PBXBuildFile section */ 4A2636F919FDEDB700DBFB00 /* Apple2Mac.help in Resources */ = {isa = PBXBuildFile; fileRef = 4A2636F819FDEDB700DBFB00 /* Apple2Mac.help */; }; - 4A61119C1A6A1DE60035F7DE /* blank.po.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4A61119B1A6A1DE60035F7DE /* blank.po.gz */; }; 4A61119D1A6A1DE60035F7DE /* blank.po.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4A61119B1A6A1DE60035F7DE /* blank.po.gz */; }; - 4A6111A31A6A1DFC0035F7DE /* flapple140.po.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4A6111A21A6A1DFC0035F7DE /* flapple140.po.gz */; }; - 4A69C1801A33D6D7001579EF /* images in Resources */ = {isa = PBXBuildFile; fileRef = 4A69C17F1A33D6D7001579EF /* images */; }; 4A69C1921A33DB90001579EF /* DDHidLib.framework in Copy Files (1 item) */ = {isa = PBXBuildFile; fileRef = 77C2796F1A1047AF000FE33F /* DDHidLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4A7EDC931AE092680072E98A /* glhudmodel.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A7EDC911AE092680072E98A /* glhudmodel.c */; }; 4A7EDC941AE092680072E98A /* glhudmodel.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A7EDC911AE092680072E98A /* glhudmodel.c */; }; @@ -28,7 +25,6 @@ 4A7EDCA01AE092B80072E98A /* interface.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A7EDC9D1AE092B80072E98A /* interface.c */; }; 4A7EDCA11AE092B80072E98A /* interface.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A7EDC9D1AE092B80072E98A /* interface.c */; }; 4A7EDCA21AE092B80072E98A /* interface.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A7EDC9D1AE092B80072E98A /* interface.c */; }; - 4AC7A76D19ECC3FB00BCD457 /* EmulatorWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AC7A76C19ECC3FB00BCD457 /* EmulatorWindow.m */; }; 4AD4FE941A52464F00F958EC /* cpu.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9019568A570085CE5F /* cpu.S */; }; 4AD4FE951A52464F00F958EC /* prefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7719568A570085CE5F /* prefs.c */; }; 4AD4FE961A52464F00F958EC /* display.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6419568A570085CE5F /* display.c */; }; @@ -45,7 +41,6 @@ 4AD4FEA11A52464F00F958EC /* rom-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 779DD826195764E200DF89E5 /* rom-shim.c */; }; 4AD4FEA21A52464F00F958EC /* zlib-helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9519568A570085CE5F /* zlib-helpers.c */; }; 4AD4FEA31A52464F00F958EC /* darwin-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6019568A570085CE5F /* darwin-shim.c */; }; - 4AD4FEA41A52464F00F958EC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D1B1956885A0085CE5F /* main.m */; }; 4AD4FEA51A52464F00F958EC /* vectorUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0A919D72700004344E0 /* vectorUtil.c */; }; 4AD4FEA61A52464F00F958EC /* debug.l in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7219568A570085CE5F /* debug.l */; }; 4AD4FEA71A52464F00F958EC /* CPUTestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 779DD854195BDB1700DF89E5 /* CPUTestAppDelegate.m */; }; @@ -56,7 +51,6 @@ 4AD4FEAD1A52464F00F958EC /* matrixUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AF19D72700004344E0 /* matrixUtil.c */; }; 4AD4FEAE1A52464F00F958EC /* joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6C19568A570085CE5F /* joystick.c */; }; 4AD4FEB01A52464F00F958EC /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 779F565F19EAF6D000A6F107 /* OpenAL.framework */; }; - 4AD4FEB11A52464F00F958EC /* libz.1.1.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */; }; 4AD4FEB21A52464F00F958EC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3D0F1956885A0085CE5F /* Cocoa.framework */; }; 4AD4FEB51A52464F00F958EC /* blank.dsk.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC523019E8D3F600186B36 /* blank.dsk.gz */; }; 4AD4FEB61A52464F00F958EC /* blank.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC523119E8D3F600186B36 /* blank.nib.gz */; }; @@ -79,7 +73,6 @@ 4ADC51C719E8BD5800186B36 /* Basic.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 779F562719E4FE9E00A6F107 /* Basic.vsh */; }; 4ADC51C819E8BD5A00186B36 /* Basic.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 779F562819E4FE9E00A6F107 /* Basic.fsh */; }; 4ADC51CD19E8C19A00186B36 /* MainMenu-Test.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC51C919E8BEB700186B36 /* MainMenu-Test.xib */; }; - 4ADC51FA19E8C6EF00186B36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D1B1956885A0085CE5F /* main.m */; }; 4ADC51FE19E8CA4500186B36 /* cpu.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9019568A570085CE5F /* cpu.S */; }; 4ADC51FF19E8CA4500186B36 /* prefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7719568A570085CE5F /* prefs.c */; }; 4ADC520019E8CA4500186B36 /* display.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6419568A570085CE5F /* display.c */; }; @@ -96,7 +89,6 @@ 4ADC520B19E8CA4500186B36 /* rom-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 779DD826195764E200DF89E5 /* rom-shim.c */; }; 4ADC520C19E8CA4500186B36 /* zlib-helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9519568A570085CE5F /* zlib-helpers.c */; }; 4ADC520D19E8CA4500186B36 /* darwin-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6019568A570085CE5F /* darwin-shim.c */; }; - 4ADC520E19E8CA4500186B36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D1B1956885A0085CE5F /* main.m */; }; 4ADC520F19E8CA4500186B36 /* vectorUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0A919D72700004344E0 /* vectorUtil.c */; }; 4ADC521019E8CA4500186B36 /* debug.l in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7219568A570085CE5F /* debug.l */; }; 4ADC521119E8CA4500186B36 /* CPUTestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 779DD854195BDB1700DF89E5 /* CPUTestAppDelegate.m */; }; @@ -106,7 +98,6 @@ 4ADC521619E8CA4500186B36 /* darwin-glue.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9119568A570085CE5F /* darwin-glue.S */; }; 4ADC521719E8CA4500186B36 /* matrixUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AF19D72700004344E0 /* matrixUtil.c */; }; 4ADC521819E8CA4500186B36 /* joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6C19568A570085CE5F /* joystick.c */; }; - 4ADC521A19E8CA4500186B36 /* libz.1.1.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */; }; 4ADC521B19E8CA4500186B36 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3D0F1956885A0085CE5F /* Cocoa.framework */; }; 4ADC521E19E8CA4500186B36 /* MainMenu-Test.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC51C919E8BEB700186B36 /* MainMenu-Test.xib */; }; 4ADC521F19E8CA4500186B36 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 773B3D181956885A0085CE5F /* InfoPlist.strings */; }; @@ -125,17 +116,36 @@ 4AFC170C1AAE9C3200B215FA /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC17091AAE9C3200B215FA /* sha1.c */; }; 4AFC170D1AAE9C3200B215FA /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC17091AAE9C3200B215FA /* sha1.c */; }; 4AFC170E1AAE9C3200B215FA /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC17091AAE9C3200B215FA /* sha1.c */; }; - 4AFC17111AAE9CC000B215FA /* testdisplay1.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4AFC170F1AAE9CC000B215FA /* testdisplay1.nib.gz */; }; 4AFC17121AAE9CC000B215FA /* testdisplay1.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4AFC170F1AAE9CC000B215FA /* testdisplay1.nib.gz */; }; 4AFC17131AAE9CC000B215FA /* testdisplay1.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4AFC170F1AAE9CC000B215FA /* testdisplay1.nib.gz */; }; 4AFC17141AAE9CC000B215FA /* testdisplay1.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4AFC170F1AAE9CC000B215FA /* testdisplay1.nib.gz */; }; - 4AFC17151AAE9CC000B215FA /* testvm1.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4AFC17101AAE9CC000B215FA /* testvm1.nib.gz */; }; 4AFC17161AAE9CC000B215FA /* testvm1.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4AFC17101AAE9CC000B215FA /* testvm1.nib.gz */; }; 4AFC17171AAE9CC000B215FA /* testvm1.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4AFC17101AAE9CC000B215FA /* testvm1.nib.gz */; }; 4AFC17181AAE9CC000B215FA /* testvm1.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4AFC17101AAE9CC000B215FA /* testvm1.nib.gz */; }; + 4E1733E31C2C5F7600CDF9DF /* iosPrefControllerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E4E62A01C2C5B56002E324F /* iosPrefControllerViewController.m */; }; + 4E1733E41C2C5F7A00CDF9DF /* AppleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E1733DD1C2C5E5D00CDF9DF /* AppleViewController.m */; }; + 4EB4F8571C393F0E0072A15C /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EB4F8561C393F0E0072A15C /* OpenAL.framework */; }; + 4ECBEADF1C3432010046F537 /* speedtest.dsk in Resources */ = {isa = PBXBuildFile; fileRef = 4ECBEADD1C3432010046F537 /* speedtest.dsk */; }; + 4ECBEAE01C3432010046F537 /* testvm1.dsk in Resources */ = {isa = PBXBuildFile; fileRef = 4ECBEADE1C3432010046F537 /* testvm1.dsk */; }; + 4ECFC39E1C368620008E2633 /* flapple140.po in Resources */ = {isa = PBXBuildFile; fileRef = 4ECFC39B1C368620008E2633 /* flapple140.po */; }; + 4ECFC39F1C368620008E2633 /* mystery.dsk in Resources */ = {isa = PBXBuildFile; fileRef = 4ECFC39C1C368620008E2633 /* mystery.dsk */; }; + 4ECFC3A01C368620008E2633 /* NSCT.dsk in Resources */ = {isa = PBXBuildFile; fileRef = 4ECFC39D1C368620008E2633 /* NSCT.dsk */; }; + 4ECFC3A11C368643008E2633 /* NSCT.dsk in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4ECFC39D1C368620008E2633 /* NSCT.dsk */; }; + 4ECFC3A21C368645008E2633 /* flapple140.po in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4ECFC39B1C368620008E2633 /* flapple140.po */; }; + 4ECFC3A31C368647008E2633 /* mystery.dsk in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4ECFC39C1C368620008E2633 /* mystery.dsk */; }; + 4ECFC3A41C368649008E2633 /* speedtest.dsk in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4ECBEADD1C3432010046F537 /* speedtest.dsk */; }; + 4ECFC3A51C36864B008E2633 /* testvm1.dsk in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4ECBEADE1C3432010046F537 /* testvm1.dsk */; }; + 4ECFC3AE1C368EAB008E2633 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ECFC3AD1C368EAB008E2633 /* main.m */; }; + 4ECFC3B11C368EAB008E2633 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ECFC3B01C368EAB008E2633 /* AppDelegate.m */; }; + 4ECFC3B41C368EAB008E2633 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ECFC3B31C368EAB008E2633 /* ViewController.m */; }; + 4ECFC3B71C368EAB008E2633 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4ECFC3B51C368EAB008E2633 /* Main.storyboard */; }; + 4ECFC3B91C368EAC008E2633 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4ECFC3B81C368EAC008E2633 /* Assets.xcassets */; }; + 4ECFC3BF1C368ED3008E2633 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4ECFC3BE1C368ED3008E2633 /* GameController.framework */; }; + 4EEF0E8A1C3536A3001BEB67 /* disksViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EEF0E891C3536A3001BEB67 /* disksViewController.m */; }; + 4EF7D04D1C38204C007E0ADD /* floppy.png in Resources */ = {isa = PBXBuildFile; fileRef = 4EF7D04C1C38204C007E0ADD /* floppy.png */; }; + 4EF7D04E1C38204C007E0ADD /* floppy.png in Resources */ = {isa = PBXBuildFile; fileRef = 4EF7D04C1C38204C007E0ADD /* floppy.png */; }; 773B3D101956885A0085CE5F /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3D0F1956885A0085CE5F /* Cocoa.framework */; }; 773B3D1A1956885A0085CE5F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 773B3D181956885A0085CE5F /* InfoPlist.strings */; }; - 773B3D1C1956885A0085CE5F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D1B1956885A0085CE5F /* main.m */; }; 773B3D201956885A0085CE5F /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 773B3D1E1956885A0085CE5F /* Credits.rtf */; }; 773B3D281956885A0085CE5F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 773B3D271956885A0085CE5F /* Images.xcassets */; }; 773B3DA019568A570085CE5F /* cpu-supp.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D5D19568A570085CE5F /* cpu-supp.c */; }; @@ -154,9 +164,6 @@ 773B3DBF19568A570085CE5F /* cpu.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9019568A570085CE5F /* cpu.S */; }; 773B3DC019568A570085CE5F /* darwin-glue.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9119568A570085CE5F /* darwin-glue.S */; }; 773B3DC319568A570085CE5F /* zlib-helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9519568A570085CE5F /* zlib-helpers.c */; }; - 773B3DCB1956903D0085CE5F /* libz.1.1.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */; }; - 773BC91619F2E6A900996893 /* EmulatorDiskController.m in Sources */ = {isa = PBXBuildFile; fileRef = 773BC91519F2E6A900996893 /* EmulatorDiskController.m */; }; - 773BC91919F2FD4500996893 /* EmulatorPrefsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 773BC91819F2FD4500996893 /* EmulatorPrefsController.m */; }; 773BC91A19F31E7B00996893 /* prefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7719568A570085CE5F /* prefs.c */; }; 779DD827195764E200DF89E5 /* rom-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 779DD826195764E200DF89E5 /* rom-shim.c */; }; 779DD82F195BD9F900DF89E5 /* cpu.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9019568A570085CE5F /* cpu.S */; }; @@ -177,7 +184,6 @@ 779DD83F195BD9F900DF89E5 /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D8D19568A570085CE5F /* vm.c */; }; 779DD840195BD9F900DF89E5 /* darwin-glue.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9119568A570085CE5F /* darwin-glue.S */; }; 779DD843195BD9F900DF89E5 /* joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6C19568A570085CE5F /* joystick.c */; }; - 779DD845195BD9F900DF89E5 /* libz.1.1.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */; }; 779DD846195BD9F900DF89E5 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3D0F1956885A0085CE5F /* Cocoa.framework */; }; 779DD849195BD9F900DF89E5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 773B3D181956885A0085CE5F /* InfoPlist.strings */; }; 779DD84A195BD9F900DF89E5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 773B3D271956885A0085CE5F /* Images.xcassets */; }; @@ -212,7 +218,6 @@ 779F567119EB0B9100A6F107 /* rom-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 779DD826195764E200DF89E5 /* rom-shim.c */; }; 779F567219EB0B9100A6F107 /* zlib-helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9519568A570085CE5F /* zlib-helpers.c */; }; 779F567319EB0B9100A6F107 /* darwin-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6019568A570085CE5F /* darwin-shim.c */; }; - 779F567419EB0B9100A6F107 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D1B1956885A0085CE5F /* main.m */; }; 779F567519EB0B9100A6F107 /* vectorUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0A919D72700004344E0 /* vectorUtil.c */; }; 779F567619EB0B9100A6F107 /* debug.l in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7219568A570085CE5F /* debug.l */; }; 779F567719EB0B9100A6F107 /* CPUTestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 779DD854195BDB1700DF89E5 /* CPUTestAppDelegate.m */; }; @@ -223,7 +228,6 @@ 779F567D19EB0B9100A6F107 /* matrixUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AF19D72700004344E0 /* matrixUtil.c */; }; 779F567E19EB0B9100A6F107 /* joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6C19568A570085CE5F /* joystick.c */; }; 779F568019EB0B9100A6F107 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 779F565F19EAF6D000A6F107 /* OpenAL.framework */; }; - 779F568119EB0B9100A6F107 /* libz.1.1.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */; }; 779F568219EB0B9100A6F107 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3D0F1956885A0085CE5F /* Cocoa.framework */; }; 779F568619EB0B9100A6F107 /* README in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC523419E8D3F600186B36 /* README */; }; 779F568719EB0B9100A6F107 /* MainMenu-Test.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC51C919E8BEB700186B36 /* MainMenu-Test.xib */; }; @@ -236,20 +240,87 @@ 779F569319EB0D1E00A6F107 /* testdisplay.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7F19568A570085CE5F /* testdisplay.c */; }; 779F569419EB10A100A6F107 /* testdisplay1.dsk.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC523719E8D3F600186B36 /* testdisplay1.dsk.gz */; }; 77C279701A1047DD000FE33F /* DDHidLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C2796F1A1047AF000FE33F /* DDHidLib.framework */; }; - 77C279751A1048B4000FE33F /* EmulatorJoystickController.m in Sources */ = {isa = PBXBuildFile; fileRef = 77C279741A1048B4000FE33F /* EmulatorJoystickController.m */; }; 77E1C0B319D72700004344E0 /* vectorUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0A919D72700004344E0 /* vectorUtil.c */; }; 77E1C0B419D72700004344E0 /* sourceUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AB19D72700004344E0 /* sourceUtil.c */; }; 77E1C0B519D72700004344E0 /* modelUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AD19D72700004344E0 /* modelUtil.c */; }; 77E1C0B619D72700004344E0 /* matrixUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AF19D72700004344E0 /* matrixUtil.c */; }; 77E1C0B719D72700004344E0 /* imageUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0B019D72700004344E0 /* imageUtil.m */; }; - 77E1C0C419D7298F004344E0 /* EmulatorWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0BE19D7298F004344E0 /* EmulatorWindowController.m */; }; - 77E1C0C519D7298F004344E0 /* EmulatorGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0C019D7298F004344E0 /* EmulatorGLView.m */; }; - 77E1C0C619D7298F004344E0 /* EmulatorFullscreenWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0C219D7298F004344E0 /* EmulatorFullscreenWindow.m */; }; 77EB316C1A27A9AF00DC5A8A /* blank.dsk.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC523019E8D3F600186B36 /* blank.dsk.gz */; }; 77EB316D1A27A9AF00DC5A8A /* blank.nib.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4ADC523119E8D3F600186B36 /* blank.nib.gz */; }; - 77F80B441A2D95E300D45030 /* EmulatorJoystickCalibrationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 77F80B421A2D95E300D45030 /* EmulatorJoystickCalibrationView.m */; }; - 93BC72551BF6F8E2005CDFCA /* glalert.c in Sources */ = {isa = PBXBuildFile; fileRef = 93BC72541BF6F8E2005CDFCA /* glalert.c */; settings = {ASSET_TAGS = (); }; }; - 93BC72571BF6FF11005CDFCA /* playqueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 93BC72561BF6FF11005CDFCA /* playqueue.c */; settings = {ASSET_TAGS = (); }; }; + 93206C781C14E14000668153 /* Apple2iOS.strings in Resources */ = {isa = PBXBuildFile; fileRef = 93206C761C14E14000668153 /* Apple2iOS.strings */; }; + 93206C851C156BD300668153 /* A2IXPopupChoreographer.m in Sources */ = {isa = PBXBuildFile; fileRef = 93206C841C156BD300668153 /* A2IXPopupChoreographer.m */; }; + 935C55131C12B61D0013166D /* EmulatorGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C55041C12B61D0013166D /* EmulatorGLView.m */; }; + 935C55141C12B61D0013166D /* EmulatorDiskController.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C55061C12B61D0013166D /* EmulatorDiskController.m */; }; + 935C55151C12B61D0013166D /* EmulatorFullscreenWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C55081C12B61D0013166D /* EmulatorFullscreenWindow.m */; }; + 935C55161C12B61D0013166D /* EmulatorJoystickCalibrationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C550A1C12B61D0013166D /* EmulatorJoystickCalibrationView.m */; }; + 935C55171C12B61D0013166D /* EmulatorJoystickController.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C550C1C12B61D0013166D /* EmulatorJoystickController.m */; }; + 935C55181C12B61D0013166D /* EmulatorPrefsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C550E1C12B61D0013166D /* EmulatorPrefsController.m */; }; + 935C55191C12B61D0013166D /* EmulatorWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C55101C12B61D0013166D /* EmulatorWindow.m */; }; + 935C551A1C12B61D0013166D /* EmulatorWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C55121C12B61D0013166D /* EmulatorWindowController.m */; }; + 935C551C1C12B6400013166D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C551B1C12B6400013166D /* main.m */; }; + 935C551D1C12B6450013166D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C551B1C12B6400013166D /* main.m */; }; + 935C551E1C12B6450013166D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C551B1C12B6400013166D /* main.m */; }; + 935C551F1C12B6460013166D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C551B1C12B6400013166D /* main.m */; }; + 935C55201C12B64A0013166D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C551B1C12B6400013166D /* main.m */; }; + 935C55351C12BA5F0013166D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 935C55331C12BA5F0013166D /* Main.storyboard */; }; + 935C55371C12BA5F0013166D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 935C55361C12BA5F0013166D /* Assets.xcassets */; }; + 935C55431C12BCFD0013166D /* Apple2iOS-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 935C55421C12BCFD0013166D /* Apple2iOS-Info.plist */; }; + 935C55461C12BE110013166D /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 935C55441C12BE110013166D /* LaunchScreen.xib */; }; + 935C554D1C12BE510013166D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C55481C12BE510013166D /* AppDelegate.m */; }; + 935C554E1C12BE510013166D /* EAGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C554A1C12BE510013166D /* EAGLView.m */; }; + 935C55511C136DF40013166D /* alhelpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 779F564719EAF66E00A6F107 /* alhelpers.c */; }; + 935C55521C136DF40013166D /* AY8910.c in Sources */ = {isa = PBXBuildFile; fileRef = 779F564919EAF66E00A6F107 /* AY8910.c */; }; + 935C55531C136DF40013166D /* mockingboard.c in Sources */ = {isa = PBXBuildFile; fileRef = 779F564C19EAF66E00A6F107 /* mockingboard.c */; }; + 935C55541C136DF40013166D /* playqueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 93BC72561BF6FF11005CDFCA /* playqueue.c */; }; + 935C55551C136DF40013166D /* soundcore-openal.c in Sources */ = {isa = PBXBuildFile; fileRef = 779F564F19EAF66E00A6F107 /* soundcore-openal.c */; }; + 935C55561C136DF40013166D /* soundcore.c in Sources */ = {isa = PBXBuildFile; fileRef = 779F565119EAF66E00A6F107 /* soundcore.c */; }; + 935C55571C136DF40013166D /* speaker.c in Sources */ = {isa = PBXBuildFile; fileRef = 779F565319EAF66E00A6F107 /* speaker.c */; }; + 935C55581C136DF40013166D /* cpu-supp.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D5D19568A570085CE5F /* cpu-supp.c */; }; + 935C55591C136DF40013166D /* darwin-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6019568A570085CE5F /* darwin-shim.c */; }; + 935C555A1C136DF40013166D /* disk.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6219568A570085CE5F /* disk.c */; }; + 935C555B1C136DF40013166D /* display.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6419568A570085CE5F /* display.c */; }; + 935C555C1C136DF40013166D /* font.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6519568A570085CE5F /* font.c */; }; + 935C555D1C136DF40013166D /* interface.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A7EDC9D1AE092B80072E98A /* interface.c */; }; + 935C555E1C136DF40013166D /* joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6C19568A570085CE5F /* joystick.c */; }; + 935C555F1C136DF40013166D /* keys.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D6E19568A570085CE5F /* keys.c */; }; + 935C55601C136E070013166D /* debugger.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7319568A570085CE5F /* debugger.c */; }; + 935C55611C136E070013166D /* opcodes.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7419568A570085CE5F /* opcodes.c */; }; + 935C55621C136E070013166D /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7519568A570085CE5F /* misc.c */; }; + 935C55631C136E070013166D /* prefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7719568A570085CE5F /* prefs.c */; }; + 935C55641C136E070013166D /* rom-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 779DD826195764E200DF89E5 /* rom-shim.c */; }; + 935C55651C136E070013166D /* timing.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D8719568A570085CE5F /* timing.c */; }; + 935C55661C136E070013166D /* glalert.c in Sources */ = {isa = PBXBuildFile; fileRef = 93BC72541BF6F8E2005CDFCA /* glalert.c */; }; + 935C55671C136E070013166D /* glhudmodel.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A7EDC911AE092680072E98A /* glhudmodel.c */; }; + 935C55681C136E070013166D /* glnode.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A7EDC921AE092680072E98A /* glnode.c */; }; + 935C55691C136E070013166D /* glvideo.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0C719D736EB004344E0 /* glvideo.c */; }; + 935C556A1C136E070013166D /* matrixUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AF19D72700004344E0 /* matrixUtil.c */; }; + 935C556B1C136E070013166D /* modelUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AD19D72700004344E0 /* modelUtil.c */; }; + 935C556C1C136E070013166D /* sourceUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0AB19D72700004344E0 /* sourceUtil.c */; }; + 935C556D1C136E070013166D /* vectorUtil.c in Sources */ = {isa = PBXBuildFile; fileRef = 77E1C0A919D72700004344E0 /* vectorUtil.c */; }; + 935C556E1C136E070013166D /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D8D19568A570085CE5F /* vm.c */; }; + 935C556F1C136E070013166D /* zlib-helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9519568A570085CE5F /* zlib-helpers.c */; }; + 935C55721C136E6F0013166D /* json_parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55701C136E6F0013166D /* json_parse.c */; }; + 935C55731C136E6F0013166D /* json_parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55701C136E6F0013166D /* json_parse.c */; }; + 935C558A1C1370800013166D /* gltouchjoy_joy.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55841C1370800013166D /* gltouchjoy_joy.c */; }; + 935C558B1C1370800013166D /* gltouchjoy_kpad.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55851C1370800013166D /* gltouchjoy_kpad.c */; }; + 935C558C1C1370800013166D /* gltouchjoy.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55861C1370800013166D /* gltouchjoy.c */; }; + 935C558D1C1370800013166D /* gltouchkbd.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55881C1370800013166D /* gltouchkbd.c */; }; + 935C558E1C1370800013166D /* gltouchmenu.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55891C1370800013166D /* gltouchmenu.c */; }; + 935C55911C1371AD0013166D /* Basic.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 779F562819E4FE9E00A6F107 /* Basic.fsh */; }; + 935C55921C1371AD0013166D /* Basic.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 779F562719E4FE9E00A6F107 /* Basic.vsh */; }; + 935C559F1C1384240013166D /* darwin-cpu-glue.S in Sources */ = {isa = PBXBuildFile; fileRef = 935C559E1C1384240013166D /* darwin-cpu-glue.S */; }; + 935C55A11C13887E0013166D /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC17091AAE9C3200B215FA /* sha1.c */; }; + 935C55A41C1388E30013166D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 935C551B1C12B6400013166D /* main.m */; }; + 935C55A91C1389370013166D /* jsmn.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55A71C1389370013166D /* jsmn.c */; }; + 935C55AA1C138C2F0013166D /* jsmn.c in Sources */ = {isa = PBXBuildFile; fileRef = 935C55A71C1389370013166D /* jsmn.c */; }; + 939C959E1C3B8E2100263E41 /* SolidColor.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 939C959C1C3B8E2100263E41 /* SolidColor.fsh */; }; + 939C959F1C3B8E2100263E41 /* SolidColor.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 939C959C1C3B8E2100263E41 /* SolidColor.fsh */; }; + 939C95A01C3B8E2100263E41 /* SolidColor.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 939C959C1C3B8E2100263E41 /* SolidColor.fsh */; }; + 939C95A11C3B8E2100263E41 /* SolidColor.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 939C959D1C3B8E2100263E41 /* SolidColor.vsh */; }; + 939C95A21C3B8E2100263E41 /* SolidColor.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 939C959D1C3B8E2100263E41 /* SolidColor.vsh */; }; + 939C95A31C3B8E2100263E41 /* SolidColor.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 939C959D1C3B8E2100263E41 /* SolidColor.vsh */; }; + 93BC72551BF6F8E2005CDFCA /* glalert.c in Sources */ = {isa = PBXBuildFile; fileRef = 93BC72541BF6F8E2005CDFCA /* glalert.c */; }; + 93BC72571BF6FF11005CDFCA /* playqueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 93BC72561BF6FF11005CDFCA /* playqueue.c */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -302,18 +373,28 @@ name = "Copy Files (1 item)"; runOnlyForDeploymentPostprocessing = 0; }; + 4E1733EF1C2E955700CDF9DF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = ./disks; + dstSubfolderSpec = 16; + files = ( + 4ECFC3A11C368643008E2633 /* NSCT.dsk in CopyFiles */, + 4ECFC3A21C368645008E2633 /* flapple140.po in CopyFiles */, + 4ECFC3A51C36864B008E2633 /* testvm1.dsk in CopyFiles */, + 4ECFC3A41C368649008E2633 /* speedtest.dsk in CopyFiles */, + 4ECFC3A31C368647008E2633 /* mystery.dsk in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 4A2636F819FDEDB700DBFB00 /* Apple2Mac.help */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Apple2Mac.help; sourceTree = ""; }; 4A61119B1A6A1DE60035F7DE /* blank.po.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = blank.po.gz; sourceTree = ""; }; - 4A6111A21A6A1DFC0035F7DE /* flapple140.po.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = flapple140.po.gz; sourceTree = ""; }; - 4A69C17F1A33D6D7001579EF /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../images; sourceTree = ""; }; 4A7EDC911AE092680072E98A /* glhudmodel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = glhudmodel.c; sourceTree = ""; }; 4A7EDC921AE092680072E98A /* glnode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = glnode.c; sourceTree = ""; }; 4A7EDC9D1AE092B80072E98A /* interface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interface.c; sourceTree = ""; }; - 4AC7A76B19ECC3FB00BCD457 /* EmulatorWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorWindow.h; path = Classes/OSX/EmulatorWindow.h; sourceTree = ""; }; - 4AC7A76C19ECC3FB00BCD457 /* EmulatorWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorWindow.m; path = Classes/OSX/EmulatorWindow.m; sourceTree = ""; }; 4AD4FEC31A52464F00F958EC /* Apple2MacTestDisk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Apple2MacTestDisk.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4AD4FEC41A52464F00F958EC /* Apple2MacTestDisk-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Apple2MacTestDisk-Info.plist"; path = "Apple2MacTests/Apple2MacTestDisk-Info.plist"; sourceTree = SOURCE_ROOT; }; 4AD4FEC91A52467D00F958EC /* testdisk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testdisk.c; sourceTree = ""; }; @@ -323,15 +404,49 @@ 4ADC523019E8D3F600186B36 /* blank.dsk.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = blank.dsk.gz; sourceTree = ""; }; 4ADC523119E8D3F600186B36 /* blank.nib.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = blank.nib.gz; sourceTree = ""; }; 4ADC523219E8D3F600186B36 /* etc.dsk.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = etc.dsk.gz; sourceTree = ""; }; - 4ADC523319E8D3F600186B36 /* mystery.dsk.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = mystery.dsk.gz; sourceTree = ""; }; 4ADC523419E8D3F600186B36 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; - 4ADC523519E8D3F600186B36 /* speedtest.dsk.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = speedtest.dsk.gz; sourceTree = ""; }; 4ADC523619E8D3F600186B36 /* speedtest.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = speedtest.txt; sourceTree = ""; }; 4ADC523719E8D3F600186B36 /* testdisplay1.dsk.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = testdisplay1.dsk.gz; sourceTree = ""; }; 4ADC523819E8D3F600186B36 /* testvm1.dsk.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = testvm1.dsk.gz; sourceTree = ""; }; 4AFC17091AAE9C3200B215FA /* sha1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sha1.c; sourceTree = ""; }; 4AFC170F1AAE9CC000B215FA /* testdisplay1.nib.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = testdisplay1.nib.gz; sourceTree = ""; }; 4AFC17101AAE9CC000B215FA /* testvm1.nib.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = testvm1.nib.gz; sourceTree = ""; }; + 4E1733DC1C2C5E5D00CDF9DF /* AppleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleViewController.h; sourceTree = ""; }; + 4E1733DD1C2C5E5D00CDF9DF /* AppleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppleViewController.m; sourceTree = ""; }; + 4E1ACFE61C2B0F3600C755BB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Main.strings; sourceTree = ""; }; + 4E1ACFE71C2B12F900C755BB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 4E4356E31C386AC500B71328 /* interface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interface.h; sourceTree = ""; }; + 4E4356E41C386AC500B71328 /* memmngt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memmngt.h; sourceTree = ""; }; + 4E4585F91C29F2B9003E74A1 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; + 4E4585FF1C29F393003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = "fr.lproj/MainMenu-Test.strings"; sourceTree = ""; }; + 4E4586001C29F399003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = fr; path = fr.lproj/Credits.rtf; sourceTree = ""; }; + 4E4586011C29F399003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; + 4E4586021C29F399003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = fr; path = fr.lproj/MainMenu.xib; sourceTree = ""; }; + 4E4586031C29F399003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = ""; }; + 4E4586041C29F399003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Main.strings; sourceTree = ""; }; + 4E4586051C29F399003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; + 4E4586061C29F39A003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Apple2iOS.strings; sourceTree = ""; }; + 4E4E629F1C2C5B56002E324F /* iosPrefControllerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iosPrefControllerViewController.h; sourceTree = ""; }; + 4E4E62A01C2C5B56002E324F /* iosPrefControllerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iosPrefControllerViewController.m; sourceTree = ""; }; + 4EB4F8561C393F0E0072A15C /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.2.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; }; + 4ECBEADD1C3432010046F537 /* speedtest.dsk */ = {isa = PBXFileReference; lastKnownFileType = file; path = speedtest.dsk; sourceTree = ""; }; + 4ECBEADE1C3432010046F537 /* testvm1.dsk */ = {isa = PBXFileReference; lastKnownFileType = file; path = testvm1.dsk; sourceTree = ""; }; + 4ECFC39B1C368620008E2633 /* flapple140.po */ = {isa = PBXFileReference; lastKnownFileType = file; path = flapple140.po; sourceTree = ""; }; + 4ECFC39C1C368620008E2633 /* mystery.dsk */ = {isa = PBXFileReference; lastKnownFileType = file; path = mystery.dsk; sourceTree = ""; }; + 4ECFC39D1C368620008E2633 /* NSCT.dsk */ = {isa = PBXFileReference; lastKnownFileType = file; path = NSCT.dsk; sourceTree = ""; }; + 4ECFC3AA1C368EAB008E2633 /* Apple2etvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Apple2etvOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4ECFC3AD1C368EAB008E2633 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 4ECFC3AF1C368EAB008E2633 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 4ECFC3B01C368EAB008E2633 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 4ECFC3B21C368EAB008E2633 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 4ECFC3B31C368EAB008E2633 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 4ECFC3B61C368EAB008E2633 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 4ECFC3B81C368EAC008E2633 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 4ECFC3BA1C368EAC008E2633 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4ECFC3BE1C368ED3008E2633 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.1.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; }; + 4EEF0E881C3536A3001BEB67 /* disksViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = disksViewController.h; sourceTree = ""; }; + 4EEF0E891C3536A3001BEB67 /* disksViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = disksViewController.m; sourceTree = ""; }; + 4EF7D04C1C38204C007E0ADD /* floppy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = floppy.png; path = ../floppy.png; sourceTree = ""; }; 773B3D0C1956885A0085CE5F /* Apple2Mac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Apple2Mac.app; sourceTree = BUILT_PRODUCTS_DIR; }; 773B3D0F1956885A0085CE5F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 773B3D121956885A0085CE5F /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -339,10 +454,7 @@ 773B3D141956885A0085CE5F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 773B3D171956885A0085CE5F /* Apple2Mac-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Apple2Mac-Info.plist"; sourceTree = ""; }; 773B3D191956885A0085CE5F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 773B3D1B1956885A0085CE5F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 773B3D1D1956885A0085CE5F /* Apple2Mac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Apple2Mac-Prefix.pch"; sourceTree = ""; }; 773B3D1F1956885A0085CE5F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; - 773B3D251956885A0085CE5F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 773B3D271956885A0085CE5F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 773B3D371956885A0085CE5F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 773B3D5C19568A570085CE5F /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; @@ -384,11 +496,6 @@ 773B3D9319568A570085CE5F /* glue-prologue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "glue-prologue.h"; sourceTree = ""; }; 773B3D9519568A570085CE5F /* zlib-helpers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "zlib-helpers.c"; sourceTree = ""; }; 773B3D9619568A570085CE5F /* zlib-helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "zlib-helpers.h"; sourceTree = ""; }; - 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.1.3.dylib; path = usr/lib/libz.1.1.3.dylib; sourceTree = SDKROOT; }; - 773BC91419F2E6A900996893 /* EmulatorDiskController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorDiskController.h; path = Classes/OSX/EmulatorDiskController.h; sourceTree = ""; }; - 773BC91519F2E6A900996893 /* EmulatorDiskController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorDiskController.m; path = Classes/OSX/EmulatorDiskController.m; sourceTree = ""; }; - 773BC91719F2FD4500996893 /* EmulatorPrefsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorPrefsController.h; path = Classes/OSX/EmulatorPrefsController.h; sourceTree = ""; }; - 773BC91819F2FD4500996893 /* EmulatorPrefsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorPrefsController.m; path = Classes/OSX/EmulatorPrefsController.m; sourceTree = ""; }; 779DD826195764E200DF89E5 /* rom-shim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "rom-shim.c"; sourceTree = ""; }; 779DD850195BD9F900DF89E5 /* Apple2MacTestCPU.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Apple2MacTestCPU.app; sourceTree = BUILT_PRODUCTS_DIR; }; 779DD851195BD9F900DF89E5 /* Apple2MacTestCPU-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Apple2MacTestCPU-Info.plist"; path = "Apple2MacTests/Apple2MacTestCPU-Info.plist"; sourceTree = SOURCE_ROOT; }; @@ -413,8 +520,6 @@ 779F569119EB0B9100A6F107 /* Apple2MacTestDisplay.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Apple2MacTestDisplay.app; sourceTree = BUILT_PRODUCTS_DIR; }; 779F569219EB0B9100A6F107 /* Apple2MacTestDisplay-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Apple2MacTestDisplay-Info.plist"; path = "Apple2MacTests/Apple2MacTestDisplay-Info.plist"; sourceTree = SOURCE_ROOT; }; 77C279601A1047AE000FE33F /* DDHidLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = DDHidLib.xcodeproj; path = DDHidLib/DDHidLib.xcodeproj; sourceTree = ""; }; - 77C279731A1048B4000FE33F /* EmulatorJoystickController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorJoystickController.h; path = Classes/OSX/EmulatorJoystickController.h; sourceTree = ""; }; - 77C279741A1048B4000FE33F /* EmulatorJoystickController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorJoystickController.m; path = Classes/OSX/EmulatorJoystickController.m; sourceTree = ""; }; 77E1C0A819D72700004344E0 /* vectorUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vectorUtil.h; path = video_util/vectorUtil.h; sourceTree = ""; }; 77E1C0A919D72700004344E0 /* vectorUtil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vectorUtil.c; path = video_util/vectorUtil.c; sourceTree = ""; }; 77E1C0AA19D72700004344E0 /* sourceUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sourceUtil.h; path = video_util/sourceUtil.h; sourceTree = ""; }; @@ -426,15 +531,59 @@ 77E1C0B019D72700004344E0 /* imageUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = imageUtil.m; path = video_util/imageUtil.m; sourceTree = ""; }; 77E1C0B119D72700004344E0 /* imageUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imageUtil.h; path = video_util/imageUtil.h; sourceTree = ""; }; 77E1C0B219D72700004344E0 /* glUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glUtil.h; path = video_util/glUtil.h; sourceTree = ""; }; - 77E1C0BE19D7298F004344E0 /* EmulatorWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorWindowController.m; path = Classes/OSX/EmulatorWindowController.m; sourceTree = ""; }; - 77E1C0BF19D7298F004344E0 /* EmulatorWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorWindowController.h; path = Classes/OSX/EmulatorWindowController.h; sourceTree = ""; }; - 77E1C0C019D7298F004344E0 /* EmulatorGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorGLView.m; path = Classes/OSX/EmulatorGLView.m; sourceTree = ""; }; - 77E1C0C119D7298F004344E0 /* EmulatorGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorGLView.h; path = Classes/OSX/EmulatorGLView.h; sourceTree = ""; }; - 77E1C0C219D7298F004344E0 /* EmulatorFullscreenWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorFullscreenWindow.m; path = Classes/OSX/EmulatorFullscreenWindow.m; sourceTree = ""; }; - 77E1C0C319D7298F004344E0 /* EmulatorFullscreenWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorFullscreenWindow.h; path = Classes/OSX/EmulatorFullscreenWindow.h; sourceTree = ""; }; 77E1C0C719D736EB004344E0 /* glvideo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = glvideo.c; sourceTree = ""; }; - 77F80B421A2D95E300D45030 /* EmulatorJoystickCalibrationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorJoystickCalibrationView.m; path = Classes/OSX/EmulatorJoystickCalibrationView.m; sourceTree = ""; }; - 77F80B431A2D95E300D45030 /* EmulatorJoystickCalibrationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorJoystickCalibrationView.h; path = Classes/OSX/EmulatorJoystickCalibrationView.h; sourceTree = ""; }; + 93206C771C14E14000668153 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Apple2iOS.strings; sourceTree = ""; }; + 93206C831C156BD300668153 /* A2IXPopupChoreographer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = A2IXPopupChoreographer.h; path = Classes/iOS/A2IXPopupChoreographer.h; sourceTree = SOURCE_ROOT; }; + 93206C841C156BD300668153 /* A2IXPopupChoreographer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = A2IXPopupChoreographer.m; path = Classes/iOS/A2IXPopupChoreographer.m; sourceTree = SOURCE_ROOT; }; + 935C55031C12B61D0013166D /* EmulatorGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorGLView.h; path = Classes/OSX/EmulatorGLView.h; sourceTree = SOURCE_ROOT; }; + 935C55041C12B61D0013166D /* EmulatorGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorGLView.m; path = Classes/OSX/EmulatorGLView.m; sourceTree = SOURCE_ROOT; }; + 935C55051C12B61D0013166D /* EmulatorDiskController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorDiskController.h; path = Classes/OSX/EmulatorDiskController.h; sourceTree = SOURCE_ROOT; }; + 935C55061C12B61D0013166D /* EmulatorDiskController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorDiskController.m; path = Classes/OSX/EmulatorDiskController.m; sourceTree = SOURCE_ROOT; }; + 935C55071C12B61D0013166D /* EmulatorFullscreenWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorFullscreenWindow.h; path = Classes/OSX/EmulatorFullscreenWindow.h; sourceTree = SOURCE_ROOT; }; + 935C55081C12B61D0013166D /* EmulatorFullscreenWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorFullscreenWindow.m; path = Classes/OSX/EmulatorFullscreenWindow.m; sourceTree = SOURCE_ROOT; }; + 935C55091C12B61D0013166D /* EmulatorJoystickCalibrationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorJoystickCalibrationView.h; path = Classes/OSX/EmulatorJoystickCalibrationView.h; sourceTree = SOURCE_ROOT; }; + 935C550A1C12B61D0013166D /* EmulatorJoystickCalibrationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorJoystickCalibrationView.m; path = Classes/OSX/EmulatorJoystickCalibrationView.m; sourceTree = SOURCE_ROOT; }; + 935C550B1C12B61D0013166D /* EmulatorJoystickController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorJoystickController.h; path = Classes/OSX/EmulatorJoystickController.h; sourceTree = SOURCE_ROOT; }; + 935C550C1C12B61D0013166D /* EmulatorJoystickController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorJoystickController.m; path = Classes/OSX/EmulatorJoystickController.m; sourceTree = SOURCE_ROOT; }; + 935C550D1C12B61D0013166D /* EmulatorPrefsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorPrefsController.h; path = Classes/OSX/EmulatorPrefsController.h; sourceTree = SOURCE_ROOT; }; + 935C550E1C12B61D0013166D /* EmulatorPrefsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorPrefsController.m; path = Classes/OSX/EmulatorPrefsController.m; sourceTree = SOURCE_ROOT; }; + 935C550F1C12B61D0013166D /* EmulatorWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorWindow.h; path = Classes/OSX/EmulatorWindow.h; sourceTree = SOURCE_ROOT; }; + 935C55101C12B61D0013166D /* EmulatorWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorWindow.m; path = Classes/OSX/EmulatorWindow.m; sourceTree = SOURCE_ROOT; }; + 935C55111C12B61D0013166D /* EmulatorWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorWindowController.h; path = Classes/OSX/EmulatorWindowController.h; sourceTree = SOURCE_ROOT; }; + 935C55121C12B61D0013166D /* EmulatorWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorWindowController.m; path = Classes/OSX/EmulatorWindowController.m; sourceTree = SOURCE_ROOT; }; + 935C551B1C12B6400013166D /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 935C55211C12B6650013166D /* Apple2Mac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Apple2Mac-Prefix.pch"; sourceTree = ""; }; + 935C55281C12BA5F0013166D /* Apple2iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Apple2iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 935C55341C12BA5F0013166D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 935C55361C12BA5F0013166D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 935C55421C12BCFD0013166D /* Apple2iOS-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Apple2iOS-Info.plist"; sourceTree = ""; }; + 935C55451C12BE110013166D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 935C55471C12BE510013166D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Classes/iOS/AppDelegate.h; sourceTree = SOURCE_ROOT; }; + 935C55481C12BE510013166D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Classes/iOS/AppDelegate.m; sourceTree = SOURCE_ROOT; }; + 935C55491C12BE510013166D /* EAGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EAGLView.h; path = Classes/iOS/EAGLView.h; sourceTree = SOURCE_ROOT; }; + 935C554A1C12BE510013166D /* EAGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EAGLView.m; path = Classes/iOS/EAGLView.m; sourceTree = SOURCE_ROOT; }; + 935C55701C136E6F0013166D /* json_parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = json_parse.c; sourceTree = ""; }; + 935C55711C136E6F0013166D /* json_parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_parse.h; sourceTree = ""; }; + 935C55741C136ED40013166D /* playqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playqueue.h; sourceTree = ""; }; + 935C55751C136F0D0013166D /* testtrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testtrace.c; sourceTree = ""; }; + 935C55771C136F260013166D /* sha1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha1.h; sourceTree = ""; }; + 935C557A1C136F7E0013166D /* cpu-regs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "cpu-regs.h"; path = "arm/cpu-regs.h"; sourceTree = ""; }; + 935C557C1C136FBD0013166D /* glue-prologue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "glue-prologue.h"; path = "arm/glue-prologue.h"; sourceTree = ""; }; + 935C557F1C136FEF0013166D /* glvideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glvideo.h; sourceTree = ""; }; + 935C55811C13702A0013166D /* glhudmodel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glhudmodel.h; sourceTree = ""; }; + 935C55821C13703F0013166D /* glnode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glnode.h; sourceTree = ""; }; + 935C55841C1370800013166D /* gltouchjoy_joy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gltouchjoy_joy.c; sourceTree = ""; }; + 935C55851C1370800013166D /* gltouchjoy_kpad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gltouchjoy_kpad.c; sourceTree = ""; }; + 935C55861C1370800013166D /* gltouchjoy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gltouchjoy.c; sourceTree = ""; }; + 935C55871C1370800013166D /* gltouchjoy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gltouchjoy.h; sourceTree = ""; }; + 935C55881C1370800013166D /* gltouchkbd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gltouchkbd.c; sourceTree = ""; }; + 935C55891C1370800013166D /* gltouchmenu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gltouchmenu.c; sourceTree = ""; }; + 935C559E1C1384240013166D /* darwin-cpu-glue.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "darwin-cpu-glue.S"; sourceTree = ""; }; + 935C55A01C1384400013166D /* cpu.S */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; name = cpu.S; path = arm/cpu.S; sourceTree = ""; }; + 935C55A71C1389370013166D /* jsmn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = jsmn.c; path = ../externals/jsmn/jsmn.c; sourceTree = ""; }; + 935C55A81C1389370013166D /* jsmn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jsmn.h; path = ../externals/jsmn/jsmn.h; sourceTree = ""; }; + 939C959C1C3B8E2100263E41 /* SolidColor.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = SolidColor.fsh; sourceTree = ""; }; + 939C959D1C3B8E2100263E41 /* SolidColor.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = SolidColor.vsh; sourceTree = ""; }; 93BC72541BF6F8E2005CDFCA /* glalert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = glalert.c; sourceTree = ""; }; 93BC72561BF6FF11005CDFCA /* playqueue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = playqueue.c; sourceTree = ""; }; /* End PBXFileReference section */ @@ -445,7 +594,6 @@ buildActionMask = 2147483647; files = ( 4AD4FEB01A52464F00F958EC /* OpenAL.framework in Frameworks */, - 4AD4FEB11A52464F00F958EC /* libz.1.1.3.dylib in Frameworks */, 4AD4FEB21A52464F00F958EC /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -455,17 +603,23 @@ buildActionMask = 2147483647; files = ( 779F566019EAF6D000A6F107 /* OpenAL.framework in Frameworks */, - 4ADC521A19E8CA4500186B36 /* libz.1.1.3.dylib in Frameworks */, 4ADC521B19E8CA4500186B36 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; + 4ECFC3A71C368EAB008E2633 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4ECFC3BF1C368ED3008E2633 /* GameController.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 773B3D09195688590085CE5F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 77C279701A1047DD000FE33F /* DDHidLib.framework in Frameworks */, - 773B3DCB1956903D0085CE5F /* libz.1.1.3.dylib in Frameworks */, 773B3D101956885A0085CE5F /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -474,7 +628,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 779DD845195BD9F900DF89E5 /* libz.1.1.3.dylib in Frameworks */, 779DD846195BD9F900DF89E5 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -484,40 +637,80 @@ buildActionMask = 2147483647; files = ( 779F568019EB0B9100A6F107 /* OpenAL.framework in Frameworks */, - 779F568119EB0B9100A6F107 /* libz.1.1.3.dylib in Frameworks */, 779F568219EB0B9100A6F107 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; + 935C55251C12BA5F0013166D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4EB4F8571C393F0E0072A15C /* OpenAL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 4ADC522F19E8D3F600186B36 /* disks */ = { + 4ADC522F19E8D3F600186B36 /* Documents */ = { isa = PBXGroup; children = ( + 4ECFC39B1C368620008E2633 /* flapple140.po */, + 4ECFC39C1C368620008E2633 /* mystery.dsk */, + 4ECFC39D1C368620008E2633 /* NSCT.dsk */, 4AFC170F1AAE9CC000B215FA /* testdisplay1.nib.gz */, + 4ECBEADD1C3432010046F537 /* speedtest.dsk */, + 4ECBEADE1C3432010046F537 /* testvm1.dsk */, 4AFC17101AAE9CC000B215FA /* testvm1.nib.gz */, - 4A6111A21A6A1DFC0035F7DE /* flapple140.po.gz */, 4A61119B1A6A1DE60035F7DE /* blank.po.gz */, 4ADC523019E8D3F600186B36 /* blank.dsk.gz */, 4ADC523119E8D3F600186B36 /* blank.nib.gz */, 4ADC523219E8D3F600186B36 /* etc.dsk.gz */, - 4ADC523319E8D3F600186B36 /* mystery.dsk.gz */, 4ADC523419E8D3F600186B36 /* README */, - 4ADC523519E8D3F600186B36 /* speedtest.dsk.gz */, 4ADC523619E8D3F600186B36 /* speedtest.txt */, 4ADC523719E8D3F600186B36 /* testdisplay1.dsk.gz */, 4ADC523819E8D3F600186B36 /* testvm1.dsk.gz */, ); - name = disks; - path = ../../disks; + name = Documents; + path = ../disks; + sourceTree = ""; + }; + 4ECFC3AB1C368EAB008E2633 /* Apple2etvOS */ = { + isa = PBXGroup; + children = ( + 4ECFC3AF1C368EAB008E2633 /* AppDelegate.h */, + 4ECFC3B01C368EAB008E2633 /* AppDelegate.m */, + 4ECFC3B21C368EAB008E2633 /* ViewController.h */, + 4ECFC3B31C368EAB008E2633 /* ViewController.m */, + 4ECFC3B51C368EAB008E2633 /* Main.storyboard */, + 4ECFC3B81C368EAC008E2633 /* Assets.xcassets */, + 4ECFC3BA1C368EAC008E2633 /* Info.plist */, + 4ECFC3AC1C368EAB008E2633 /* Supporting Files */, + ); + path = Apple2etvOS; + sourceTree = ""; + }; + 4ECFC3AC1C368EAB008E2633 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 4ECFC3AD1C368EAB008E2633 /* main.m */, + ); + name = "Supporting Files"; sourceTree = ""; }; 773B3D03195688590085CE5F = { isa = PBXGroup; children = ( - 773B3D151956885A0085CE5F /* Apple2Mac */, + 935C551B1C12B6400013166D /* main.m */, + 935C55211C12B6650013166D /* Apple2Mac-Prefix.pch */, 773B3D331956885A0085CE5F /* Apple2MacTests */, + 773B3D151956885A0085CE5F /* Apple2Mac */, + 935C55291C12BA5F0013166D /* Apple2iOS */, + 4ECFC3AB1C368EAB008E2633 /* Apple2etvOS */, + 773B3D431956897D0085CE5F /* Classes */, + 773B3D4519568A570085CE5F /* src */, + 935C55A51C1389000013166D /* externals */, + 4ADC522F19E8D3F600186B36 /* Documents */, 773B3D0E1956885A0085CE5F /* Frameworks */, 773B3D0D1956885A0085CE5F /* Products */, ); @@ -531,6 +724,8 @@ 4ADC522719E8CA4500186B36 /* Apple2MacTestVM.app */, 779F569119EB0B9100A6F107 /* Apple2MacTestDisplay.app */, 4AD4FEC31A52464F00F958EC /* Apple2MacTestDisk.app */, + 935C55281C12BA5F0013166D /* Apple2iOS.app */, + 4ECFC3AA1C368EAB008E2633 /* Apple2etvOS.app */, ); name = Products; sourceTree = ""; @@ -538,9 +733,10 @@ 773B3D0E1956885A0085CE5F /* Frameworks */ = { isa = PBXGroup; children = ( + 4EB4F8561C393F0E0072A15C /* OpenAL.framework */, + 4ECFC3BE1C368ED3008E2633 /* GameController.framework */, 77C279601A1047AE000FE33F /* DDHidLib.xcodeproj */, 779F565F19EAF6D000A6F107 /* OpenAL.framework */, - 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */, 773B3D0F1956885A0085CE5F /* Cocoa.framework */, 773B3D111956885A0085CE5F /* Other Frameworks */, ); @@ -560,34 +756,22 @@ 773B3D151956885A0085CE5F /* Apple2Mac */ = { isa = PBXGroup; children = ( - 4A69C17F1A33D6D7001579EF /* images */, - 4ADC522F19E8D3F600186B36 /* disks */, - 773B3D4519568A570085CE5F /* src */, - 773B3D431956897D0085CE5F /* Classes */, - 773B3D44195689910085CE5F /* Resources */, - 773B3D161956885A0085CE5F /* Supporting Files */, + 773B3D171956885A0085CE5F /* Apple2Mac-Info.plist */, + 4A2636F819FDEDB700DBFB00 /* Apple2Mac.help */, + 773B3D1E1956885A0085CE5F /* Credits.rtf */, + 773B3D181956885A0085CE5F /* InfoPlist.strings */, + 773B3D271956885A0085CE5F /* Images.xcassets */, + 773B3D241956885A0085CE5F /* MainMenu.xib */, + 4ADC51C919E8BEB700186B36 /* MainMenu-Test.xib */, ); path = Apple2Mac; sourceTree = ""; }; - 773B3D161956885A0085CE5F /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 773B3D171956885A0085CE5F /* Apple2Mac-Info.plist */, - 773B3D181956885A0085CE5F /* InfoPlist.strings */, - 773B3D1B1956885A0085CE5F /* main.m */, - 773B3D1D1956885A0085CE5F /* Apple2Mac-Prefix.pch */, - 773B3D1E1956885A0085CE5F /* Credits.rtf */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; 773B3D331956885A0085CE5F /* Apple2MacTests */ = { isa = PBXGroup; children = ( 779DD854195BDB1700DF89E5 /* CPUTestAppDelegate.m */, 779DD855195BDB1700DF89E5 /* CPUTestAppDelegate.h */, - 773B3D7919568A570085CE5F /* test */, 773B3D341956885A0085CE5F /* Supporting Files */, ); path = Apple2MacTests; @@ -608,65 +792,48 @@ 773B3D431956897D0085CE5F /* Classes */ = { isa = PBXGroup; children = ( - 773BC91419F2E6A900996893 /* EmulatorDiskController.h */, - 773BC91519F2E6A900996893 /* EmulatorDiskController.m */, - 77E1C0C219D7298F004344E0 /* EmulatorFullscreenWindow.m */, - 77E1C0C319D7298F004344E0 /* EmulatorFullscreenWindow.h */, - 77E1C0C019D7298F004344E0 /* EmulatorGLView.m */, - 77E1C0C119D7298F004344E0 /* EmulatorGLView.h */, - 77F80B421A2D95E300D45030 /* EmulatorJoystickCalibrationView.m */, - 77F80B431A2D95E300D45030 /* EmulatorJoystickCalibrationView.h */, - 77C279731A1048B4000FE33F /* EmulatorJoystickController.h */, - 77C279741A1048B4000FE33F /* EmulatorJoystickController.m */, - 773BC91719F2FD4500996893 /* EmulatorPrefsController.h */, - 773BC91819F2FD4500996893 /* EmulatorPrefsController.m */, - 77E1C0BE19D7298F004344E0 /* EmulatorWindowController.m */, - 77E1C0BF19D7298F004344E0 /* EmulatorWindowController.h */, - 4AC7A76B19ECC3FB00BCD457 /* EmulatorWindow.h */, - 4AC7A76C19ECC3FB00BCD457 /* EmulatorWindow.m */, + 935C54741C129C740013166D /* OSX */, + 935C55231C12B9CE0013166D /* iOS */, ); name = Classes; - sourceTree = ""; - }; - 773B3D44195689910085CE5F /* Resources */ = { - isa = PBXGroup; - children = ( - 4A2636F819FDEDB700DBFB00 /* Apple2Mac.help */, - 773B3D271956885A0085CE5F /* Images.xcassets */, - 773B3D241956885A0085CE5F /* MainMenu.xib */, - 4ADC51C919E8BEB700186B36 /* MainMenu-Test.xib */, - ); - name = Resources; + path = Apple2Mac; sourceTree = ""; }; 773B3D4519568A570085CE5F /* src */ = { isa = PBXGroup; children = ( + 4E4356E31C386AC500B71328 /* interface.h */, + 4E4356E41C386AC500B71328 /* memmngt.h */, + 935C55781C136F550013166D /* arm */, 779F564619EAF66E00A6F107 /* audio */, 773B3D5C19568A570085CE5F /* common.h */, 773B3D5D19568A570085CE5F /* cpu-supp.c */, 773B3D5E19568A570085CE5F /* cpu.h */, - 773B3D6019568A570085CE5F /* darwin-shim.c */, + 935C559E1C1384240013166D /* darwin-cpu-glue.S */, 773B3D6119568A570085CE5F /* darwin-shim.h */, - 773B3D6219568A570085CE5F /* disk.c */, + 773B3D6019568A570085CE5F /* darwin-shim.c */, 773B3D6319568A570085CE5F /* disk.h */, + 773B3D6219568A570085CE5F /* disk.c */, 773B3D6419568A570085CE5F /* display.c */, 773B3D6519568A570085CE5F /* font.c */, 773B3D6919568A570085CE5F /* glue.h */, 4A7EDC9D1AE092B80072E98A /* interface.c */, - 773B3D6C19568A570085CE5F /* joystick.c */, 773B3D6D19568A570085CE5F /* joystick.h */, - 773B3D6E19568A570085CE5F /* keys.c */, + 773B3D6C19568A570085CE5F /* joystick.c */, + 935C55711C136E6F0013166D /* json_parse.h */, + 935C55701C136E6F0013166D /* json_parse.c */, 773B3D6F19568A570085CE5F /* keys.h */, + 773B3D6E19568A570085CE5F /* keys.c */, 773B3D7019568A570085CE5F /* meta */, - 773B3D7519568A570085CE5F /* misc.c */, 773B3D7619568A570085CE5F /* misc.h */, + 773B3D7519568A570085CE5F /* misc.c */, 773B3D7719568A570085CE5F /* prefs.c */, 773B3D7819568A570085CE5F /* prefs.h */, 779DD826195764E200DF89E5 /* rom-shim.c */, 773B3D8719568A570085CE5F /* timing.c */, 773B3D8819568A570085CE5F /* timing.h */, 773B3D8919568A570085CE5F /* uthash.h */, + 773B3D7919568A570085CE5F /* test */, 773B3D8A19568A570085CE5F /* video */, 77E1C0A719D726E8004344E0 /* video_util */, 773B3D8D19568A570085CE5F /* vm.c */, @@ -675,7 +842,7 @@ 773B3D9619568A570085CE5F /* zlib-helpers.h */, ); name = src; - path = ../../src; + path = ../src; sourceTree = ""; }; 773B3D7019568A570085CE5F /* meta */ = { @@ -692,27 +859,34 @@ 773B3D7919568A570085CE5F /* test */ = { isa = PBXGroup; children = ( - 4AFC17091AAE9C3200B215FA /* sha1.c */, 773B3D7A19568A570085CE5F /* greatest.h */, - 773B3D7C19568A570085CE5F /* testcommon.c */, + 935C55771C136F260013166D /* sha1.h */, + 4AFC17091AAE9C3200B215FA /* sha1.c */, 773B3D7D19568A570085CE5F /* testcommon.h */, + 773B3D7C19568A570085CE5F /* testcommon.c */, 773B3D7E19568A570085CE5F /* testcpu.c */, 4AD4FEC91A52467D00F958EC /* testdisk.c */, 773B3D7F19568A570085CE5F /* testdisplay.c */, + 935C55751C136F0D0013166D /* testtrace.c */, 773B3D8619568A570085CE5F /* testvm.c */, ); - name = test; - path = ../../src/test; + path = test; sourceTree = ""; }; 773B3D8A19568A570085CE5F /* video */ = { isa = PBXGroup; children = ( + 935C55801C1370160013166D /* gltouch */, 779F562819E4FE9E00A6F107 /* Basic.fsh */, 779F562719E4FE9E00A6F107 /* Basic.vsh */, + 939C959C1C3B8E2100263E41 /* SolidColor.fsh */, + 939C959D1C3B8E2100263E41 /* SolidColor.vsh */, 93BC72541BF6F8E2005CDFCA /* glalert.c */, + 935C55811C13702A0013166D /* glhudmodel.h */, 4A7EDC911AE092680072E98A /* glhudmodel.c */, + 935C55821C13703F0013166D /* glnode.h */, 4A7EDC921AE092680072E98A /* glnode.c */, + 935C557F1C136FEF0013166D /* glvideo.h */, 77E1C0C719D736EB004344E0 /* glvideo.c */, 773B3D8B19568A570085CE5F /* video.h */, ); @@ -733,19 +907,20 @@ 779F564619EAF66E00A6F107 /* audio */ = { isa = PBXGroup; children = ( - 779F564719EAF66E00A6F107 /* alhelpers.c */, 779F564819EAF66E00A6F107 /* alhelpers.h */, - 779F564919EAF66E00A6F107 /* AY8910.c */, + 779F564719EAF66E00A6F107 /* alhelpers.c */, 779F564A19EAF66E00A6F107 /* AY8910.h */, - 779F564C19EAF66E00A6F107 /* mockingboard.c */, + 779F564919EAF66E00A6F107 /* AY8910.c */, 779F564D19EAF66E00A6F107 /* mockingboard.h */, + 779F564C19EAF66E00A6F107 /* mockingboard.c */, 779F564E19EAF66E00A6F107 /* peripherals.h */, + 935C55741C136ED40013166D /* playqueue.h */, 93BC72561BF6FF11005CDFCA /* playqueue.c */, 779F564F19EAF66E00A6F107 /* soundcore-openal.c */, - 779F565119EAF66E00A6F107 /* soundcore.c */, 779F565219EAF66E00A6F107 /* soundcore.h */, - 779F565319EAF66E00A6F107 /* speaker.c */, + 779F565119EAF66E00A6F107 /* soundcore.c */, 779F565419EAF66E00A6F107 /* speaker.h */, + 779F565319EAF66E00A6F107 /* speaker.c */, 779F565519EAF66E00A6F107 /* SSI263Phonemes.h */, ); path = audio; @@ -780,6 +955,101 @@ name = video_util; sourceTree = ""; }; + 935C54741C129C740013166D /* OSX */ = { + isa = PBXGroup; + children = ( + 935C55051C12B61D0013166D /* EmulatorDiskController.h */, + 935C55061C12B61D0013166D /* EmulatorDiskController.m */, + 935C55071C12B61D0013166D /* EmulatorFullscreenWindow.h */, + 935C55081C12B61D0013166D /* EmulatorFullscreenWindow.m */, + 935C55031C12B61D0013166D /* EmulatorGLView.h */, + 935C55041C12B61D0013166D /* EmulatorGLView.m */, + 935C55091C12B61D0013166D /* EmulatorJoystickCalibrationView.h */, + 935C550A1C12B61D0013166D /* EmulatorJoystickCalibrationView.m */, + 935C550B1C12B61D0013166D /* EmulatorJoystickController.h */, + 935C550C1C12B61D0013166D /* EmulatorJoystickController.m */, + 935C550D1C12B61D0013166D /* EmulatorPrefsController.h */, + 935C550E1C12B61D0013166D /* EmulatorPrefsController.m */, + 935C550F1C12B61D0013166D /* EmulatorWindow.h */, + 935C55101C12B61D0013166D /* EmulatorWindow.m */, + 935C55111C12B61D0013166D /* EmulatorWindowController.h */, + 935C55121C12B61D0013166D /* EmulatorWindowController.m */, + ); + name = OSX; + sourceTree = ""; + }; + 935C55231C12B9CE0013166D /* iOS */ = { + isa = PBXGroup; + children = ( + 4EEF0E881C3536A3001BEB67 /* disksViewController.h */, + 4EEF0E891C3536A3001BEB67 /* disksViewController.m */, + 935C55471C12BE510013166D /* AppDelegate.h */, + 935C55481C12BE510013166D /* AppDelegate.m */, + 93206C831C156BD300668153 /* A2IXPopupChoreographer.h */, + 93206C841C156BD300668153 /* A2IXPopupChoreographer.m */, + 935C55491C12BE510013166D /* EAGLView.h */, + 935C554A1C12BE510013166D /* EAGLView.m */, + 4E4E629F1C2C5B56002E324F /* iosPrefControllerViewController.h */, + 4E4E62A01C2C5B56002E324F /* iosPrefControllerViewController.m */, + 4E1733DC1C2C5E5D00CDF9DF /* AppleViewController.h */, + 4E1733DD1C2C5E5D00CDF9DF /* AppleViewController.m */, + ); + name = iOS; + sourceTree = ""; + }; + 935C55291C12BA5F0013166D /* Apple2iOS */ = { + isa = PBXGroup; + children = ( + 4EF7D04C1C38204C007E0ADD /* floppy.png */, + 93206C761C14E14000668153 /* Apple2iOS.strings */, + 935C55421C12BCFD0013166D /* Apple2iOS-Info.plist */, + 935C55361C12BA5F0013166D /* Assets.xcassets */, + 935C55441C12BE110013166D /* LaunchScreen.xib */, + 935C55331C12BA5F0013166D /* Main.storyboard */, + ); + path = Apple2iOS; + sourceTree = ""; + }; + 935C55781C136F550013166D /* arm */ = { + isa = PBXGroup; + children = ( + 935C55A01C1384400013166D /* cpu.S */, + 935C557C1C136FBD0013166D /* glue-prologue.h */, + 935C557A1C136F7E0013166D /* cpu-regs.h */, + ); + name = arm; + sourceTree = ""; + }; + 935C55801C1370160013166D /* gltouch */ = { + isa = PBXGroup; + children = ( + 935C55841C1370800013166D /* gltouchjoy_joy.c */, + 935C55851C1370800013166D /* gltouchjoy_kpad.c */, + 935C55861C1370800013166D /* gltouchjoy.c */, + 935C55871C1370800013166D /* gltouchjoy.h */, + 935C55881C1370800013166D /* gltouchkbd.c */, + 935C55891C1370800013166D /* gltouchmenu.c */, + ); + name = gltouch; + sourceTree = ""; + }; + 935C55A51C1389000013166D /* externals */ = { + isa = PBXGroup; + children = ( + 935C55A61C13890D0013166D /* jsmn */, + ); + name = externals; + sourceTree = ""; + }; + 935C55A61C13890D0013166D /* jsmn */ = { + isa = PBXGroup; + children = ( + 935C55A71C1389370013166D /* jsmn.c */, + 935C55A81C1389370013166D /* jsmn.h */, + ); + name = jsmn; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -821,6 +1091,23 @@ productReference = 4ADC522719E8CA4500186B36 /* Apple2MacTestVM.app */; productType = "com.apple.product-type.application"; }; + 4ECFC3A91C368EAB008E2633 /* Apple2etvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4ECFC3BB1C368EAC008E2633 /* Build configuration list for PBXNativeTarget "Apple2etvOS" */; + buildPhases = ( + 4ECFC3A61C368EAB008E2633 /* Sources */, + 4ECFC3A71C368EAB008E2633 /* Frameworks */, + 4ECFC3A81C368EAB008E2633 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Apple2etvOS; + productName = Apple2etvOS; + productReference = 4ECFC3AA1C368EAB008E2633 /* Apple2etvOS.app */; + productType = "com.apple.product-type.application"; + }; 773B3D0B195688590085CE5F /* Apple2Mac */ = { isa = PBXNativeTarget; buildConfigurationList = 773B3D3D1956885A0085CE5F /* Build configuration list for PBXNativeTarget "Apple2Mac" */; @@ -880,6 +1167,26 @@ productReference = 779F569119EB0B9100A6F107 /* Apple2MacTestDisplay.app */; productType = "com.apple.product-type.application"; }; + 935C55271C12BA5F0013166D /* Apple2iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 935C553C1C12BA5F0013166D /* Build configuration list for PBXNativeTarget "Apple2iOS" */; + buildPhases = ( + 935C558F1C1371020013166D /* ShellScript */, + 935C55241C12BA5F0013166D /* Sources */, + 935C55251C12BA5F0013166D /* Frameworks */, + 935C55901C13715A0013166D /* ShellScript */, + 935C55261C12BA5F0013166D /* Resources */, + 4E1733EF1C2E955700CDF9DF /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Apple2iOS; + productName = Apple2iOS; + productReference = 935C55281C12BA5F0013166D /* Apple2iOS.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -888,14 +1195,30 @@ attributes = { LastUpgradeCheck = 0510; ORGANIZATIONNAME = deadc0de.org; + TargetAttributes = { + 4ECFC3A91C368EAB008E2633 = { + CreatedOnToolsVersion = 7.2; + DevelopmentTeam = 774X2MBDTH; + SystemCapabilities = { + com.apple.GameControllers.appletvos = { + enabled = 1; + }; + }; + }; + 935C55271C12BA5F0013166D = { + CreatedOnToolsVersion = 7.1.1; + DevelopmentTeam = 2SR5BWLATN; + }; + }; }; buildConfigurationList = 773B3D07195688590085CE5F /* Build configuration list for PBXProject "Apple2Mac" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 6.3"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, + fr, ); mainGroup = 773B3D03195688590085CE5F; productRefGroup = 773B3D0D1956885A0085CE5F /* Products */; @@ -913,6 +1236,8 @@ 4AD4FE911A52464F00F958EC /* Apple2MacTestDisk */, 779F566119EB0B9100A6F107 /* Apple2MacTestDisplay */, 4ADC51FB19E8CA4500186B36 /* Apple2MacTestVM */, + 935C55271C12BA5F0013166D /* Apple2iOS */, + 4ECFC3A91C368EAB008E2633 /* Apple2etvOS */, ); }; /* End PBXProject section */ @@ -991,22 +1316,31 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4ECFC3A81C368EAB008E2633 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4ECFC3B91C368EAC008E2633 /* Assets.xcassets in Resources */, + 939C95A01C3B8E2100263E41 /* SolidColor.fsh in Resources */, + 4ECFC3B71C368EAB008E2633 /* Main.storyboard in Resources */, + 939C95A31C3B8E2100263E41 /* SolidColor.vsh in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 773B3D0A195688590085CE5F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4AFC17151AAE9CC000B215FA /* testvm1.nib.gz in Resources */, - 4A69C1801A33D6D7001579EF /* images in Resources */, - 773B3D1A1956885A0085CE5F /* InfoPlist.strings in Resources */, 773B3D281956885A0085CE5F /* Images.xcassets in Resources */, - 4A6111A31A6A1DFC0035F7DE /* flapple140.po.gz in Resources */, + 939C959E1C3B8E2100263E41 /* SolidColor.fsh in Resources */, + 773B3D1A1956885A0085CE5F /* InfoPlist.strings in Resources */, 773B3D201956885A0085CE5F /* Credits.rtf in Resources */, - 4A61119C1A6A1DE60035F7DE /* blank.po.gz in Resources */, 4A2636F919FDEDB700DBFB00 /* Apple2Mac.help in Resources */, - 4AFC17111AAE9CC000B215FA /* testdisplay1.nib.gz in Resources */, + 939C95A11C3B8E2100263E41 /* SolidColor.vsh in Resources */, + 779F562319DA59D600A6F107 /* MainMenu.xib in Resources */, 779F562919E4FE9E00A6F107 /* Basic.vsh in Resources */, 779F562A19E4FE9E00A6F107 /* Basic.fsh in Resources */, - 779F562319DA59D600A6F107 /* MainMenu.xib in Resources */, + 4EF7D04D1C38204C007E0ADD /* floppy.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1043,6 +1377,28 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 935C55261C12BA5F0013166D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 939C95A21C3B8E2100263E41 /* SolidColor.vsh in Resources */, + 935C55371C12BA5F0013166D /* Assets.xcassets in Resources */, + 939C959F1C3B8E2100263E41 /* SolidColor.fsh in Resources */, + 935C55431C12BCFD0013166D /* Apple2iOS-Info.plist in Resources */, + 935C55461C12BE110013166D /* LaunchScreen.xib in Resources */, + 935C55351C12BA5F0013166D /* Main.storyboard in Resources */, + 4ECFC3A01C368620008E2633 /* NSCT.dsk in Resources */, + 935C55921C1371AD0013166D /* Basic.vsh in Resources */, + 4ECBEAE01C3432010046F537 /* testvm1.dsk in Resources */, + 935C55911C1371AD0013166D /* Basic.fsh in Resources */, + 4ECFC39E1C368620008E2633 /* flapple140.po in Resources */, + 4ECBEADF1C3432010046F537 /* speedtest.dsk in Resources */, + 4EF7D04E1C38204C007E0ADD /* floppy.png in Resources */, + 93206C781C14E14000668153 /* Apple2iOS.strings in Resources */, + 4ECFC39F1C368620008E2633 /* mystery.dsk in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -1186,6 +1542,34 @@ shellScript = "/bin/rm -f \"$SRCROOT/../src/x86/glue.S\""; showEnvVarsInLog = 0; }; + 935C558F1C1371020013166D /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$SRCROOT/../src/arm/genglue\" \"$SRCROOT/../src/disk.c\" \"$SRCROOT/../src/misc.c\" \"$SRCROOT/../src/display.c\" \"$SRCROOT/../src/vm.c\" \"$SRCROOT/../src/audio/speaker.c\" \"$SRCROOT/../src/audio/mockingboard.c\" > \"$SRCROOT/../src/arm/glue.S\"\n\"$SRCROOT/../src/x86/genglue\" \"$SRCROOT/../src/disk.c\" \"$SRCROOT/../src/misc.c\" \"$SRCROOT/../src/display.c\" \"$SRCROOT/../src/vm.c\" \"$SRCROOT/../src/audio/speaker.c\" \"$SRCROOT/../src/audio/mockingboard.c\" > \"$SRCROOT/../src/x86/glue.S\""; + showEnvVarsInLog = 0; + }; + 935C55901C13715A0013166D /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/rm -f \"$SRCROOT/../src/arm/glue.S\""; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -1206,13 +1590,13 @@ 4AD4FE9D1A52464F00F958EC /* testcommon.c in Sources */, 4AD4FE9E1A52464F00F958EC /* misc.c in Sources */, 4AD4FE9F1A52464F00F958EC /* opcodes.c in Sources */, + 935C551F1C12B6460013166D /* main.m in Sources */, 4A7EDCA01AE092B80072E98A /* interface.c in Sources */, 4AD4FEA01A52464F00F958EC /* glvideo.c in Sources */, 4AD4FEA11A52464F00F958EC /* rom-shim.c in Sources */, 4AD4FEA21A52464F00F958EC /* zlib-helpers.c in Sources */, 4AD4FEA31A52464F00F958EC /* darwin-shim.c in Sources */, 4A7EDC9A1AE092680072E98A /* glnode.c in Sources */, - 4AD4FEA41A52464F00F958EC /* main.m in Sources */, 4AD4FECB1A52468700F958EC /* testdisk.c in Sources */, 4AD4FEA51A52464F00F958EC /* vectorUtil.c in Sources */, 4AD4FEA61A52464F00F958EC /* debug.l in Sources */, @@ -1244,13 +1628,13 @@ 4ADC520719E8CA4500186B36 /* testcommon.c in Sources */, 4ADC520819E8CA4500186B36 /* misc.c in Sources */, 4ADC520919E8CA4500186B36 /* opcodes.c in Sources */, + 935C551D1C12B6450013166D /* main.m in Sources */, 4A7EDCA21AE092B80072E98A /* interface.c in Sources */, 4ADC520A19E8CA4500186B36 /* glvideo.c in Sources */, 4ADC520B19E8CA4500186B36 /* rom-shim.c in Sources */, 4ADC520C19E8CA4500186B36 /* zlib-helpers.c in Sources */, 4ADC520D19E8CA4500186B36 /* darwin-shim.c in Sources */, 4A7EDC9C1AE092680072E98A /* glnode.c in Sources */, - 4ADC520E19E8CA4500186B36 /* main.m in Sources */, 4ADC520F19E8CA4500186B36 /* vectorUtil.c in Sources */, 4ADC521019E8CA4500186B36 /* debug.l in Sources */, 4ADC521119E8CA4500186B36 /* CPUTestAppDelegate.m in Sources */, @@ -1265,55 +1649,67 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4ECFC3A61C368EAB008E2633 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4ECFC3B41C368EAB008E2633 /* ViewController.m in Sources */, + 4ECFC3B11C368EAB008E2633 /* AppDelegate.m in Sources */, + 4ECFC3AE1C368EAB008E2633 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 773B3D08195688590085CE5F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 773B3DBF19568A570085CE5F /* cpu.S in Sources */, + 773B3DAF19568A570085CE5F /* misc.c in Sources */, + 779F565B19EAF66E00A6F107 /* soundcore-openal.c in Sources */, + 779F561C19D7929100A6F107 /* glvideo.c in Sources */, + 935C55151C12B61D0013166D /* EmulatorFullscreenWindow.m in Sources */, + 935C55AA1C138C2F0013166D /* jsmn.c in Sources */, 4A7EDC931AE092680072E98A /* glhudmodel.c in Sources */, 779F565D19EAF66E00A6F107 /* speaker.c in Sources */, - 779F565B19EAF66E00A6F107 /* soundcore-openal.c in Sources */, 773B3DA419568A570085CE5F /* display.c in Sources */, + 935C55171C12B61D0013166D /* EmulatorJoystickController.m in Sources */, 773B3DA319568A570085CE5F /* disk.c in Sources */, 773B3DAD19568A570085CE5F /* debugger.c in Sources */, 77E1C0B319D72700004344E0 /* vectorUtil.c in Sources */, - 4AC7A76D19ECC3FB00BCD457 /* EmulatorWindow.m in Sources */, - 77F80B441A2D95E300D45030 /* EmulatorJoystickCalibrationView.m in Sources */, 4A7EDC9E1AE092B80072E98A /* interface.c in Sources */, 773B3DAB19568A570085CE5F /* keys.c in Sources */, 773B3DBC19568A570085CE5F /* timing.c in Sources */, - 773B3DAF19568A570085CE5F /* misc.c in Sources */, - 77E1C0C419D7298F004344E0 /* EmulatorWindowController.m in Sources */, 773BC91A19F31E7B00996893 /* prefs.c in Sources */, 77E1C0B619D72700004344E0 /* matrixUtil.c in Sources */, - 77E1C0C519D7298F004344E0 /* EmulatorGLView.m in Sources */, 773B3DAE19568A570085CE5F /* opcodes.c in Sources */, - 773BC91619F2E6A900996893 /* EmulatorDiskController.m in Sources */, 779F565C19EAF66E00A6F107 /* soundcore.c in Sources */, + 935C55131C12B61D0013166D /* EmulatorGLView.m in Sources */, 779DD827195764E200DF89E5 /* rom-shim.c in Sources */, + 935C55191C12B61D0013166D /* EmulatorWindow.m in Sources */, 4A7EDC981AE092680072E98A /* glnode.c in Sources */, 773B3DC319568A570085CE5F /* zlib-helpers.c in Sources */, 77E1C0B719D72700004344E0 /* imageUtil.m in Sources */, 773B3DA219568A570085CE5F /* darwin-shim.c in Sources */, + 935C551C1C12B6400013166D /* main.m in Sources */, 77E1C0B519D72700004344E0 /* modelUtil.c in Sources */, 773B3DAC19568A570085CE5F /* debug.l in Sources */, + 935C55161C12B61D0013166D /* EmulatorJoystickCalibrationView.m in Sources */, 779F565919EAF66E00A6F107 /* AY8910.c in Sources */, - 77E1C0C619D7298F004344E0 /* EmulatorFullscreenWindow.m in Sources */, + 935C55181C12B61D0013166D /* EmulatorPrefsController.m in Sources */, 93BC72571BF6FF11005CDFCA /* playqueue.c in Sources */, - 773BC91919F2FD4500996893 /* EmulatorPrefsController.m in Sources */, 773B3DA519568A570085CE5F /* font.c in Sources */, 773B3DA019568A570085CE5F /* cpu-supp.c in Sources */, - 77C279751A1048B4000FE33F /* EmulatorJoystickController.m in Sources */, - 779F561C19D7929100A6F107 /* glvideo.c in Sources */, 779F565A19EAF66E00A6F107 /* mockingboard.c in Sources */, 77E1C0B419D72700004344E0 /* sourceUtil.c in Sources */, 779F565819EAF66E00A6F107 /* alhelpers.c in Sources */, 93BC72551BF6F8E2005CDFCA /* glalert.c in Sources */, + 935C55141C12B61D0013166D /* EmulatorDiskController.m in Sources */, 4AFC170A1AAE9C3200B215FA /* sha1.c in Sources */, + 935C551A1C12B61D0013166D /* EmulatorWindowController.m in Sources */, 773B3DBE19568A570085CE5F /* vm.c in Sources */, 773B3DC019568A570085CE5F /* darwin-glue.S in Sources */, - 773B3D1C1956885A0085CE5F /* main.m in Sources */, 773B3DAA19568A570085CE5F /* joystick.c in Sources */, + 935C55721C136E6F0013166D /* json_parse.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1334,13 +1730,13 @@ 779DD853195BDA3400DF89E5 /* testcommon.c in Sources */, 779DD836195BD9F900DF89E5 /* misc.c in Sources */, 779DD837195BD9F900DF89E5 /* opcodes.c in Sources */, + 935C55201C12B64A0013166D /* main.m in Sources */, 4A7EDC9F1AE092B80072E98A /* interface.c in Sources */, 4ADC51C619E8BD5200186B36 /* glvideo.c in Sources */, 779DD838195BD9F900DF89E5 /* rom-shim.c in Sources */, 779DD839195BD9F900DF89E5 /* zlib-helpers.c in Sources */, 779DD83A195BD9F900DF89E5 /* darwin-shim.c in Sources */, 4A7EDC991AE092680072E98A /* glnode.c in Sources */, - 4ADC51FA19E8C6EF00186B36 /* main.m in Sources */, 4ADC51C219E8BD3700186B36 /* vectorUtil.c in Sources */, 779DD83C195BD9F900DF89E5 /* debug.l in Sources */, 779DD856195BDB1700DF89E5 /* CPUTestAppDelegate.m in Sources */, @@ -1372,6 +1768,7 @@ 779F566C19EB0B9100A6F107 /* timing.c in Sources */, 779F566D19EB0B9100A6F107 /* testcommon.c in Sources */, 779F566E19EB0B9100A6F107 /* misc.c in Sources */, + 935C551E1C12B6450013166D /* main.m in Sources */, 4A7EDCA11AE092B80072E98A /* interface.c in Sources */, 779F566F19EB0B9100A6F107 /* opcodes.c in Sources */, 779F567019EB0B9100A6F107 /* glvideo.c in Sources */, @@ -1379,7 +1776,6 @@ 779F567219EB0B9100A6F107 /* zlib-helpers.c in Sources */, 4A7EDC9B1AE092680072E98A /* glnode.c in Sources */, 779F567319EB0B9100A6F107 /* darwin-shim.c in Sources */, - 779F567419EB0B9100A6F107 /* main.m in Sources */, 779F567519EB0B9100A6F107 /* vectorUtil.c in Sources */, 779F567619EB0B9100A6F107 /* debug.l in Sources */, 779F567719EB0B9100A6F107 /* CPUTestAppDelegate.m in Sources */, @@ -1393,6 +1789,60 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 935C55241C12BA5F0013166D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 935C559F1C1384240013166D /* darwin-cpu-glue.S in Sources */, + 935C55621C136E070013166D /* misc.c in Sources */, + 935C55691C136E070013166D /* glvideo.c in Sources */, + 935C558A1C1370800013166D /* gltouchjoy_joy.c in Sources */, + 93206C851C156BD300668153 /* A2IXPopupChoreographer.m in Sources */, + 935C558B1C1370800013166D /* gltouchjoy_kpad.c in Sources */, + 935C558C1C1370800013166D /* gltouchjoy.c in Sources */, + 935C55561C136DF40013166D /* soundcore.c in Sources */, + 935C55551C136DF40013166D /* soundcore-openal.c in Sources */, + 935C55611C136E070013166D /* opcodes.c in Sources */, + 935C55631C136E070013166D /* prefs.c in Sources */, + 935C55731C136E6F0013166D /* json_parse.c in Sources */, + 935C55641C136E070013166D /* rom-shim.c in Sources */, + 935C55651C136E070013166D /* timing.c in Sources */, + 935C55661C136E070013166D /* glalert.c in Sources */, + 935C55A91C1389370013166D /* jsmn.c in Sources */, + 935C55671C136E070013166D /* glhudmodel.c in Sources */, + 935C55681C136E070013166D /* glnode.c in Sources */, + 935C556A1C136E070013166D /* matrixUtil.c in Sources */, + 4EEF0E8A1C3536A3001BEB67 /* disksViewController.m in Sources */, + 935C556B1C136E070013166D /* modelUtil.c in Sources */, + 935C556C1C136E070013166D /* sourceUtil.c in Sources */, + 935C556D1C136E070013166D /* vectorUtil.c in Sources */, + 935C556E1C136E070013166D /* vm.c in Sources */, + 935C556F1C136E070013166D /* zlib-helpers.c in Sources */, + 935C558D1C1370800013166D /* gltouchkbd.c in Sources */, + 935C55511C136DF40013166D /* alhelpers.c in Sources */, + 935C55521C136DF40013166D /* AY8910.c in Sources */, + 935C55531C136DF40013166D /* mockingboard.c in Sources */, + 935C55541C136DF40013166D /* playqueue.c in Sources */, + 935C558E1C1370800013166D /* gltouchmenu.c in Sources */, + 935C55571C136DF40013166D /* speaker.c in Sources */, + 4E1733E41C2C5F7A00CDF9DF /* AppleViewController.m in Sources */, + 935C55581C136DF40013166D /* cpu-supp.c in Sources */, + 935C55591C136DF40013166D /* darwin-shim.c in Sources */, + 935C55601C136E070013166D /* debugger.c in Sources */, + 935C555A1C136DF40013166D /* disk.c in Sources */, + 935C555B1C136DF40013166D /* display.c in Sources */, + 935C555C1C136DF40013166D /* font.c in Sources */, + 935C555D1C136DF40013166D /* interface.c in Sources */, + 935C555E1C136DF40013166D /* joystick.c in Sources */, + 4E1733E31C2C5F7600CDF9DF /* iosPrefControllerViewController.m in Sources */, + 935C55A11C13887E0013166D /* sha1.c in Sources */, + 935C555F1C136DF40013166D /* keys.c in Sources */, + 935C554D1C12BE510013166D /* AppDelegate.m in Sources */, + 935C55A41C1388E30013166D /* main.m in Sources */, + 935C554E1C12BE510013166D /* EAGLView.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -1408,14 +1858,24 @@ isa = PBXVariantGroup; children = ( 4ADC51CA19E8BEB700186B36 /* Base */, + 4E4585FF1C29F393003E74A1 /* fr */, ); name = "MainMenu-Test.xib"; sourceTree = ""; }; + 4ECFC3B51C368EAB008E2633 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 4ECFC3B61C368EAB008E2633 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; 773B3D181956885A0085CE5F /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 773B3D191956885A0085CE5F /* en */, + 4E4586011C29F399003E74A1 /* fr */, ); name = InfoPlist.strings; sourceTree = ""; @@ -1424,6 +1884,7 @@ isa = PBXVariantGroup; children = ( 773B3D1F1956885A0085CE5F /* en */, + 4E4586001C29F399003E74A1 /* fr */, ); name = Credits.rtf; sourceTree = ""; @@ -1431,7 +1892,9 @@ 773B3D241956885A0085CE5F /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( - 773B3D251956885A0085CE5F /* Base */, + 4E4585F91C29F2B9003E74A1 /* en */, + 4E4586021C29F399003E74A1 /* fr */, + 4E1ACFE71C2B12F900C755BB /* Base */, ); name = MainMenu.xib; sourceTree = ""; @@ -1440,10 +1903,39 @@ isa = PBXVariantGroup; children = ( 773B3D371956885A0085CE5F /* en */, + 4E4586051C29F399003E74A1 /* fr */, ); name = InfoPlist.strings; sourceTree = ""; }; + 93206C761C14E14000668153 /* Apple2iOS.strings */ = { + isa = PBXVariantGroup; + children = ( + 93206C771C14E14000668153 /* Base */, + 4E4586061C29F39A003E74A1 /* fr */, + ); + name = Apple2iOS.strings; + sourceTree = ""; + }; + 935C55331C12BA5F0013166D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 935C55341C12BA5F0013166D /* Base */, + 4E4586041C29F399003E74A1 /* fr */, + 4E1ACFE61C2B0F3600C755BB /* en */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 935C55441C12BE110013166D /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 935C55451C12BE110013166D /* Base */, + 4E4586031C29F399003E74A1 /* fr */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -1565,6 +2057,47 @@ }; name = Release; }; + 4ECFC3BC1C368EAC008E2633 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_WARN_UNREACHABLE_CODE = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = Apple2etvOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = bxo.Apple2etvOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.1; + }; + name = Debug; + }; + 4ECFC3BD1C368EAC008E2633 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_WARN_UNREACHABLE_CODE = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = Apple2etvOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = bxo.Apple2etvOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.1; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; 773B3D3B1956885A0085CE5F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1639,11 +2172,12 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; + ARCHS = "$(ARCHS_STANDARD)"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_OBJC_ARC = NO; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Apple2Mac/Apple2Mac-Prefix.pch"; + GCC_PREFIX_HEADER = "Apple2Mac-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "APPLE2IX=1", "DEBUGGER=1", @@ -1656,6 +2190,9 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, ); INFOPLIST_FILE = "Apple2Mac/Apple2Mac-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.8; + OTHER_LDFLAGS = "-lz"; + PRODUCT_BUNDLE_IDENTIFIER = bxo.Apple2Mac; PRODUCT_NAME = "$(TARGET_NAME)"; USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../src"; WRAPPER_EXTENSION = app; @@ -1666,11 +2203,12 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; + ARCHS = "$(ARCHS_STANDARD)"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_OBJC_ARC = NO; COMBINE_HIDPI_IMAGES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Apple2Mac/Apple2Mac-Prefix.pch"; + GCC_PREFIX_HEADER = "Apple2Mac-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "NDEBUG=1", "APPLE2IX=1", @@ -1684,6 +2222,9 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, ); INFOPLIST_FILE = "Apple2Mac/Apple2Mac-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.8; + OTHER_LDFLAGS = "-lz"; + PRODUCT_BUNDLE_IDENTIFIER = bxo.Apple2Mac; PRODUCT_NAME = "$(TARGET_NAME)"; USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../src"; WRAPPER_EXTENSION = app; @@ -1804,6 +2345,82 @@ }; name = Release; }; + 935C553D1C12BA5F0013166D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + ARCHS = armv7; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Apple2Mac-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "APPLE2IX=1", + "INTERFACE_TOUCH=1", + "MOBILE_DEVICE=1", + "DEBUGGER=1", + "VIDEO_OPENGL=1", + "AUDIO_ENABLED=1", + ); + INFOPLIST_FILE = "$(SRCROOT)/Apple2iOS/Apple2iOS-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = "-lz"; + PRODUCT_BUNDLE_IDENTIFIER = com.deadc0de.Apple2iOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../src"; + VALID_ARCHS = "armv7 armv7s"; + }; + name = Debug; + }; + 935C553E1C12BA5F0013166D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + ARCHS = armv7; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Apple2Mac-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "NDEBUG=1", + "APPLE2IX=1", + "INTERFACE_TOUCH=1", + "MOBILE_DEVICE=1", + "DEBUGGER=1", + "VIDEO_OPENGL=1", + "AUDIO_ENABLED=1", + ); + INFOPLIST_FILE = "$(SRCROOT)/Apple2iOS/Apple2iOS-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = "-lz"; + PRODUCT_BUNDLE_IDENTIFIER = com.deadc0de.Apple2iOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../src"; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "armv7 armv7s"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1825,6 +2442,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 4ECFC3BB1C368EAC008E2633 /* Build configuration list for PBXNativeTarget "Apple2etvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4ECFC3BC1C368EAC008E2633 /* Debug */, + 4ECFC3BD1C368EAC008E2633 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 773B3D07195688590085CE5F /* Build configuration list for PBXProject "Apple2Mac" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1861,6 +2487,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 935C553C1C12BA5F0013166D /* Build configuration list for PBXNativeTarget "Apple2iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 935C553D1C12BA5F0013166D /* Debug */, + 935C553E1C12BA5F0013166D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 773B3D04195688590085CE5F /* Project object */; diff --git a/Apple2Mac/Apple2Mac/Apple2Mac-Info.plist b/Apple2Mac/Apple2Mac/Apple2Mac-Info.plist index 30cedae2..32029024 100644 --- a/Apple2Mac/Apple2Mac/Apple2Mac-Info.plist +++ b/Apple2Mac/Apple2Mac/Apple2Mac-Info.plist @@ -6,10 +6,14 @@ en CFBundleExecutable ${EXECUTABLE_NAME} + CFBundleHelpBookFolder + Apple2Mac.help + CFBundleHelpBookName + org.deadc0de.Apple2Mac.help CFBundleIconFile CFBundleIdentifier - org.deadc0de.Apple2Mac + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -22,10 +26,6 @@ ???? CFBundleVersion 1 - CFBundleHelpBookFolder - Apple2Mac.help - CFBundleHelpBookName - org.deadc0de.Apple2Mac.help LSApplicationCategoryType public.app-category.education LSMinimumSystemVersion diff --git a/Apple2Mac/Apple2Mac/AppleViewController.h b/Apple2Mac/Apple2Mac/AppleViewController.h new file mode 100644 index 00000000..71005b50 --- /dev/null +++ b/Apple2Mac/Apple2Mac/AppleViewController.h @@ -0,0 +1,23 @@ +// +// AppleViewController.h +// Apple2Mac +// +// Created by Jerome Vernet on 24/12/2015. +// Copyright © 2015 deadc0de.org. All rights reserved. +// + +#import +#import "iosPrefControllerViewController.h" + +@interface AppleViewController : UIViewController +@property (nonatomic, assign) BOOL paused; +@property (assign) IBOutlet UIToolbar *mainToolBar; +@property (assign) IBOutlet iosPrefControllerViewController *viewPrefs; + +-(IBAction)rebootItemSelected:(id)sender; +-(IBAction)prefsItemSelected:(id)sender; +-(IBAction)toggleCPUSpeedItemSelected:(id)sender; +-(IBAction)togglePauseItemSelected:(id)sender; +-(IBAction)diskInsert:(id)sender; + +@end diff --git a/Apple2Mac/Apple2Mac/AppleViewController.m b/Apple2Mac/Apple2Mac/AppleViewController.m new file mode 100644 index 00000000..6dc86c85 --- /dev/null +++ b/Apple2Mac/Apple2Mac/AppleViewController.m @@ -0,0 +1,120 @@ +// +// AppleViewController.m +// Apple2Mac +// +// Created by Jerome Vernet on 24/12/2015. +// Copyright © 2015 deadc0de.org. All rights reserved. +// + +#import "AppleViewController.h" +#import "common.h" +#import "modelUtil.h" + +@interface AppleViewController () + +@end + +@implementation AppleViewController + +@synthesize paused = _paused; + +- (void)viewDidLoad { + [super viewDidLoad]; + // [self mainToolBar ]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + + +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. + cpu_pause(); +} + + +- (IBAction)unwindForSegue:(UIStoryboardSegue*)sender +{ + cpu_resume(); +} +- (IBAction)upSwipe:(id)sender +{ + self.mainToolBar.hidden=NO; +} + +- (IBAction)diskInsert:(id)sender +{ + NSLog(@"LISTING ALL FILES FOUND"); + + int Count; + NSString *path; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Disks"]; + NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL]; + for (Count = 0; Count < (int)[directoryContent count]; Count++) + { + NSLog(@"File %d: %@", (Count + 1), [directoryContent objectAtIndex:Count]); + } +} + +-(IBAction)rebootItemSelected:(id)sender{ + cpu65_reboot(); +} + +-(IBAction)prefsItemSelected:(id)sender{ + cpu_pause(); + //[self.viewPrefs ]; + //pause + //show pref windows + cpu_resume(); +} + +- (IBAction)toggleCPUSpeedItemSelected:(id)sender +{ + cpu_pause(); + timing_toggleCPUSpeed(); + if (video_backend && video_backend->animation_showCPUSpeed) + { + video_backend->animation_showCPUSpeed(); + } + cpu_resume(); +} + +- (IBAction)togglePauseItemSelected:(id)sender +{ + NSAssert(pthread_main_np(), @"Pause emulation called from non-main thread"); + self.paused = !_paused; +} +- (void)setPaused:(BOOL)paused +{ + if (_paused == paused) + { + return; + } + + _paused = paused; + if (paused) + { + cpu_pause(); + } + else + { + cpu_resume(); + } + if (video_backend && video_backend->animation_showPaused) + { + video_backend->animation_showPaused(); + } +} + +- (void)dealloc { + [super dealloc]; +} +@end diff --git a/Apple2Mac/Apple2Mac/Base.lproj/MainMenu-Test.xib b/Apple2Mac/Apple2Mac/Base.lproj/MainMenu-Test.xib index 646d5d84..a784c1ca 100644 --- a/Apple2Mac/Apple2Mac/Base.lproj/MainMenu-Test.xib +++ b/Apple2Mac/Apple2Mac/Base.lproj/MainMenu-Test.xib @@ -1,8 +1,8 @@ - + - + @@ -88,7 +88,7 @@ - + diff --git a/Apple2Mac/Apple2Mac/Base.lproj/MainMenu.xib b/Apple2Mac/Apple2Mac/Base.lproj/MainMenu.xib index 9062ae18..01a83254 100644 --- a/Apple2Mac/Apple2Mac/Base.lproj/MainMenu.xib +++ b/Apple2Mac/Apple2Mac/Base.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - + - + @@ -23,27 +23,6 @@ - - -CA - - - - - - - - - - - - - - - - - - @@ -52,21 +31,6 @@ CA - - - - - - - - - - - - - - - @@ -103,6 +67,299 @@ CA + + + + + + +CA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -118,21 +375,50 @@ CA - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -238,7 +524,7 @@ CA - + @@ -266,7 +552,7 @@ CA - + @@ -365,7 +651,7 @@ DQ - + @@ -729,5 +1015,15 @@ DQ + + + + + + + + + + diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/Contents.json b/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/Contents.json new file mode 100644 index 00000000..f17d33b1 --- /dev/null +++ b/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "cpu32.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "cpu64.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "cpu128.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu128.png b/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu128.png new file mode 100644 index 00000000..a010efe4 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu128.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu32.png b/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu32.png new file mode 100644 index 00000000..30ebabf0 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu32.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu64.png b/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu64.png new file mode 100644 index 00000000..c3720234 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/CPU.imageset/cpu64.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Contents.json b/Apple2Mac/Apple2Mac/Images.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2Mac/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/Contents.json b/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/Contents.json new file mode 100644 index 00000000..07d8e123 --- /dev/null +++ b/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "floppy32.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "floppy64.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "floppy128.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy128.png b/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy128.png new file mode 100644 index 00000000..3303f163 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy128.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy32.png b/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy32.png new file mode 100644 index 00000000..53800364 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy32.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy64.png b/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy64.png new file mode 100644 index 00000000..87039746 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Disks.imageset/floppy64.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/Contents.json b/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/Contents.json new file mode 100644 index 00000000..18d30f7c --- /dev/null +++ b/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "fullscreen32.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "fullscreen64.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "fullscreen128.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen128.png b/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen128.png new file mode 100644 index 00000000..47363b48 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen128.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen32.png b/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen32.png new file mode 100644 index 00000000..976b7f9a Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen32.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen64.png b/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen64.png new file mode 100644 index 00000000..e9437dd3 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Fullscreen.imageset/fullscreen64.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/Contents.json b/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/Contents.json new file mode 100644 index 00000000..a460a432 --- /dev/null +++ b/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "pref32.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "pref64.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "pref128.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref128.png b/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref128.png new file mode 100644 index 00000000..ad0be8a3 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref128.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref32.png b/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref32.png new file mode 100644 index 00000000..22427b69 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref32.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref64.png b/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref64.png new file mode 100644 index 00000000..734b7c17 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Prefs.imageset/pref64.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Reboot.imageset/Contents.json b/Apple2Mac/Apple2Mac/Images.xcassets/Reboot.imageset/Contents.json new file mode 100644 index 00000000..d710d3f6 --- /dev/null +++ b/Apple2Mac/Apple2Mac/Images.xcassets/Reboot.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reboot32.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Reboot.imageset/reboot32.png b/Apple2Mac/Apple2Mac/Images.xcassets/Reboot.imageset/reboot32.png new file mode 100644 index 00000000..fdb8fb84 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Reboot.imageset/reboot32.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/Contents.json b/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/Contents.json new file mode 100644 index 00000000..b0f79368 --- /dev/null +++ b/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "play32.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "play64.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "play128.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play128.png b/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play128.png new file mode 100644 index 00000000..254a59c5 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play128.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play32.png b/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play32.png new file mode 100644 index 00000000..986002ad Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play32.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play64.png b/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play64.png new file mode 100644 index 00000000..cb475b52 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/play64.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/Contents.json b/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/Contents.json new file mode 100644 index 00000000..bdd792f7 --- /dev/null +++ b/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "stop32.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "stop64.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "stop128.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop128.png b/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop128.png new file mode 100644 index 00000000..413b5617 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop128.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop32.png b/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop32.png new file mode 100644 index 00000000..3f1d7c03 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop32.png differ diff --git a/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop64.png b/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop64.png new file mode 100644 index 00000000..b2078618 Binary files /dev/null and b/Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/stop64.png differ diff --git a/Apple2Mac/Apple2Mac/disksViewController.h b/Apple2Mac/Apple2Mac/disksViewController.h new file mode 100644 index 00000000..46ae3f40 --- /dev/null +++ b/Apple2Mac/Apple2Mac/disksViewController.h @@ -0,0 +1,19 @@ +// +// disksViewController.h +// Apple2Mac +// +// Created by Jerome Vernet on 31/12/2015. +// Copyright © 2015 deadc0de.org. All rights reserved. +// + +#import + +@interface disksViewController : UIViewController +@property (retain, nonatomic) IBOutlet UIPickerView *disk1Picker; +@property (retain, nonatomic) IBOutlet UIPickerView *disk2Picker; +@property (retain, nonatomic) IBOutlet UISwitch *diskAProtection; +@property (retain, nonatomic) IBOutlet UISwitch *diskBProtection; + +@property (strong,nonatomic) NSArray *_disks; +@property (retain,nonatomic) NSString *path; +@end diff --git a/Apple2Mac/Apple2Mac/disksViewController.m b/Apple2Mac/Apple2Mac/disksViewController.m new file mode 100644 index 00000000..1c2e52ec --- /dev/null +++ b/Apple2Mac/Apple2Mac/disksViewController.m @@ -0,0 +1,93 @@ +// +// disksViewController.m +// Apple2Mac +// +// Created by Jerome Vernet on 31/12/2015. +// Copyright © 2015 deadc0de.org. All rights reserved. +// + +#import "disksViewController.h" +#import "common.h" + +@implementation disksViewController + + + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + + + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + //self.path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Disks"]; + self.path = [paths objectAtIndex:0]; + NSLog(@"Path:%@",self.path); + self._disks=[[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.path error:NULL]; + + // Connect data + self.disk1Picker.dataSource = self; + self.disk1Picker.delegate = self; + self.disk2Picker.dataSource = self; + self.disk2Picker.delegate = self; +} + +// The number of columns of data +- (int)numberOfComponentsInPickerView:(UIPickerView *)pickerView +{ + return 1; +} + +// The number of rows of data +- (int)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component +{ + return self._disks.count; + //_pickerData.cout; +} + +// The data to return for the row and component (column) that's being passed in +- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component +{ + return [self._disks objectAtIndex:row]; +} + +// Catpure the picker view selection +- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component +{ + // This method is triggered whenever the user makes a change to the picker selection. + // The parameter named row and component represents what was selected. + int drive=0; + BOOL ro=YES; + + if(pickerView==self.disk1Picker) + { + drive=0; + ro=self.diskAProtection.on; + } + if(pickerView==self.disk2Picker) + { + drive=1; + ro=self.diskBProtection.on; + } + + NSLog(@"Selected Row %d %@ %c", row,(NSString*)[self._disks objectAtIndex:row],ro); + disk6_eject(drive); + const char *errMsg = disk6_insert(drive, [[self.path stringByAppendingPathComponent:[self._disks objectAtIndex:row]] UTF8String], ro); +} + +- (IBAction)unwindToMainViewController:(UIStoryboardSegue*)sender +{ } + +-(IBAction)goodbye:(id)sender +{ + [self dismissViewControllerAnimated:YES completion:nil]; + cpu_resume(); +} + +- (void)dealloc { + [_diskAProtection release]; + [_diskBProtection release]; + [super dealloc]; +} +@end + diff --git a/Apple2Mac/Apple2Mac/en.lproj/MainMenu.xib b/Apple2Mac/Apple2Mac/en.lproj/MainMenu.xib new file mode 100644 index 00000000..e47c8690 --- /dev/null +++ b/Apple2Mac/Apple2Mac/en.lproj/MainMenu.xib @@ -0,0 +1,1029 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +CA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "Clamp Beyond Radius" setting is recommended for gamepad devices (not traditional joysticks) which cannot generate values in the extreme corners. + + + + Clamp Beyond Radius setting is recommended for gamepad devices (not traditional joysticks) which cannot generate values in the extreme corners. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Apple2Mac/Apple2Mac/fr.lproj/Credits.rtf b/Apple2Mac/Apple2Mac/fr.lproj/Credits.rtf new file mode 100644 index 00000000..221cc8d9 --- /dev/null +++ b/Apple2Mac/Apple2Mac/fr.lproj/Credits.rtf @@ -0,0 +1,29 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf210 +{\fonttbl\f0\fnil\fcharset0 Menlo-Bold;\f1\fnil\fcharset0 Menlo-Regular;\f2\fnil\fcharset0 Menlo-Italic; +} +{\colortbl;\red255\green255\blue255;} +\vieww9600\viewh8400\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl216\slmult1\qc + +\f0\b\fs24 \cf0 Authors\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl216\slmult1\pardirnatural\qc + +\f1\b0 \cf0 Aaron Culliney\ +and other contributors\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl120\slmult1\pardirnatural\qc +\cf0 \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl216\slmult1\pardirnatural\qc + +\f0\b \cf0 Web Resources +\f1\b0 \ + +\f2\i ftp.apple.asimov.net +\f1\i0 and elsewhere\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl120\slmult1\pardirnatural\qc +\cf0 \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl216\slmult1\pardirnatural\qc + +\f0\b \cf0 Special thanks to +\f1\b0 \ +Tom Charlesworth\ +and the AppleWin project} diff --git a/Apple2Mac/Apple2Mac/fr.lproj/InfoPlist.strings b/Apple2Mac/Apple2Mac/fr.lproj/InfoPlist.strings new file mode 100644 index 00000000..477b28ff --- /dev/null +++ b/Apple2Mac/Apple2Mac/fr.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Apple2Mac/Apple2Mac/fr.lproj/MainMenu-Test.strings b/Apple2Mac/Apple2Mac/fr.lproj/MainMenu-Test.strings new file mode 100644 index 00000000..17e0e231 --- /dev/null +++ b/Apple2Mac/Apple2Mac/fr.lproj/MainMenu-Test.strings @@ -0,0 +1,45 @@ + +/* Class = "NSMenu"; title = "AMainMenu"; ObjectID = "29"; */ +"29.title" = "AMainMenu"; + +/* Class = "NSMenuItem"; title = "Apple2Mac"; ObjectID = "56"; */ +"56.title" = "Apple2Mac"; + +/* Class = "NSMenu"; title = "Apple2Mac"; ObjectID = "57"; */ +"57.title" = "Apple2Mac"; + +/* Class = "NSMenuItem"; title = "About Apple2Mac"; ObjectID = "58"; */ +"58.title" = "About Apple2Mac"; + +/* Class = "NSMenuItem"; title = "Preferences…"; ObjectID = "129"; */ +"129.title" = "Preferences…"; + +/* Class = "NSMenu"; title = "Services"; ObjectID = "130"; */ +"130.title" = "Services"; + +/* Class = "NSMenuItem"; title = "Services"; ObjectID = "131"; */ +"131.title" = "Services"; + +/* Class = "NSMenuItem"; title = "Hide Apple2Mac"; ObjectID = "134"; */ +"134.title" = "Hide Apple2Mac"; + +/* Class = "NSMenuItem"; title = "Quit Apple2Mac"; ObjectID = "136"; */ +"136.title" = "Quit Apple2Mac"; + +/* Class = "NSMenuItem"; title = "Hide Others"; ObjectID = "145"; */ +"145.title" = "Hide Others"; + +/* Class = "NSMenuItem"; title = "Show All"; ObjectID = "150"; */ +"150.title" = "Show All"; + +/* Class = "NSMenuItem"; title = "Help"; ObjectID = "490"; */ +"490.title" = "Help"; + +/* Class = "NSMenu"; title = "Help"; ObjectID = "491"; */ +"491.title" = "Help"; + +/* Class = "NSMenuItem"; title = "Apple2Mac Help"; ObjectID = "492"; */ +"492.title" = "Apple2Mac Help"; + +/* Class = "NSWindow"; title = "Window"; ObjectID = "HyN-la-Rec"; */ +"HyN-la-Rec.title" = "Window"; diff --git a/Apple2Mac/Apple2Mac/fr.lproj/MainMenu.xib b/Apple2Mac/Apple2Mac/fr.lproj/MainMenu.xib new file mode 100644 index 00000000..caa2f124 --- /dev/null +++ b/Apple2Mac/Apple2Mac/fr.lproj/MainMenu.xib @@ -0,0 +1,1062 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +CA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "Clamp Beyond Radius" setting is recommended for gamepad devices (not traditional joysticks) which cannot generate values in the extreme corners. + + + + Clamp Beyond Radius setting is recommended for gamepad devices (not traditional joysticks) which cannot generate values in the extreme corners. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Apple2Mac/Apple2Mac/iosPrefControllerViewController.h b/Apple2Mac/Apple2Mac/iosPrefControllerViewController.h new file mode 100644 index 00000000..eb380e39 --- /dev/null +++ b/Apple2Mac/Apple2Mac/iosPrefControllerViewController.h @@ -0,0 +1,45 @@ +// +// iosPrefControllerViewController.h +// Apple2Mac +// +// Created by Jerome Vernet on 24/12/2015. +// Copyright © 2015 deadc0de.org. All rights reserved. +// + +#import + +#define kApple2SavedPrefs @"kApple2SavedPrefs" +#define kApple2CPUSpeed @"kApple2CPUSpeed" +#define kApple2CPUSpeedIsMax @"kApple2CPUSpeedIsMax" +#define kApple2AltSpeed @"kApple2AltSpeed" +#define kApple2AltSpeedIsMax @"kApple2AltSpeedIsMax" +#define kApple2SoundcardConfig @"kApple2SoundcardConfig" +#define kApple2ColorConfig @"kApple2ColorConfig" +#define kApple2JoystickConfig @"kApple2JoystickConfig" +#define kApple2JoystickAutoRecenter @"kApple2JoystickAutoRecenter" +#define kApple2JoystickClipToRadius @"kApple2JoystickClipToRadius" +#define kApple2PrefStartupDiskA @"kApple2PrefStartupDiskA" +#define kApple2PrefStartupDiskAProtected @"kApple2PrefStartupDiskAProtected" +#define kApple2PrefStartupDiskB @"kApple2PrefStartupDiskB" +#define kApple2PrefStartupDiskBProtected @"kApple2PrefStartupDiskBProtected" +#define kApple2JoystickStep @"kApple2JoystickStep" + + +@interface iosPrefControllerViewController : UIViewController + +@property (retain, nonatomic) IBOutlet UIPickerView *videoModePicker; +@property (retain, nonatomic) IBOutlet UISlider *cpuSlider; +@property (retain, nonatomic) IBOutlet UISlider *altSlider; +@property (retain, nonatomic) IBOutlet UILabel *cpuSliderLabel; +@property (retain, nonatomic) IBOutlet UILabel *altSliderLabel; +@property (retain, nonatomic) IBOutlet UISwitch *cpuMaxChoice; +@property (retain, nonatomic) IBOutlet UISwitch *altMaxChoice; + +@property (strong,nonatomic) NSArray *_videoMode; + + +@end + + + + diff --git a/Apple2Mac/Apple2Mac/iosPrefControllerViewController.m b/Apple2Mac/Apple2Mac/iosPrefControllerViewController.m new file mode 100644 index 00000000..4305bcf2 --- /dev/null +++ b/Apple2Mac/Apple2Mac/iosPrefControllerViewController.m @@ -0,0 +1,230 @@ +// +// iosPrefControllerViewController.m +// Apple2Mac +// +// Created by Jerome Vernet on 24/12/2015. +// Copyright © 2015 deadc0de.org. All rights reserved. +// + +#import "iosPrefControllerViewController.h" + + +#import "common.h" +#import "modelUtil.h" + + +@implementation iosPrefControllerViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self._videoMode = [[NSArray alloc] initWithObjects:@"Mono",@"Color", nil]; + + // Connect data + self.videoModePicker.dataSource = self; + self.videoModePicker.delegate = self; + + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + BOOL firstTime = ![defaults boolForKey:kApple2SavedPrefs]; + if (firstTime) + { + [defaults setBool:YES forKey:kApple2SavedPrefs]; + [defaults setDouble:1.0 forKey:kApple2CPUSpeed]; + [defaults setDouble:CPU_SCALE_SLOWEST forKey:kApple2AltSpeed]; + [defaults setBool:NO forKey:kApple2CPUSpeedIsMax]; + [defaults setBool:NO forKey:kApple2AltSpeedIsMax]; + [defaults setInteger:COLOR_INTERP forKey:kApple2ColorConfig]; + // [defaults setInteger:JOY_KPAD forKey:kApple2JoystickConfig]; + [defaults setBool:YES forKey:kApple2JoystickAutoRecenter]; + [defaults removeObjectForKey:kApple2PrefStartupDiskA]; + [defaults removeObjectForKey:kApple2PrefStartupDiskB]; + } + + cpu_scale_factor = [defaults doubleForKey:kApple2CPUSpeed]; + [self.cpuSlider setValue:cpu_scale_factor animated:NO]; + self.cpuSliderLabel.text=[NSString stringWithFormat:@"%.0f%%", cpu_scale_factor*100]; + if ([defaults boolForKey:kApple2CPUSpeedIsMax]) + { + cpu_scale_factor = CPU_SCALE_FASTEST; + [self.cpuMaxChoice setOn:YES]; + [self.cpuSlider setEnabled:NO]; + } + else + { + [self.cpuMaxChoice setOn:NO]; + [self.cpuSlider setEnabled:YES]; + } + + cpu_altscale_factor = [defaults doubleForKey:kApple2AltSpeed]; + [self.altSlider setValue:cpu_altscale_factor]; + self.altSliderLabel.text = [NSString stringWithFormat:@"%.0f%%", cpu_altscale_factor*100]; + if ([defaults boolForKey:kApple2AltSpeedIsMax]) + { + cpu_altscale_factor = CPU_SCALE_FASTEST; + [self.altMaxChoice setOn:YES]; + [self.altSlider setEnabled:NO]; + } + else + { + [self.altMaxChoice setOn:NO]; + [self.altSlider setEnabled:YES]; + } + + NSInteger mode = [defaults integerForKey:kApple2ColorConfig]; + if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) ) + { + mode = COLOR_NONE; + } + //[self.videoModePicker d:mode]; + color_mode = (color_mode_t)mode; + + mode = [defaults integerForKey:kApple2JoystickConfig]; + if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) ) + { + mode = JOY_PCJOY; + } + joy_mode = (joystick_mode_t)mode; +// [self.joystickChoice selectItemAtIndex:mode]; +/* +#ifdef KEYPAD_JOYSTICK + joy_auto_recenter = [defaults integerForKey:kApple2JoystickAutoRecenter]; + [self.joystickRecenter setState:joy_auto_recenter ? NSOnState : NSOffState]; + joy_step = [defaults integerForKey:kApple2JoystickStep]; + if (!joy_step) + { + joy_step = 1; + } + [self.joystickStepLabel setIntegerValue:joy_step]; + [self.joystickStepper setIntegerValue:joy_step]; +#endif + + joy_clip_to_radius = [defaults boolForKey:kApple2JoystickClipToRadius]; + [self.joystickClipToRadius setState:joy_clip_to_radius ? NSOnState : NSOffState]; + + [self _setupJoystickUI]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawJoystickCalibration:) name:(NSString *)kDrawTimerNotification object:nil]; +*/ + +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +// The number of columns of data +- (int)numberOfComponentsInPickerView:(UIPickerView *)pickerView +{ + return 1; +} + +// The number of rows of data +- (int)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component +{ + return 2; + //_pickerData.count; +} + +// The data to return for the row and component (column) that's being passed in +- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component +{ + return [self._videoMode objectAtIndex:row]; +} + +// Catpure the picker view selection +- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component +{ + // This method is triggered whenever the user makes a change to the picker selection. + // The parameter named row and component represents what was selected. + NSLog(@"Selected Row %d", row); +} + +- (void)_savePrefs +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setBool:YES forKey:kApple2SavedPrefs]; + [defaults setDouble:cpu_scale_factor forKey:kApple2CPUSpeed]; + [defaults setDouble:cpu_altscale_factor forKey:kApple2AltSpeed]; + // [defaults setBool:([self.cpuMaxChoice state] == NSOnState) forKey:kApple2CPUSpeedIsMax]; + // [defaults setBool:([self.altMaxChoice state] == NSOnState) forKey:kApple2AltSpeedIsMax]; + [defaults setInteger:color_mode forKey:kApple2ColorConfig]; + [defaults setInteger:joy_mode forKey:kApple2JoystickConfig]; + // [defaults setInteger:joy_step forKey:kApple2JoystickStep]; + // [defaults setBool:joy_auto_recenter forKey:kApple2JoystickAutoRecenter]; + [defaults setBool:joy_clip_to_radius forKey:kApple2JoystickClipToRadius]; +} +- (IBAction)sliderDidMove:(id)sender +{ + UISlider *slider = (UISlider *)sender; + double value = slider.value; + if (slider == self.cpuSlider) + { + cpu_scale_factor = value; + self.cpuSliderLabel.text=[NSString stringWithFormat:@"%.0f%%", value*100]; + } + else + { + cpu_altscale_factor = value; + self.altSliderLabel.text=[NSString stringWithFormat:@"%.0f%%", value*100]; + } + + timing_initialize(); + + [self _savePrefs]; +} + +- (IBAction)peggedChoiceChanged:(id)sender +{ + UISwitch *maxButton = (UISwitch *)sender; + if (maxButton == self.cpuMaxChoice) + { + [self.cpuSlider setEnabled:([maxButton state] != YES)]; + cpu_scale_factor = ([maxButton state] == NO) ? CPU_SCALE_FASTEST : self.cpuSlider.value; + } + else + { + [self.altSlider setEnabled:([maxButton state] != YES)]; + cpu_altscale_factor = ([maxButton state] == YES) ? CPU_SCALE_FASTEST : self.altSlider.value; + } + + timing_initialize(); + + [self _savePrefs]; +} +/* + #pragma mark - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. + } + */ + + +- (void)dealloc { + /* [_videoModePicker release]; + [_cpuSlider release]; + [_altSlider release]; + [_cpuSliderLabel release]; + [_altSlider release]; + [_cpuMaxChoice release]; + [_altMaxChoice release]; + */ + [super dealloc]; +} + +-(IBAction)goodbye:(id)sender +{ + [self dismissViewControllerAnimated:YES completion:nil]; + cpu_resume(); +} +- (IBAction)unwindToMainViewController:(UIStoryboardSegue*)sender +{ + +} + +@end + + diff --git a/Apple2Mac/Apple2MacTests/fr.lproj/InfoPlist.strings b/Apple2Mac/Apple2MacTests/fr.lproj/InfoPlist.strings new file mode 100644 index 00000000..477b28ff --- /dev/null +++ b/Apple2Mac/Apple2MacTests/fr.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Apple2Mac/Apple2etvOS/AppDelegate.h b/Apple2Mac/Apple2etvOS/AppDelegate.h new file mode 100644 index 00000000..87caeece --- /dev/null +++ b/Apple2Mac/Apple2etvOS/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// Apple2etvOS +// +// Created by Jerome Vernet on 01/01/2016. +// Copyright © 2016 deadc0de.org. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/Apple2Mac/Apple2etvOS/AppDelegate.m b/Apple2Mac/Apple2etvOS/AppDelegate.m new file mode 100644 index 00000000..a32f3324 --- /dev/null +++ b/Apple2Mac/Apple2etvOS/AppDelegate.m @@ -0,0 +1,45 @@ +// +// AppDelegate.m +// Apple2etvOS +// +// Created by Jerome Vernet on 01/01/2016. +// Copyright © 2016 deadc0de.org. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json new file mode 100644 index 00000000..8bf75d9f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json new file mode 100644 index 00000000..8bf75d9f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json new file mode 100644 index 00000000..6a3dcfa5 --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json @@ -0,0 +1,26 @@ +{ + "assets" : [ + { + "size" : "1280x768", + "idiom" : "tv", + "filename" : "App Icon - Large.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "400x240", + "idiom" : "tv", + "filename" : "App Icon - Small.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "1920x720", + "idiom" : "tv", + "filename" : "Top Shelf Image.imageset", + "role" : "top-shelf-image" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json new file mode 100644 index 00000000..0564959f --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json b/Apple2Mac/Apple2etvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 00000000..29d94c78 --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "orientation" : "landscape", + "idiom" : "tv", + "extent" : "full-screen", + "minimum-system-version" : "9.0", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2etvOS/Base.lproj/Main.storyboard b/Apple2Mac/Apple2etvOS/Base.lproj/Main.storyboard new file mode 100644 index 00000000..3e6780b3 --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Base.lproj/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Apple2Mac/Apple2etvOS/Info.plist b/Apple2Mac/Apple2etvOS/Info.plist new file mode 100644 index 00000000..34e38136 --- /dev/null +++ b/Apple2Mac/Apple2etvOS/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + GCSupportedGameControllers + + + ProfileName + ExtendedGamepad + + + ProfileName + Gamepad + + + ProfileName + MicroGamepad + + + GCSupportsControllerUserInteraction + + LSRequiresIPhoneOS + + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + + diff --git a/Apple2Mac/Apple2etvOS/ViewController.h b/Apple2Mac/Apple2etvOS/ViewController.h new file mode 100644 index 00000000..a3201402 --- /dev/null +++ b/Apple2Mac/Apple2etvOS/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// Apple2etvOS +// +// Created by Jerome Vernet on 01/01/2016. +// Copyright © 2016 deadc0de.org. All rights reserved. +// + +#import + +@interface ViewController : UIViewController + + +@end + diff --git a/Apple2Mac/Apple2etvOS/ViewController.m b/Apple2Mac/Apple2etvOS/ViewController.m new file mode 100644 index 00000000..5b18ff23 --- /dev/null +++ b/Apple2Mac/Apple2etvOS/ViewController.m @@ -0,0 +1,27 @@ +// +// ViewController.m +// Apple2etvOS +// +// Created by Jerome Vernet on 01/01/2016. +// Copyright © 2016 deadc0de.org. All rights reserved. +// + +#import "ViewController.h" + +@interface ViewController () + +@end + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/Apple2Mac/Apple2etvOS/main.m b/Apple2Mac/Apple2etvOS/main.m new file mode 100644 index 00000000..c78904dc --- /dev/null +++ b/Apple2Mac/Apple2etvOS/main.m @@ -0,0 +1,16 @@ +// +// main.m +// Apple2etvOS +// +// Created by Jerome Vernet on 01/01/2016. +// Copyright © 2016 deadc0de.org. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/Apple2Mac/Apple2iOS/Apple2iOS-Info.plist b/Apple2Mac/Apple2iOS/Apple2iOS-Info.plist new file mode 100644 index 00000000..6d00bc96 --- /dev/null +++ b/Apple2Mac/Apple2iOS/Apple2iOS-Info.plist @@ -0,0 +1,75 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDocumentTypes + + + CFBundleTypeIconFiles + + CFBundleTypeName + Dsk Images + LSItemContentTypes + + com.apple2ios.dskinfo + + + + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.9.1 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIFileSharingEnabled + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UTExportedTypeDeclarations + + + UTTypeDescription + dsk + UTTypeIdentifier + com.apple2ios.dskinfo + UTTypeSize64IconFile + floppy + UTTypeTagSpecification + + public.filename-extension + dsk + + + + + diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-120.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-120.png new file mode 100644 index 00000000..228f3db9 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-120.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-130.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-130.png new file mode 100644 index 00000000..05c07b66 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-130.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-156.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-156.png new file mode 100644 index 00000000..e50db1d5 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-156.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29.png new file mode 100644 index 00000000..5a30f576 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29x2-1.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29x2-1.png new file mode 100644 index 00000000..a5f43f00 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29x2-1.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29x2.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29x2.png new file mode 100644 index 00000000..a5f43f00 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-29x2.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-30.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-30.png new file mode 100644 index 00000000..5a30f576 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-30.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-40.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-40.png new file mode 100644 index 00000000..cd387599 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-40.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-41.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-41.png new file mode 100644 index 00000000..cd387599 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-41.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-60.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-60.png new file mode 100644 index 00000000..7b7f2a3f Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-60.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-76.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-76.png new file mode 100644 index 00000000..b79a4caa Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-76.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-80.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-80.png new file mode 100644 index 00000000..8c7f986a Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-80.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-81.png b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-81.png new file mode 100644 index 00000000..8c7f986a Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/2e-81.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..b5f0d3f7 --- /dev/null +++ b/Apple2Mac/Apple2iOS/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,86 @@ +{ + "images" : [ + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "2e-29.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "2e-29x2.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "2e-40.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "2e-80.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "2e-60.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "2e-120.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "2e-30.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "2e-29x2-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "2e-41.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "2e-81.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "2e-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "2e-156.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "2e-130.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/CPU.imageset/Contents.json b/Apple2Mac/Apple2iOS/Assets.xcassets/CPU.imageset/Contents.json new file mode 100644 index 00000000..0b873402 --- /dev/null +++ b/Apple2Mac/Apple2iOS/Assets.xcassets/CPU.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "cpu.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/CPU.imageset/cpu.png b/Apple2Mac/Apple2iOS/Assets.xcassets/CPU.imageset/cpu.png new file mode 100644 index 00000000..9cfd989f Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/CPU.imageset/cpu.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Contents.json b/Apple2Mac/Apple2iOS/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/Apple2Mac/Apple2iOS/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Disk.imageset/Contents.json b/Apple2Mac/Apple2iOS/Assets.xcassets/Disk.imageset/Contents.json new file mode 100644 index 00000000..ab63c4a6 --- /dev/null +++ b/Apple2Mac/Apple2iOS/Assets.xcassets/Disk.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "floppy.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Disk.imageset/floppy.png b/Apple2Mac/Apple2iOS/Assets.xcassets/Disk.imageset/floppy.png new file mode 100644 index 00000000..8edadee9 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/Disk.imageset/floppy.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Pause.imageset/Contents.json b/Apple2Mac/Apple2iOS/Assets.xcassets/Pause.imageset/Contents.json new file mode 100644 index 00000000..4da7210b --- /dev/null +++ b/Apple2Mac/Apple2iOS/Assets.xcassets/Pause.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Pause.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Pause.imageset/Pause.png b/Apple2Mac/Apple2iOS/Assets.xcassets/Pause.imageset/Pause.png new file mode 100644 index 00000000..93a0c8c3 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/Pause.imageset/Pause.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Prefs.imageset/Contents.json b/Apple2Mac/Apple2iOS/Assets.xcassets/Prefs.imageset/Contents.json new file mode 100644 index 00000000..185c49e4 --- /dev/null +++ b/Apple2Mac/Apple2iOS/Assets.xcassets/Prefs.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Prefs.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Prefs.imageset/Prefs.png b/Apple2Mac/Apple2iOS/Assets.xcassets/Prefs.imageset/Prefs.png new file mode 100644 index 00000000..4d32f90a Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/Prefs.imageset/Prefs.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Reboot.imageset/Contents.json b/Apple2Mac/Apple2iOS/Assets.xcassets/Reboot.imageset/Contents.json new file mode 100644 index 00000000..b5094596 --- /dev/null +++ b/Apple2Mac/Apple2iOS/Assets.xcassets/Reboot.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "reboot.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Reboot.imageset/reboot.png b/Apple2Mac/Apple2iOS/Assets.xcassets/Reboot.imageset/reboot.png new file mode 100644 index 00000000..6e20f45f Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/Reboot.imageset/reboot.png differ diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Run.imageset/Contents.json b/Apple2Mac/Apple2iOS/Assets.xcassets/Run.imageset/Contents.json new file mode 100644 index 00000000..cef5b921 --- /dev/null +++ b/Apple2Mac/Apple2iOS/Assets.xcassets/Run.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "run.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Apple2Mac/Apple2iOS/Assets.xcassets/Run.imageset/run.png b/Apple2Mac/Apple2iOS/Assets.xcassets/Run.imageset/run.png new file mode 100644 index 00000000..82032fc5 Binary files /dev/null and b/Apple2Mac/Apple2iOS/Assets.xcassets/Run.imageset/run.png differ diff --git a/Apple2Mac/Apple2iOS/Base.lproj/Apple2iOS.strings b/Apple2Mac/Apple2iOS/Base.lproj/Apple2iOS.strings new file mode 100644 index 00000000..1afa4994 --- /dev/null +++ b/Apple2Mac/Apple2iOS/Base.lproj/Apple2iOS.strings @@ -0,0 +1,11 @@ + +// Main Menu titles +"Emulator settings" = "Emulator settings"; +"Load disk image" = "Load disk image"; +"Save & restore" = "Save & restore"; +"Reboot or quit emulator" = "Reboot or quit emulator"; + +// Main Menu subtitles +"General, CPU, Joystick" = "General, CPU, Joystick"; +"Insert a Disk ][ image file" = "Insert a Disk ][ image file"; +"Quick save and restore" = "Quick save and restore"; diff --git a/Apple2Mac/Apple2iOS/Base.lproj/LaunchScreen.xib b/Apple2Mac/Apple2iOS/Base.lproj/LaunchScreen.xib new file mode 100644 index 00000000..7984b95e --- /dev/null +++ b/Apple2Mac/Apple2iOS/Base.lproj/LaunchScreen.xib @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Apple2Mac/Apple2iOS/Base.lproj/Main.storyboard b/Apple2Mac/Apple2iOS/Base.lproj/Main.storyboard new file mode 100644 index 00000000..7321d8ba --- /dev/null +++ b/Apple2Mac/Apple2iOS/Base.lproj/Main.storyboard @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Apple2Mac/Apple2iOS/en.lproj/Main.strings b/Apple2Mac/Apple2iOS/en.lproj/Main.strings new file mode 100644 index 00000000..6048397a --- /dev/null +++ b/Apple2Mac/Apple2iOS/en.lproj/Main.strings @@ -0,0 +1,27 @@ + +/* Class = "UILabel"; text = "Reboot or quit emulator"; ObjectID = "0WI-e2-xoP"; */ +"0WI-e2-xoP.text" = "Reboot or quit emulator"; + +/* Class = "UILabel"; text = "General, CPU, Joystick"; ObjectID = "HSF-ji-5WS"; */ +"HSF-ji-5WS.text" = "General, CPU, Joystick"; + +/* Class = "UILabel"; text = "Insert a Disk ][ image file"; ObjectID = "c93-nC-i3L"; */ +"c93-nC-i3L.text" = "Insert a Disk ][ image file"; + +/* Class = "UIBarButtonItem"; title = "Item"; ObjectID = "d5g-uX-Ssk"; */ +"d5g-uX-Ssk.title" = "Togle CPU"; + +/* Class = "UILabel"; text = "Save & restore"; ObjectID = "fJA-S4-XoG"; */ +"fJA-S4-XoG.text" = "Save & restore"; + +/* Class = "UILabel"; text = "Load disk image"; ObjectID = "gOe-OR-ycd"; */ +"gOe-OR-ycd.text" = "Load disk image"; + +/* Class = "UILabel"; text = "Emulator settings"; ObjectID = "mbz-lM-DIP"; */ +"mbz-lM-DIP.text" = "Emulator settings"; + +/* Class = "UIBarButtonItem"; title = "Reboot"; ObjectID = "pwr-c0-7tW"; */ +"pwr-c0-7tW.title" = "Reboot"; + +/* Class = "UILabel"; text = "Quick save and restore"; ObjectID = "t5D-5L-z8k"; */ +"t5D-5L-z8k.text" = "Quick save and restore"; diff --git a/Apple2Mac/Apple2iOS/fr.lproj/Apple2iOS.strings b/Apple2Mac/Apple2iOS/fr.lproj/Apple2iOS.strings new file mode 100644 index 00000000..1afa4994 --- /dev/null +++ b/Apple2Mac/Apple2iOS/fr.lproj/Apple2iOS.strings @@ -0,0 +1,11 @@ + +// Main Menu titles +"Emulator settings" = "Emulator settings"; +"Load disk image" = "Load disk image"; +"Save & restore" = "Save & restore"; +"Reboot or quit emulator" = "Reboot or quit emulator"; + +// Main Menu subtitles +"General, CPU, Joystick" = "General, CPU, Joystick"; +"Insert a Disk ][ image file" = "Insert a Disk ][ image file"; +"Quick save and restore" = "Quick save and restore"; diff --git a/Apple2Mac/Apple2iOS/fr.lproj/LaunchScreen.strings b/Apple2Mac/Apple2iOS/fr.lproj/LaunchScreen.strings new file mode 100644 index 00000000..d8569360 --- /dev/null +++ b/Apple2Mac/Apple2iOS/fr.lproj/LaunchScreen.strings @@ -0,0 +1,3 @@ + +/* Class = "UILabel"; text = "Apple2iOS"; ObjectID = "kId-c2-rCX"; */ +"kId-c2-rCX.text" = "Apple2iOS"; diff --git a/Apple2Mac/Apple2iOS/fr.lproj/Main.strings b/Apple2Mac/Apple2iOS/fr.lproj/Main.strings new file mode 100644 index 00000000..6c9b20f3 --- /dev/null +++ b/Apple2Mac/Apple2iOS/fr.lproj/Main.strings @@ -0,0 +1,24 @@ + +/* Class = "UILabel"; text = "Reboot or quit emulator"; ObjectID = "0WI-e2-xoP"; */ +"0WI-e2-xoP.text" = "Reboot or quit emulator"; + +/* Class = "UILabel"; text = "General, CPU, Joystick"; ObjectID = "HSF-ji-5WS"; */ +"HSF-ji-5WS.text" = "General, CPU, Joystick"; + +/* Class = "UILabel"; text = "Insert a Disk ][ image file"; ObjectID = "c93-nC-i3L"; */ +"c93-nC-i3L.text" = "Insert a Disk ][ image file"; + +/* Class = "UILabel"; text = "Save & restore"; ObjectID = "fJA-S4-XoG"; */ +"fJA-S4-XoG.text" = "Save & restore"; + +/* Class = "UILabel"; text = "Load disk image"; ObjectID = "gOe-OR-ycd"; */ +"gOe-OR-ycd.text" = "Load disk image"; + +/* Class = "UILabel"; text = "Emulator settings"; ObjectID = "mbz-lM-DIP"; */ +"mbz-lM-DIP.text" = "Emulator settings"; + +/* Class = "UILabel"; text = "Quick save and restore"; ObjectID = "t5D-5L-z8k"; */ +"t5D-5L-z8k.text" = "Quick save and restore"; + +/* Class = "UIBarButtonItem"; title = "Item"; ObjectID = "d5g-uX-Ssk"; */ +"d5g-uX-Ssk.title" = "CPU"; \ No newline at end of file diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.h b/Apple2Mac/Classes/OSX/EmulatorDiskController.h similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.h rename to Apple2Mac/Classes/OSX/EmulatorDiskController.h diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.m b/Apple2Mac/Classes/OSX/EmulatorDiskController.m similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.m rename to Apple2Mac/Classes/OSX/EmulatorDiskController.m diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.h b/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.h similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.h rename to Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.h diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.m b/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.m similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.m rename to Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.m diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorGLView.h b/Apple2Mac/Classes/OSX/EmulatorGLView.h similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorGLView.h rename to Apple2Mac/Classes/OSX/EmulatorGLView.h diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorGLView.m b/Apple2Mac/Classes/OSX/EmulatorGLView.m similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorGLView.m rename to Apple2Mac/Classes/OSX/EmulatorGLView.m diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickCalibrationView.h b/Apple2Mac/Classes/OSX/EmulatorJoystickCalibrationView.h similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickCalibrationView.h rename to Apple2Mac/Classes/OSX/EmulatorJoystickCalibrationView.h diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickCalibrationView.m b/Apple2Mac/Classes/OSX/EmulatorJoystickCalibrationView.m similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickCalibrationView.m rename to Apple2Mac/Classes/OSX/EmulatorJoystickCalibrationView.m diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.h b/Apple2Mac/Classes/OSX/EmulatorJoystickController.h similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.h rename to Apple2Mac/Classes/OSX/EmulatorJoystickController.h diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.m b/Apple2Mac/Classes/OSX/EmulatorJoystickController.m similarity index 83% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.m rename to Apple2Mac/Classes/OSX/EmulatorJoystickController.m index b1452419..a12a9652 100644 --- a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.m +++ b/Apple2Mac/Classes/OSX/EmulatorJoystickController.m @@ -127,26 +127,6 @@ void gldriver_joystick_reset(void) { #pragma mark NSObject(DDHidJoystickDelegate) #define DDHID_JOYSTICK_NORMALIZER ((float)JOY_RANGE/(DDHID_JOYSTICK_VALUE_MAX*2)) -#define QUARTER_JOY (HALF_JOY_RANGE>>1) - -static inline void clampBeyondRadius(void) { - CGFloat half_x = joy_x - HALF_JOY_RANGE; - CGFloat half_y = joy_y - HALF_JOY_RANGE; - CGFloat r = sqrtf(half_x*half_x + half_y*half_y); - bool shouldClip = (r > HALF_JOY_RANGE); - if (joy_clip_to_radius && shouldClip) { - if (joy_x < HALF_JOY_RANGE) { - joy_x = (joy_x < QUARTER_JOY) ? 0.f : joy_x; - } else { - joy_x = (joy_x < HALF_JOY_RANGE+QUARTER_JOY) ? joy_x : JOY_RANGE-1; - } - if (joy_y < HALF_JOY_RANGE) { - joy_y = (joy_y < QUARTER_JOY) ? 0.f : joy_y; - } else { - joy_y = (joy_y < HALF_JOY_RANGE+QUARTER_JOY) ? joy_y : JOY_RANGE-1; - } - } -} - (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick xChanged:(int)value { @@ -156,12 +136,8 @@ static inline void clampBeyondRadius(void) { } #endif - joy_x = (uint16_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER); - if (joy_x > 0xFF) { - joy_x = 0xFF; - } - - clampBeyondRadius(); + uint8_t x = (uint8_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER); + joydriver_setAxisValue(x, joydriver_getAxisY()); } - (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick yChanged:(int)value @@ -172,12 +148,8 @@ static inline void clampBeyondRadius(void) { } #endif - joy_y = (uint16_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER); - if (joy_y > 0xFF) { - joy_y = 0xFF; - } - - clampBeyondRadius(); + uint8_t y = (uint8_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER); + joydriver_setAxisValue(joydriver_getAxisX(), y); } - (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick otherAxis:(unsigned)otherAxis valueChanged:(int)value diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorPrefsController.h b/Apple2Mac/Classes/OSX/EmulatorPrefsController.h similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorPrefsController.h rename to Apple2Mac/Classes/OSX/EmulatorPrefsController.h diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorPrefsController.m b/Apple2Mac/Classes/OSX/EmulatorPrefsController.m similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorPrefsController.m rename to Apple2Mac/Classes/OSX/EmulatorPrefsController.m diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindow.h b/Apple2Mac/Classes/OSX/EmulatorWindow.h similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindow.h rename to Apple2Mac/Classes/OSX/EmulatorWindow.h diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindow.m b/Apple2Mac/Classes/OSX/EmulatorWindow.m similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindow.m rename to Apple2Mac/Classes/OSX/EmulatorWindow.m diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.h b/Apple2Mac/Classes/OSX/EmulatorWindowController.h similarity index 100% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.h rename to Apple2Mac/Classes/OSX/EmulatorWindowController.h diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m b/Apple2Mac/Classes/OSX/EmulatorWindowController.m similarity index 94% rename from Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m rename to Apple2Mac/Classes/OSX/EmulatorWindowController.m index 40927eab..bca5c5e0 100644 --- a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m +++ b/Apple2Mac/Classes/OSX/EmulatorWindowController.m @@ -23,7 +23,10 @@ @property (assign) IBOutlet NSWindow *disksWindow; @property (assign) IBOutlet NSWindow *prefsWindow; @property (assign) IBOutlet NSMenuItem *pauseMenuItem; - +@property (assign) IBOutlet NSToolbar *toolBar; +@property (assign) IBOutlet NSToolbarItem *pauseItem; +@property (assign) IBOutlet NSToolbarItem *disk1Item; +@property (assign) IBOutlet NSToolbarItem *disk2Item; @property (nonatomic, retain) EmulatorFullscreenWindow *fullscreenWindow; @property (nonatomic, retain) NSWindow *standardWindow; @@ -62,6 +65,7 @@ { [[self disksWindow] close]; cpu65_reboot(); + } - (IBAction)showDisksWindow:(id)sender @@ -126,13 +130,21 @@ if (paused) { [[self pauseMenuItem] setTitle:@"Resume Emulation"]; + [[self pauseItem] setImage:[NSImage imageNamed:@"Run"]]; + [[self pauseItem] setLabel:@"Paused"]; cpu_pause(); } else { [[self pauseMenuItem] setTitle:@"Pause Emulation"]; + [[self pauseItem] setImage:[NSImage imageNamed:@"Stop"]]; + [[self pauseItem] setLabel:@"Running"]; cpu_resume(); } + if (video_backend && video_backend->animation_showPaused) + { + video_backend->animation_showPaused(); + } } - (void)windowWillOpen:(NSNotification *)notification diff --git a/Apple2Mac/Classes/iOS/A2IXPopupChoreographer.h b/Apple2Mac/Classes/iOS/A2IXPopupChoreographer.h new file mode 100644 index 00000000..a907fe0f --- /dev/null +++ b/Apple2Mac/Classes/iOS/A2IXPopupChoreographer.h @@ -0,0 +1,22 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2015 Aaron Culliney + * + */ + +#import + +@interface A2IXPopupChoreographer : NSObject + ++ (A2IXPopupChoreographer *)sharedInstance; + +- (void)showMainMenuFromView:(UIView *)view; + +- (void)dismissMainMenu; + +@end diff --git a/Apple2Mac/Classes/iOS/A2IXPopupChoreographer.m b/Apple2Mac/Classes/iOS/A2IXPopupChoreographer.m new file mode 100644 index 00000000..78b3cce9 --- /dev/null +++ b/Apple2Mac/Classes/iOS/A2IXPopupChoreographer.m @@ -0,0 +1,129 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2015 Aaron Culliney + * + */ + +#import "A2IXPopupChoreographer.h" + +@interface A2IXPopupChoreographer () + +@property (nonatomic, retain) UIPopoverController *popover; +@property (nonatomic, retain) UIViewController *mainMenuVC; + +@end + +@implementation A2IXPopupChoreographer + ++ (A2IXPopupChoreographer *)sharedInstance +{ + static A2IXPopupChoreographer *mainMenuChoreographer = nil; + static dispatch_once_t onceToken = 0L; + dispatch_once(&onceToken, ^{ + mainMenuChoreographer = [[A2IXPopupChoreographer alloc] init]; + }); + return mainMenuChoreographer; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; + self.mainMenuVC = (UIViewController *)[storyboard instantiateViewControllerWithIdentifier:@"MainMenu"]; + } + return self; +} + +- (void)dealloc +{ + self.popover = nil; + self.mainMenuVC = nil; + [super dealloc]; +} + +- (void)showMainMenuFromView:(UIView *)view +{ + @synchronized(self) { + if (!self.popover) + { + // TODO : pause emulation + UIPopoverController *pop = [[UIPopoverController alloc] initWithContentViewController:self.mainMenuVC]; + [pop setDelegate:self]; + self.popover = pop; + [pop release]; + CGRect aRect = CGRectMake(0, 0, 640, 480); + [pop presentPopoverFromRect:aRect inView:view permittedArrowDirections:UIPopoverArrowDirectionUnknown animated:YES]; + + UITableViewController *tableVC = self.mainMenuVC.childViewControllers.firstObject; + tableVC.tableView.delegate = self; + } + } +} + +- (void)dismissMainMenu +{ + @synchronized(self) { + [self.popover dismissPopoverAnimated:YES]; + [self popoverControllerDidDismissPopover:nil]; + } +} + + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + switch (indexPath.row) { + case 0: + NSLog(@"Show emulator settings ..."); + break; + case 1: + NSLog(@"Show load disk image ..."); + break; + case 2: + NSLog(@"Show save/restore ..."); + break; + case 3: + NSLog(@"Show reboot/quit ..."); + break; + default: + NSAssert(false, @"This should not happen ..."); + break; + } +} + + +#pragma mark - UIPopoverControllerDelegate + +/* Called on the delegate when the popover controller will dismiss the popover. Return NO to prevent the dismissal of the view. + */ +- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController +{ + return YES; +} + +/* Called on the delegate when the user has taken action to dismiss the popover. This is not called when -dismissPopoverAnimated: is called directly. + */ +- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController +{ + @synchronized(self) { + self.popover = nil; + // TODO : restart emulation + } +} + +/* -popoverController:willRepositionPopoverToRect:inView: is called on your delegate when the popover may require a different view or rectangle + */ +- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView **)view +{ + +} + +@end diff --git a/Apple2Mac/Classes/iOS/AppDelegate.h b/Apple2Mac/Classes/iOS/AppDelegate.h new file mode 100644 index 00000000..7606a3a2 --- /dev/null +++ b/Apple2Mac/Classes/iOS/AppDelegate.h @@ -0,0 +1,22 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2015 Aaron Culliney + * + */ + +#import + +@class EAGLView; +@class MainViewController; + +@interface AppDelegate : NSObject + +@property (nonatomic, retain) UIWindow *window; + +@end + diff --git a/Apple2Mac/Classes/iOS/AppDelegate.m b/Apple2Mac/Classes/iOS/AppDelegate.m new file mode 100644 index 00000000..85a2ee66 --- /dev/null +++ b/Apple2Mac/Classes/iOS/AppDelegate.m @@ -0,0 +1,93 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2015 Aaron Culliney + * + */ + +#import "AppDelegate.h" +#import "EAGLView.h" +#import "common.h" + +@implementation AppDelegate + +#pragma mark - Application lifecycle + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)options +{ + // Override point for customization after application launch. + + [self.window makeKeyAndVisible]; + + EAGLView *view = (EAGLView *)self.window.rootViewController.view; + [view resumeRendering]; + [view resumeEmulation]; + + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of + // temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application + // and it begins the transition to the background state. Use this method to pause ongoing tasks, disable timers, + // and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + EAGLView *view = (EAGLView *)self.window.rootViewController.view; + [view pauseRendering]; + [view pauseEmulation]; +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application + // state information to restore your application to its current state in case it is terminated later. If your + // application supports background execution, called instead of applicationWillTerminate: when the user quits. + EAGLView *view = (EAGLView *)self.window.rootViewController.view; + [view pauseRendering]; + [view pauseEmulation]; +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // Called as part of transition from the background to the inactive state: here you can undo many of the changes + // made on entering the background. + EAGLView *view = (EAGLView *)self.window.rootViewController.view; + [view resumeRendering]; + [view resumeEmulation]; +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application + // was previously in the background, optionally refresh the user interface. + EAGLView *view = (EAGLView *)self.window.rootViewController.view; + [view resumeRendering]; + [view resumeEmulation]; +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. See also applicationDidEnterBackground: + EAGLView *view = (EAGLView *)self.window.rootViewController.view; + self.window.rootViewController.view = [[UIView alloc] init]; + + [view pauseRendering]; + [view pauseEmulation]; + + [view release]; +} + +#pragma mark - Memory management + +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application +{ + // prolly not much we can do here at the moment since we run a tight ship... + LOG("..."); +} + +@end + diff --git a/Apple2Mac/Classes/iOS/EAGLView.h b/Apple2Mac/Classes/iOS/EAGLView.h new file mode 100644 index 00000000..587ac3f8 --- /dev/null +++ b/Apple2Mac/Classes/iOS/EAGLView.h @@ -0,0 +1,28 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2015 Aaron Culliney + * + */ + +#import + +// This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass. +// The view content is basically an EAGL surface you render your OpenGL scene into. +// Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel. +@interface EAGLView : UIView + +@property (nonatomic, readonly, getter=isAnimating, assign) BOOL animating; +@property (nonatomic, assign) NSInteger renderFrameInterval; + +- (void)pauseRendering; +- (void)resumeRendering; + +- (void)pauseEmulation; +- (void)resumeEmulation; + +@end diff --git a/Apple2Mac/Classes/iOS/EAGLView.m b/Apple2Mac/Classes/iOS/EAGLView.m new file mode 100644 index 00000000..45e119f6 --- /dev/null +++ b/Apple2Mac/Classes/iOS/EAGLView.m @@ -0,0 +1,333 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2015 Aaron Culliney + * + */ + +#import "EAGLView.h" +#import "common.h" +#import "modelUtil.h" + +#import "A2IXPopupChoreographer.h" + +#import +#import + +@interface EAGLView () + +@property (nonatomic, retain) EAGLContext *context; +@property (nonatomic, retain) CADisplayLink *displayLink; +@property (nonatomic, assign) GLuint defaultFBOName; +@property (nonatomic, assign) GLuint colorRenderbuffer; + +@end + +@implementation EAGLView + +@synthesize renderFrameInterval = _renderFrameInterval; + +// Must return the CAEAGLLayer class so that CA allocates an EAGLLayer backing for this view ++ (Class)layerClass +{ + return [CAEAGLLayer class]; +} + +// -initWithCoder: is sent when unarchived from storyboard file +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) + { + CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; + + eaglLayer.opaque = YES; + eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; + + + _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + if (!_context || ![EAGLContext setCurrentContext:_context]) + { + [self release]; + return nil; + } + + // Create default framebuffer object. The backing will be allocated for the + // current layer in -resizeFromLayer + glGenFramebuffers(1, &_defaultFBOName); + + glGenRenderbuffers(1, &_colorRenderbuffer); + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBOName); + glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); + + // This call associates the storage for the current render buffer with the + // EAGLDrawable (our CAEAGLLayer) allowing us to draw into a buffer that + // will later be rendered to the screen wherever the layer is (which + // corresponds with our view). + [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id)self.layer]; + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderbuffer); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); + [self release]; + return nil; + } + + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBOName); + + // start emulator from paused state + cpu_pause(); + emulator_start(); + video_backend->init(0); + + _animating = NO; + _renderFrameInterval = 1; + _displayLink = nil; + } + + return self; +} + +- (void)dealloc +{ + [self pauseRendering]; + [_displayLink release]; + _displayLink = nil; + + // shut down common OpenGL stuff AFTER display link has been released + emulator_shutdown(); + + if (_defaultFBOName != UNINITIALIZED_GL) + { + glDeleteFramebuffers(1, &_defaultFBOName); + _defaultFBOName = UNINITIALIZED_GL; + } + if (_colorRenderbuffer != UNINITIALIZED_GL) + { + glDeleteRenderbuffers(1, &_colorRenderbuffer); + _colorRenderbuffer = UNINITIALIZED_GL; + } + + if ([EAGLContext currentContext] == _context) + { + [EAGLContext setCurrentContext:nil]; + } + + [_context release]; + _context = nil; + + [super dealloc]; +} + +- (void)pauseEmulation +{ + cpu_pause(); +} + +- (void)resumeEmulation +{ + cpu_resume(); +} + +- (void)drawView:(id)sender +{ + [EAGLContext setCurrentContext:_context]; + + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBOName); + video_backend->render(); + glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); + + [_context presentRenderbuffer:GL_RENDERBUFFER]; +} + +- (void)layoutSubviews +{ + // Allocate color buffer backing based on the current layer size + glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); + [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id)self.layer]; + + // The pixel dimensions of the CAEAGLLayer + GLint backingWidth = 0; + GLint backingHeight = 0; + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); + + video_backend->reshape((int)backingWidth, (int)backingHeight); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); + return; + } + + [self drawView:nil]; +} + +- (void)setRenderFrameInterval:(NSInteger)frameInterval +{ + // Frame interval defines how many display frames must pass between each time the + // display link fires. The display link will only fire 30 times a second when the + // frame internal is two on a display that refreshes 60 times a second. The default + // frame interval setting of one will fire 60 times a second when the display refreshes + // at 60 times a second. A frame interval setting of less than one results in undefined + // behavior. + if (frameInterval >= 1) + { + _renderFrameInterval = frameInterval; + if (_animating) + { + [self pauseRendering]; + [self resumeRendering]; + } + } +} + +- (void)resumeRendering +{ + if (!_animating) + { + _animating = YES; + + // Create the display link and set the callback to our drawView method + _displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(drawView:)] retain]; + + // Set it to our _renderFrameInterval + [_displayLink setFrameInterval:_renderFrameInterval]; + + // Have the display link run on the default runn loop (and the main thread) + [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + } +} + +- (void)pauseRendering +{ + if (_animating) + { + [_displayLink invalidate]; + [_displayLink release]; + _displayLink = nil; + _animating = NO; + } +} + +#pragma mark - Touch Handling + +- (BOOL)isMultipleTouchEnabled +{ + return YES; +} + +static inline void _handleTouch(EAGLView *self, SEL _cmd, UITouch *touch, interface_touch_event_t eventType) { + + CGPoint location = [touch locationInView:self]; + float x[1] = { location.x }; + float y[1] = { location.y }; + + int64_t flags = interface_onTouchEvent(eventType, (int)1, (int)0, x, y); + + do { + if ((flags & TOUCH_FLAGS_HANDLED) == 0) + { + break; + } + + if ((flags & TOUCH_FLAGS_REQUEST_HOST_MENU) != 0) + { + // requested host menu + [[A2IXPopupChoreographer sharedInstance] showMainMenuFromView:self]; + } + + if ((flags & TOUCH_FLAGS_KEY_TAP) != 0) + { + // tapped key + } + + if ((flags & TOUCH_FLAGS_MENU) == 0) + { + // touch menu was tapped + break; + } + + // touched menu item ... + if ((flags & TOUCH_FLAGS_INPUT_DEVICE_CHANGE) != 0) + { + if ((flags & TOUCH_FLAGS_KBD) != 0) + { + keydriver_setTouchKeyboardOwnsScreen(true); + joydriver_setTouchJoystickOwnsScreen(false); + video_backend->animation_showTouchKeyboard(); + } + else if ((flags & TOUCH_FLAGS_JOY) != 0) + { + keydriver_setTouchKeyboardOwnsScreen(false); + joydriver_setTouchJoystickOwnsScreen(true); + joydriver_setTouchVariant(EMULATED_JOYSTICK); + video_backend->animation_showTouchJoystick(); + } + else if ((flags & TOUCH_FLAGS_JOY_KPAD) != 0) + { + keydriver_setTouchKeyboardOwnsScreen(false); + joydriver_setTouchJoystickOwnsScreen(true); + joydriver_setTouchVariant(EMULATED_KEYPAD); + video_backend->animation_showTouchJoystick(); + } + else + { + // switch to next variant ... + } + } + else if ((flags & TOUCH_FLAGS_CPU_SPEED_DEC) != 0) + { + // handle cpu decrement + } + else if ((flags & TOUCH_FLAGS_CPU_SPEED_INC) != 0) + { + // handle cpu increment + } + } while (NO); +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + LOG("..."); + for (UITouch *touch in touches) + { + _handleTouch(self, _cmd, touch, TOUCH_DOWN); + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + LOG("..."); + for (UITouch *touch in touches) + { + _handleTouch(self, _cmd, touch, TOUCH_MOVE); + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + LOG("..."); + for (UITouch *touch in touches) + { + _handleTouch(self, _cmd, touch, TOUCH_UP); + } +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ + LOG("..."); + for (UITouch *touch in touches) + { + _handleTouch(self, _cmd, touch, TOUCH_CANCEL); + } +} + + +@end diff --git a/Apple2Mac/DDHidLib/DDHidLib.xcodeproj/project.pbxproj b/Apple2Mac/DDHidLib/DDHidLib.xcodeproj/project.pbxproj index 828e299b..951dc2bb 100644 --- a/Apple2Mac/DDHidLib/DDHidLib.xcodeproj/project.pbxproj +++ b/Apple2Mac/DDHidLib/DDHidLib.xcodeproj/project.pbxproj @@ -185,6 +185,11 @@ 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* HIDBrowser_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HIDBrowser_Prefix.pch; sourceTree = ""; }; + 4E4586071C29F39A003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; + 4E4586081C29F39A003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = fr; path = fr.lproj/MainMenu.nib; sourceTree = ""; }; + 4E4586091C29F39A003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; + 4E45860A1C29F39A003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = fr; path = fr.lproj/MainMenu.nib; sourceTree = ""; }; + 4E45860B1C29F39A003E74A1 /* fr */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = fr; path = fr.lproj/EventWatcher.nib; sourceTree = ""; }; 55170D340B8EC2CE00C82155 /* DDHidAppleRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidAppleRemote.h; sourceTree = ""; }; 55170D350B8EC2CE00C82155 /* DDHidAppleRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidAppleRemote.m; sourceTree = ""; }; 55170E0B0B8ECCAC00C82155 /* AppleRemotePaneController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleRemotePaneController.h; sourceTree = ""; }; @@ -627,6 +632,7 @@ hasScannedForEncodings = 1; knownRegions = ( en, + fr, ); mainGroup = 29B97314FDCFA39411CA2CEA /* HIDBrowser */; projectDirPath = ""; @@ -778,6 +784,7 @@ isa = PBXVariantGroup; children = ( 089C165DFE840E0CC02AAC07 /* English */, + 4E4586091C29F39A003E74A1 /* fr */, ); name = InfoPlist.strings; sourceTree = ""; @@ -786,6 +793,7 @@ isa = PBXVariantGroup; children = ( 29B97319FDCFA39411CA2CEA /* English */, + 4E45860A1C29F39A003E74A1 /* fr */, ); name = MainMenu.nib; sourceTree = ""; @@ -794,6 +802,7 @@ isa = PBXVariantGroup; children = ( 55D5927C0BAE306E00364849 /* English */, + 4E4586071C29F39A003E74A1 /* fr */, ); name = InfoPlist.strings; sourceTree = ""; @@ -802,6 +811,7 @@ isa = PBXVariantGroup; children = ( 55D592930BAE30B600364849 /* English */, + 4E4586081C29F39A003E74A1 /* fr */, ); name = MainMenu.nib; sourceTree = ""; @@ -810,6 +820,7 @@ isa = PBXVariantGroup; children = ( 55DCD9DF0B55D503000648E5 /* English */, + 4E45860B1C29F39A003E74A1 /* fr */, ); name = EventWatcher.nib; sourceTree = ""; diff --git a/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/classes.nib b/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/classes.nib new file mode 100644 index 00000000..8f04df5d --- /dev/null +++ b/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/classes.nib @@ -0,0 +1,13 @@ +{ + IBClasses = ( + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + ACTIONS = {clearHistory = id; }; + CLASS = WatcherWindowController; + LANGUAGE = ObjC; + OUTLETS = {mEventHistoryController = NSArrayController; }; + SUPERCLASS = NSWindowController; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/info.nib b/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/info.nib new file mode 100644 index 00000000..1c52771a --- /dev/null +++ b/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBDocumentLocation + 69 14 356 240 0 0 1440 878 + IBFramework Version + 446.1 + IBOpenObjects + + 5 + + IBSystem Version + 8N1037 + + diff --git a/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/keyedobjects.nib b/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/keyedobjects.nib new file mode 100644 index 00000000..61ebe6c6 Binary files /dev/null and b/Apple2Mac/DDHidLib/browser/fr.lproj/EventWatcher.nib/keyedobjects.nib differ diff --git a/Apple2Mac/DDHidLib/browser/fr.lproj/InfoPlist.strings b/Apple2Mac/DDHidLib/browser/fr.lproj/InfoPlist.strings new file mode 100644 index 00000000..30cfd962 Binary files /dev/null and b/Apple2Mac/DDHidLib/browser/fr.lproj/InfoPlist.strings differ diff --git a/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/classes.nib b/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/classes.nib new file mode 100644 index 00000000..910a1c9f --- /dev/null +++ b/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,19 @@ +{ + IBClasses = ( + {CLASS = DDHidElement; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = HexFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; }, + { + ACTIONS = {exportPlist = id; watchSelected = id; }; + CLASS = HidBrowserController; + LANGUAGE = ObjC; + OUTLETS = { + mDevicesController = NSArrayController; + mElementsController = NSTreeController; + mWindow = NSWindow; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/info.nib b/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/info.nib new file mode 100644 index 00000000..d20a5cff --- /dev/null +++ b/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/info.nib @@ -0,0 +1,22 @@ + + + + + IBDocumentLocation + 110 86 356 240 0 0 1440 878 + IBEditorPositions + + 29 + 95 721 310 44 0 0 1440 878 + + IBFramework Version + 446.1 + IBOpenObjects + + 21 + 29 + + IBSystem Version + 8N1037 + + diff --git a/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/keyedobjects.nib b/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 00000000..904f45d5 Binary files /dev/null and b/Apple2Mac/DDHidLib/browser/fr.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/Apple2Mac/DDHidLib/device_test/fr.lproj/InfoPlist.strings b/Apple2Mac/DDHidLib/device_test/fr.lproj/InfoPlist.strings new file mode 100644 index 00000000..30cfd962 Binary files /dev/null and b/Apple2Mac/DDHidLib/device_test/fr.lproj/InfoPlist.strings differ diff --git a/Apple2Mac/DDHidLib/device_test/fr.lproj/MainMenu.nib/designable.nib b/Apple2Mac/DDHidLib/device_test/fr.lproj/MainMenu.nib/designable.nib new file mode 100644 index 00000000..fbb8f5ad --- /dev/null +++ b/Apple2Mac/DDHidLib/device_test/fr.lproj/MainMenu.nib/designable.nib @@ -0,0 +1,5311 @@ + + + + 1070 + 11G63 + 3084 + 1138.51 + 569.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 3084 + + + NSArrayController + NSBox + NSButton + NSButtonCell + NSCustomObject + NSCustomView + NSLevelIndicator + NSLevelIndicatorCell + NSMenu + NSMenuItem + NSPopUpButton + NSPopUpButtonCell + NSScrollView + NSScroller + NSTabView + NSTabViewItem + NSTableColumn + NSTableHeaderView + NSTableView + NSTextField + NSTextFieldCell + NSView + NSWindowTemplate + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + + NSApplication + + + + FirstResponder + + + NSApplication + + + 15 + 2 + {{183, 341}, {529, 499}} + 1881669632 + HID Device Test + NSWindow + + View + + + {213, 107} + + + 256 + + + + 274 + {{13, 10}, {503, 483}} + + + + + + + 1 + + + + 256 + + + + 268 + {{17, 399}, {50, 17}} + + + YES + + 67239424 + 272629760 + Mouse: + + LucidaGrande + 13 + 1044 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + 3 + MAA + + + + + + + 266 + {{69, 393}, {397, 26}} + + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + LucidaGrande + 13 + 16 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + + + + 268 + {{17, 372}, {93, 17}} + + + YES + + 67239424 + 272629760 + Manufacturer: + + + + + + + + + 266 + {{112, 372}, {354, 17}} + + + YES + + 67239424 + 272629760 + System Font Text + + + + + + + + + 268 + {{48, 338}, {62, 17}} + + + YES + + 67239424 + 272629760 + Mouse X: + + + + + + + + + 266 + {{12, 361}, {459, 5}} + + + {0, 0} + + 67239424 + 0 + Box + + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 3 + MCAwLjgwMDAwMDAxAA + + + 3 + 2 + 0 + NO + + + + 268 + {{46, 312}, {62, 17}} + + + YES + + 67239424 + 272629760 + Mouse Y: + + + + + + + + + 268 + {{17, 286}, {91, 17}} + + + YES + + 67239424 + 272629760 + Mouse Wheel: + + + + + + + + + 266 + {{113, 338}, {350, 16}} + + + YES + + 130560 + 0 + + 5000 + 1 + + + + + 266 + {{113, 312}, {350, 16}} + + + YES + + 130560 + 0 + + 5000 + 1 + + + + + 266 + {{113, 286}, {350, 16}} + + + YES + + 130560 + 0 + + 5 + 1 + + + + + 272 + + + + 2304 + + + + 256 + {157, 240} + + + YES + + + 256 + {157, 17} + + + + + + + 256 + {{158, 0}, {16, 17}} + + + + + + 65 + 40 + 1000 + + 75628096 + 2048 + Button + + LucidaGrande + 11 + 3100 + + + 3 + MC4zMzMzMzI5OQA + + + 6 + System + headerTextColor + + + + + 337772096 + 2048 + + + + 6 + System + controlBackgroundColor + + + + + 3 + YES + YES + + + + 85.97607421875 + 48.97607421875 + 1000 + + 75628096 + 2048 + Pressed + + + + + + 337772032 + 0 + + LucidaGrande + 12 + 16 + + + + + + 3 + YES + YES + + + + 3 + 2 + + + 6 + System + gridColor + + 3 + MC41AA + + + 17 + -700448768 + + + 5 + 15 + 0 + YES + 0 + 1 + + + {{1, 17}, {157, 240}} + + + + + 4 + + + + 256 + {{158, 17}, {15, 240}} + + + + _doScroller: + 0.89473682641983032 + + + + -2147483392 + {{-100, -100}, {131, 15}} + + + 1 + + _doScroller: + 0.99047619104385376 + + + + 2304 + + + + {{1, 0}, {157, 17}} + + + + + 4 + + + + {{113, 20}, {174, 258}} + + + 133138 + + + + + + QSAAAEEgAABBmAAAQZgAAA + + + {{10, 33}, {483, 437}} + + + Mice + + + + + + 2 + + + + 256 + + + + 268 + {{17, 399}, {57, 17}} + + YES + + 67239424 + 272629760 + Joystick: + + + + + + + + + 266 + {{76, 393}, {390, 26}} + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + + + + 268 + {{17, 372}, {93, 17}} + + YES + + 67239424 + 272629760 + Manufacturer: + + + + + + + + + 266 + {{112, 372}, {354, 17}} + + YES + + 69336577 + 272629760 + System Font Text + + + + + + + + + 276 + + + + 2304 + + + + 256 + {177, 267} + + YES + + + 256 + {177, 17} + + + + + + 256 + {{178, 0}, {16, 17}} + + + + + 80 + 40 + 1000 + + 75628096 + 2048 + Button + + + 3 + MC4zMzMzMzI5OQA + + + + + 337772096 + 2048 + + + + + + 3 + YES + + + + 90.97607421875 + 48.97607421875 + 1000 + + 75628096 + 2048 + Pressed + + + + + + 337772032 + 0 + + + + + + 3 + YES + + + + 3 + 2 + + + 17 + -700448768 + + + 5 + 15 + 0 + YES + 0 + 1 + + + {{1, 17}, {177, 267}} + + + + + 4 + + + + 256 + {{178, 17}, {15, 267}} + + + _doScroller: + 0.95789474248886108 + + + + 256 + {{-100, -100}, {177, 15}} + + 1 + + _doScroller: + 0.99047619104385376 + + + + 2304 + + + + {{1, 0}, {177, 17}} + + + + + 4 + + + + {{74, 20}, {194, 285}} + + + 133138 + + + + + QSAAAEEgAABBmAAAQZgAAA + + + + 266 + {{12, 361}, {459, 5}} + + {0, 0} + + 67239424 + 0 + Box + + + + 3 + MCAwLjgwMDAwMDAxAA + + + 3 + 2 + 0 + NO + + + + 266 + {{74, 337}, {389, 16}} + + YES + + 130560 + 0 + + -32768 + 32768 + 1 + + + + + 266 + {{74, 313}, {389, 16}} + + YES + + 130560 + 0 + + -32768 + 32768 + 1 + + + + + 268 + {{17, 337}, {52, 17}} + + YES + + 67239424 + 272629760 + X-Axis: + + + + + + + + + 268 + {{17, 313}, {52, 17}} + + YES + + 67239424 + 272629760 + Y-Axis: + + + + + + + + {{10, 33}, {483, 437}} + + Joysticks + + + + + + + 256 + + + + 266 + {{87, 393}, {379, 26}} + + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + + + + 264 + {{17, 399}, {68, 17}} + + + YES + + 67239424 + 272629760 + Keyboard: + + + + + + + + + 266 + {{112, 372}, {354, 17}} + + + YES + + 67239424 + 272629760 + System Font Text + + + + + + + + + 264 + {{17, 372}, {93, 17}} + + + YES + + 67239424 + 272629760 + Manufacturer: + + + + + + + + + 256 + {{12, 361}, {459, 5}} + + + {0, 0} + + 67239424 + 0 + Box + + + + 3 + MCAwLjgwMDAwMDAxAA + + + 3 + 2 + 0 + NO + + + + 256 + + + + 2304 + + + + 256 + {426, 333} + + + YES + + + 256 + {{427, 0}, {16, 17}} + + + + 94 + 40 + 1000 + + 75628096 + 2048 + + + + 3 + MC4zMzMzMzI5OQA + + + + + 337772096 + 2048 + + + + + + 3 + YES + YES + + + + 326 + 40 + 1000 + + 75628096 + 2048 + + + + + + + 337772096 + 2048 + + + + + + 3 + YES + YES + + + + 3 + 2 + + + 17 + 306184192 + + + 4 + 15 + 0 + YES + 0 + 1 + + + {{1, 1}, {426, 333}} + + + + + 4 + + + + 256 + {{427, 1}, {15, 333}} + + + + _doScroller: + 0.96315789222717285 + + + + -2147483392 + {{-100, -100}, {426, 15}} + + + 1 + + _doScroller: + 0.99047619104385376 + + + {{20, 20}, {443, 335}} + + + 133138 + + + + QSAAAEEgAABBmAAAQZgAAA + + + {{10, 33}, {483, 437}} + + + Keyboards + + + + + + + 256 + + + + 256 + {{188, 137}, {107, 280}} + + + RemoteFeedbackView + NSView + + + + 256 + {{176, 67}, {131, 32}} + + + YES + + 67239424 + 134217728 + Start Listening + + + -2038284033 + 1 + + + + + + 200 + 25 + + + + + 256 + {{165, 39}, {151, 18}} + + YES + + 67239424 + 131072 + Open in exclusive mode + + + 1211912703 + 2 + + NSSwitch + + + + 200 + 25 + + + + + 256 + {{165, 115}, {152, 14}} + + + YES + + 67239424 + 138543104 + - + + + + + + + + + 256 + {{194, 423}, {63, 14}} + + + YES + + 67239424 + 272629760 + Remote ID: + + + + + + + + + 256 + {{259, 423}, {32, 14}} + + + YES + + 67239424 + 272629760 + 9999 + + + + + + + + {{10, 33}, {483, 437}} + + + Remote + + + + + + + 256 + + + + 266 + {{87, 393}, {379, 26}} + + + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + + + + 264 + {{17, 399}, {41, 17}} + + + + YES + + 67239424 + 272629760 + Mikey + + + + + + + + + 266 + {{112, 372}, {354, 17}} + + + + YES + + 67239424 + 272629760 + System Font Text + + + + + + + + + 264 + {{17, 372}, {93, 17}} + + + + YES + + 67239424 + 272629760 + Manufacturer: + + + + + + + + + 256 + {{12, 361}, {459, 5}} + + + + {0, 0} + + 67239424 + 0 + Box + + + + 3 + MCAwLjgwMDAwMDAxAA + + + 3 + 2 + 0 + NO + + + + 256 + + + + 2304 + + + + 256 + {426, 333} + + + + YES + + + 256 + {{427, 0}, {16, 17}} + + + + 94 + 40 + 1000 + + 75628096 + 2048 + + + + 3 + MC4zMzMzMzI5OQA + + + + + 337772096 + 2048 + + + + + + 3 + YES + YES + + + + 326 + 40 + 1000 + + 75628096 + 2048 + + + + + + + 337772096 + 2048 + + + + + + 3 + YES + YES + + + + 3 + 2 + + + 17 + 306184192 + + + 4 + 15 + 0 + YES + 0 + 1 + + + {{1, 1}, {426, 333}} + + + + + + 4 + + + + 256 + {{427, 1}, {15, 333}} + + + + + _doScroller: + 0.96315789222717285 + + + + -2147483392 + {{-100, -100}, {426, 15}} + + + + 1 + + _doScroller: + 0.99047619104385376 + + + {{20, 20}, {443, 335}} + + + + 133138 + + + + QSAAAEEgAABBmAAAQZgAAA + + + {{10, 33}, {483, 437}} + + + + + Mikeys + + + + + + + 0 + YES + YES + + + + + + {529, 499} + + + + + {{0, 0}, {1920, 1178}} + {213, 129} + {10000000000000, 10000000000000} + YES + + + MainMenu + + + + HIDDeviceTest + + 1048576 + 2147483647 + + + submenuAction: + + HIDDeviceTest + + + + About HIDDeviceTest + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + + Services + + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide HIDDeviceTest + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit HIDDeviceTest + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + + File + + + + + New + n + 1048576 + 2147483647 + + + + + + Open… + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + + Open Recent + + + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save + s + 1048576 + 2147483647 + + + + + + Save As… + S + 1048576 + 2147483647 + + + + + + Revert + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup… + P + 1048576 + 2147483647 + + + + + + Print… + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + + Edit + + + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + + Find + + + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1048576 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling + + 1048576 + 2147483647 + + + submenuAction: + + Spelling + + + + Spelling… + : + 1048576 + 2147483647 + + + + + + Check Spelling + ; + 1048576 + 2147483647 + + + + + + Check Spelling as You Type + + 1048576 + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + + Window + + + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 1048576 + 2147483647 + + + submenuAction: + + + Help + + + + + NewApplication Help + ? + 1048576 + 2147483647 + + + + + + + + _NSMainMenu + + + DeviceTestController + + + + productName + manufacturer + + + YES + YES + YES + YES + YES + + + + name + pressed + + + YES + YES + YES + YES + YES + + + BoolFormatter + + + MousePaneController + + + JoystickPaneController + + + + productName + manufacturer + + + YES + YES + YES + YES + YES + + + + name + pressed + + + YES + YES + YES + YES + YES + + + AppleRemotePaneController + + + KeyboardPaneController + + + + productName + manufacturer + + YES + + YES + YES + YES + YES + YES + + + + event + description + + YES + + YES + YES + YES + YES + YES + + + AppleMikeyPaneController + + + + productName + manufacturer + + YES + + YES + YES + YES + YES + YES + + + + event + description + + YES + + YES + YES + YES + YES + YES + + + + 256 + {125, 1} + + + + + + + 256 + {125, 1} + + + + + + + 256 + {125, 1} + + + + + + + + + + terminate: + + + + 139 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + hideOtherApplications: + + + + 146 + + + + hide: + + + + 152 + + + + unhideAllApplications: + + + + 153 + + + + delegate + + + + 396 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + showHelp: + + + + 122 + + + + clearRecentDocuments: + + + + 127 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + performFindPanelAction: + + + + 242 + + + + performFindPanelAction: + + + + 243 + + + + performFindPanelAction: + + + + 244 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + pasteAsPlainText: + + + + 247 + + + + content: arrangedObjects.productName + + + + + + content: arrangedObjects.productName + content + arrangedObjects.productName + + Foo + Bar + No Mice + + 2 + + + 342 + + + + selectedIndex: mouseIndex + + + + + + selectedIndex: mouseIndex + selectedIndex + mouseIndex + + 2 + + + 355 + + + + mMousePaneController + + + + 346 + + + + mWindow + + + + 397 + + + + contentArray: mice + + + + + + contentArray: mice + contentArray + mice + + NSConditionallySetsEditable + + + 2 + + + 354 + + + + value: selection.manufacturer + + + + + + value: selection.manufacturer + value + selection.manufacturer + 2 + + + 267 + + + + maxValue: maxValue + + + + + + maxValue: maxValue + maxValue + maxValue + 2 + + + 347 + + + + value: mouseX + + + + + + value: mouseX + value + mouseX + + 2 + + + 356 + + + + maxValue: maxValue + + + + + + maxValue: maxValue + maxValue + maxValue + 2 + + + 349 + + + + value: mouseY + + + + + + value: mouseY + value + mouseY + + 2 + + + 357 + + + + maxValue: maxValue + + + + + + maxValue: maxValue + maxValue + maxValue + 2 + + + 351 + + + + value: mouseWheel + + + + + + value: mouseWheel + value + mouseWheel + + 2 + + + 358 + + + + value: arrangedObjects.name + + + + + + value: arrangedObjects.name + value + arrangedObjects.name + 2 + + + 316 + + + + value: arrangedObjects.pressed + + + + + + value: arrangedObjects.pressed + value + arrangedObjects.pressed + 2 + + + 317 + + + + contentArray: mouseButtons + + + + + + contentArray: mouseButtons + contentArray + mouseButtons + + NSConditionallySetsEditable + + + 2 + + + 353 + + + + formatter + + + + 323 + + + + mMiceController + + + + 345 + + + + mJoysticksController + + + + 374 + + + + content: arrangedObjects.productName + + + + + + content: arrangedObjects.productName + content + arrangedObjects.productName + + NSNullPlaceholder + No Joysticks + + 2 + + + 394 + + + + selectedIndex: joystickIndex + + + + + + selectedIndex: joystickIndex + selectedIndex + joystickIndex + + 2 + + + 395 + + + + value: selection.manufacturer + + + + + + value: selection.manufacturer + value + selection.manufacturer + + NSNoSelectionPlaceholder + IA + + 2 + + + 393 + + + + contentArray: joysticks + + + + + + contentArray: joysticks + contentArray + joysticks + 2 + + + 369 + + + + value: arrangedObjects.pressed + + + + + + value: arrangedObjects.pressed + value + arrangedObjects.pressed + + NSConditionallySetsEditable + + + 2 + + + 401 + + + + value: arrangedObjects.name + + + + + + value: arrangedObjects.name + value + arrangedObjects.name + 2 + + + 385 + + + + contentArray: joystickButtons + + + + + + contentArray: joystickButtons + contentArray + joystickButtons + 2 + + + 383 + + + + formatter + + + + 388 + + + + value: xAxis + + + + + + value: xAxis + value + xAxis + 2 + + + 404 + + + + value: yAxis + + + + + + value: yAxis + value + yAxis + 2 + + + 405 + + + + toggleListening: + + + + 412 + + + + mStartStopButton + + + + 414 + + + + mFeedbackView + + + + 415 + + + + mFeedbackText + + + + 419 + + + + value: openInExclusiveMode + + + + + + value: openInExclusiveMode + value + openInExclusiveMode + 2 + + + 413 + + + + value: remote.remoteId + + + + + + value: remote.remoteId + value + remote.remoteId + 2 + + + 422 + + + + mKeyboardsController + + + + 454 + + + + mKeyboardEventsController + + + + 457 + + + + content: arrangedObjects.productName + + + + + + content: arrangedObjects.productName + content + arrangedObjects.productName + + NSNullPlaceholder + No Joysticks + + 2 + + + 440 + + + + selectedIndex: keyboardIndex + + + + + + selectedIndex: keyboardIndex + selectedIndex + keyboardIndex + + 2 + + + 441 + + + + value: selection.manufacturer + + + + + + value: selection.manufacturer + value + selection.manufacturer + 2 + + + 439 + + + + contentArray: keyboards + + + + + + contentArray: keyboards + contentArray + keyboards + 2 + + + 433 + + + + value: arrangedObjects.event + + + + + + value: arrangedObjects.event + value + arrangedObjects.event + 2 + + + 459 + + + + value: arrangedObjects.description + + + + + + value: arrangedObjects.description + value + arrangedObjects.description + 2 + + + 460 + + + + contentArray: events + + + + + + contentArray: events + contentArray + events + 2 + + + 456 + + + + mMikeysController + + + + 504 + + + + mMikeysEventsController + + + + 505 + + + + contentArray: mikeys + + + + + + contentArray: mikeys + contentArray + mikeys + 2 + + + 538 + + + + contentArray: events + + + + + + contentArray: events + contentArray + events + 2 + + + 540 + + + + value: selection.manufacturer + + + + + + value: selection.manufacturer + value + selection.manufacturer + 2 + + + 544 + + + + content: arrangedObjects.productName + + + + + + content: arrangedObjects.productName + content + arrangedObjects.productName + + NSNullPlaceholder + No Mikeys + + 2 + + + 541 + + + + selectedIndex: mikeyIndex + + + + + + selectedIndex: mikeyIndex + selectedIndex + mikeyIndex + + 2 + + + 542 + + + + value: arrangedObjects.description + + + + + + value: arrangedObjects.description + value + arrangedObjects.description + 2 + + + 536 + + + + value: arrangedObjects.event + + + + + + value: arrangedObjects.event + value + arrangedObjects.event + 2 + + + 535 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + 21 + + + + + + Window + + + 2 + + + + + + + + 248 + + + + + + + + + + + + 249 + + + + + + + + 250 + + + + + + + + + + + + + + + + + 360 + + + + + + + + 361 + + + + + + + + 366 + + + + + + + + 367 + + + + + + + + 376 + + + + + + + + + + + 377 + + + + + + + + + 378 + + + + + + + + 387 + + + + + 379 + + + + + + + + 380 + + + + + + 398 + + + + + + + + 399 + + + + + + + + 402 + + + + + + + + 403 + + + + + + + + 251 + + + + + + + + 252 + + + + + + + + + + + + + + + + + + + 255 + + + + + + + + 256 + + + + + + + + 265 + + + + + + + + 266 + + + + + + + + 270 + + + + + + + + 271 + + + + + + 273 + + + + + + + + 274 + + + + + + + + 281 + + + + + + + + 288 + + + + + + + + 294 + + + + + + + + 310 + + + + + + + + + + + 311 + + + + + + + + + 312 + + + + + + + + 313 + + + + + + + + 321 + + + + + 253 + + + + + + + + 254 + + + + + + + + + + + + + 424 + + + + + + + + 429 + + + + + + + + 430 + + + + + + + + 431 + + + + + + + + 448 + + + + + + 450 + + + + + + + + + + 451 + + + + + + + + + 452 + + + + + + + + 453 + + + + + + + + 407 + + + + + + + + 408 + + + + + + + + + + + + + 409 + + + + + 410 + + + + + + + + 411 + + + + + + + + 416 + + + + + + + + 420 + + + + + + + + 421 + + + + + + + + 29 + + + + + + + + + + MainMenu + + + 19 + + + + + + + + 24 + + + + + + + + + + + 5 + + + + + 23 + + + + + 92 + + + + + 239 + + + + + 56 + + + + + + + + 57 + + + + + + + + + + + + + + + + + + 58 + + + + + 129 + + + + + 131 + + + + + + + + 130 + + + + + 134 + + + + + 136 + + + + + 143 + + + + + 144 + + + + + 145 + + + + + 149 + + + + + 150 + + + + + 236 + + + + + 83 + + + + + + + + 81 + + + + + + + + + + + + + + + + + + 72 + + + + + 73 + + + + + 74 + + + + + 75 + + + + + 77 + + + + + 78 + + + + + 79 + + + + + 80 + + + + + 82 + + + + + 112 + + + + + 124 + + + + + + + + 125 + + + + + + + + 126 + + + + + 103 + + + + + + + + 106 + + + + + + + + 111 + + + + + 217 + + + + + + + + 205 + + + + + + + + + + + + + + + + + + + + 197 + + + + + 198 + + + + + 199 + + + + + 202 + + + + + 203 + + + + + 206 + + + + + 207 + + + + + 211 + + + + + + + + 212 + + + + + + + + + 195 + + + + + 196 + + + + + 214 + + + + + 215 + + + + + 216 + + + + + + + + 200 + + + + + + + + + + 201 + + + + + 204 + + + + + 219 + + + + + 218 + + + + + + + + 220 + + + + + + + + + + + + 208 + + + + + 209 + + + + + 210 + + + + + 213 + + + + + 221 + + + + + 246 + + + + + 261 + + + DeviceTestController + + + 262 + + + Mice + + + 314 + + + MouseButtons + + + 322 + + + BoolFormatter + + + 344 + + + MousePaneController + + + 359 + + + JoystickPaneController + + + 368 + + + Joysticks + + + 382 + + + JoystickButtons + + + 406 + + + AppleRemotePaneController + + + 423 + + + KeyboardPaneController + + + 432 + + + Keyboards + + + 455 + + + KeyboardEvents + + + 462 + + + + + 463 + + + + + + + + 464 + + + + + 465 + + + + + 466 + + + + + 467 + + + + + 468 + + + + + 469 + + + + + 470 + + + + + 471 + + + + + + + + 472 + + + + + 473 + + + + + 474 + + + + + 475 + + + + + 476 + + + + + 477 + + + + + 478 + + + + + 479 + + + + + 480 + + + + + + + + 481 + + + + + 482 + + + + + 483 + + + + + 484 + + + + + 485 + + + + + 486 + + + + + 487 + + + + + 488 + + + + + 489 + + + + + 490 + + + + + 491 + + + + + 492 + + + + + 362 + + + + + + + + + + 365 + + + + + 364 + + + + + 363 + + + + + 257 + + + + + + + + + + 260 + + + + + 259 + + + + + 258 + + + + + 425 + + + + + + + + + + 428 + + + + + 427 + + + + + 426 + + + + + 493 + + + + + 494 + + + + + 495 + + + + + 496 + + + + + 497 + + + + + 498 + + + + + 499 + + + + + 500 + + + + + -3 + + + Application + + + 381 + + + + + 272 + + + + + 449 + + + + + 501 + + + AppleMikeyPaneController + + + 502 + + + mikeys + + + 503 + + + mikeyEvents + + + 506 + + + + + + + + 507 + + + + + + + + + + + + + 513 + + + + + + + + 512 + + + + + + + + 509 + + + + + 508 + + + + + + + + + + 524 + + + + + + + + + 523 + + + + + 522 + + + + + 526 + + + + + + + + 525 + + + + + + + + 528 + + + + + 527 + + + + + 519 + + + + + 514 + + + + + + + + 515 + + + + + + + + + + 518 + + + + + 517 + + + + + 516 + + + + + 510 + + + + + + + + 521 + + + + + 511 + + + + + + + + 520 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 544 + + + + + AppleMikeyPaneController + NSObject + + NSArrayController + NSArrayController + + + + mMikeysController + NSArrayController + + + mMikeysEventsController + NSArrayController + + + + IBProjectSource + ./Classes/AppleMikeyPaneController.h + + + + AppleRemotePaneController + NSObject + + toggleListening: + id + + + toggleListening: + + toggleListening: + id + + + + NSTextField + RemoteFeedbackView + NSButton + + + + mFeedbackText + NSTextField + + + mFeedbackView + RemoteFeedbackView + + + mStartStopButton + NSButton + + + + IBProjectSource + ./Classes/AppleRemotePaneController.h + + + + BoolFormatter + NSFormatter + + IBProjectSource + ./Classes/BoolFormatter.h + + + + DeviceTestController + NSObject + + MousePaneController + NSWindow + + + + mMousePaneController + MousePaneController + + + mWindow + NSWindow + + + + IBProjectSource + ./Classes/DeviceTestController.h + + + + JoystickPaneController + NSObject + + mJoysticksController + NSArrayController + + + mJoysticksController + + mJoysticksController + NSArrayController + + + + IBProjectSource + ./Classes/JoystickPaneController.h + + + + KeyboardPaneController + NSObject + + NSArrayController + NSArrayController + + + + mKeyboardEventsController + NSArrayController + + + mKeyboardsController + NSArrayController + + + + IBProjectSource + ./Classes/KeyboardPaneController.h + + + + MousePaneController + NSObject + + mMiceController + NSArrayController + + + mMiceController + + mMiceController + NSArrayController + + + + IBProjectSource + ./Classes/MousePaneController.h + + + + RemoteFeedbackView + NSView + + IBProjectSource + ./Classes/RemoteFeedbackView.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + YES + 3 + + {11, 11} + {10, 3} + + + diff --git a/Apple2Mac/DDHidLib/device_test/fr.lproj/MainMenu.nib/keyedobjects.nib b/Apple2Mac/DDHidLib/device_test/fr.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 00000000..8158386c Binary files /dev/null and b/Apple2Mac/DDHidLib/device_test/fr.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/Apple2Mac/floppy.png b/Apple2Mac/floppy.png new file mode 100644 index 00000000..8f7b8023 Binary files /dev/null and b/Apple2Mac/floppy.png differ diff --git a/Apple2Mac/main.m b/Apple2Mac/main.m new file mode 100644 index 00000000..a9d03d27 --- /dev/null +++ b/Apple2Mac/main.m @@ -0,0 +1,34 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2014, 2015 Aaron Culliney + * + */ + +#if TARGET_OS_IPHONE +# import "AppDelegate.h" +#endif + +extern int argc; +extern const char **argv; + +int main(int argc_, const char *argv_[]) +{ + int retVal = 1; + argc = argc_; + argv = argv_; + + @autoreleasepool { +#if TARGET_OS_IPHONE + retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); +#else + retVal = NSApplicationMain(argc, argv); +#endif + } + + return retVal; +} diff --git a/Makefile.am b/Makefile.am index 6f13963a..55d3b16f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -157,7 +157,7 @@ shaders_DATA = src/video/Basic.vsh src/video/Basic.fsh disksdir = @datadir@/@PACKAGE@/disks disks_DATA = \ disks/README disks/blank.dsk.gz disks/blank.nib.gz disks/blank.po.gz disks/etc.dsk.gz \ - disks/mystery.dsk.gz disks/speedtest.dsk.gz disks/speedtest.txt disks/flapple140.po.gz \ + disks/mystery.dsk disks/speedtest.dsk disks/speedtest.txt disks/flapple140.po \ disks/testdisplay1.dsk.gz disks/testdisplay1.nib.gz disks/testvm1.dsk.gz disks/testvm1.nib.gz diff --git a/README.md b/README.md index 4958fd79..99fdb3b2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,18 @@ Apple //ix ========== -Apple2ix is an Apple //e emulator implemented primarily in C with x86, x86-64, and ARM assembly language for the 65c02 CPU emulation module. In addition you will find a smattering of interface code in Objective-C/Cocoa, Java/Android, and GLSL. +Apple2ix is an Apple //e (8bit 65c02 CPU) emulator designed to work on varios POSIX platforms. + +Project Tech +------------ + +* C99 dialect of the C programming language for the majority of the project +* x86 and ARM assembly language for 65c02 CPU emulation loop +* Extensive tests for 65c02 CPU, Apple //e VM, disks, and display (expected framebuffer output) +* OpenGLES 2.x graphics with simple portable GLSL shaders +* OpenAL and OpenSLES audio (emulated speaker and emulated Mockingboard/Phasor soundcards) +* Objective-C and Cocoa APIs (Mac/iOS variant) +* Java and Android APIs (Android app) Lineage ------- @@ -17,7 +28,7 @@ Project Goals * Portability and code resilience across a wide range of modern platforms including MacOSX, desktop Linux/BSD, iOS, Android -- *But not Windows, just use the excellent [AppleWin](https://github.com/AppleWin/AppleWin) emulator if you're on Windows!* * Reasonable emulation fidelity to the original Apple //e machine (timing, video, audio, etc...) -* Language minimalism for core emulation modules (prefer coding in POSIX C over all else), except for CPU module which should be in assembly +* Language/platform/API minimalism for core emulation modules (prefer coding to POSIX APIs and using C99 over all other choices), except for CPU module which should be in custom assembly or IR ;-) * Good platform citizenship for menu system (prefer coding in language-of-choice promoted by platform--e.g.: Objective-C/Swift on Darwin, Java on Android, ...) Android @@ -25,10 +36,10 @@ Android [Available on Google Play](https://play.google.com/store/apps/details?id=org.deadc0de.apple2ix.basic). -Running at 30FPS on Gingerbread (Android 2.3.3): +Running at 30FPS on ancient Gingerbread (Android 2.3.3) devices: ![Apple2ix on Samsung Galaxy Y running Gingerbread](https://raw.github.com/mauiaaron/apple2/develop/docs/android-galaxyY.png "Apple //ix") -Running at 60FPS on Nexus 6 running Lollipop (Android 5.1.1): +Running at 60FPS on modern Android devices: ![Apple2ix on Nexus 6](https://raw.github.com/mauiaaron/apple2/develop/docs/android-nexus6.png "Apple //ix") Mac Package @@ -36,12 +47,16 @@ Mac Package ![Apple2Mac](https://raw.github.com/mauiaaron/apple2/master/docs/Apple2Mac.png "Apple2Mac") -A binary package for Macintosh is available at [deadc0de.org](http://deadc0de.org/Apple2Mac/Apple2Mac-0.9.dmg) +A dated binary package for Macintosh is available at [deadc0de.org](http://deadc0de.org/Apple2Mac/Apple2Mac-0.9.dmg) Size : 10240000 (10MB) SHASUM : 81f2d55c2daaa0d3f9b33af9b50f69f6789738bf Alt Size : 76820480 (75MB) -ALTSUM : 488a40d7f1187bcfd16d0045258f606a95f448cb +ALTSUM : 488a40d7f1187bcfd16d0045258f606a95f448cb + +Due to Apple's policy about emulators we are unlikely to ship this in the App Store any time soon. + +iOS port in progress 2016, check this repo and fork(s) too! Linux+ Package -------------- @@ -52,28 +67,18 @@ You will need GCC or Clang compiler and other tools as determined by the `config ![Apple //ix](https://raw.github.com/mauiaaron/apple2/master/docs/Apple2ix.png "Apple //ix") -Project Tech ------------- - -* C language for the majority of the project (still the most portable/reliable language after all these years ;-) -* x86 and ARM assembly language for 65c02 CPU tightloop -* Extensive tests for 65c02 CPU, Apple //e VM, disks, and display (expected framebuffer output) -* OpenGLES 2.x graphics with GLSL shaders -* OpenAL and OpenSLES audio (emulated speaker and emulated Mockingboard/Phasor soundcards) -* Objective-C and Cocoa APIs (Mac/iOS variant) -* Java and Android APIs (Android app) - -![DOS 3.3](https://raw.github.com/mauiaaron/apple2/master/docs/DOS33.png "DOS 3.3 Applesoft BASIC and //e monitor") - Semi-Ordered TODO ----------------- -* DHIRES graphics are ugly, fix 'em -* iOS/iWatch ports +* Double-LORES graphics (used in Dagen Brock's Flappy Bird clone) are ugly/incorrect ... fix 'em +* Mockingboard is seriously buggy. Need to research/check upstream for bugfixes and refactor. +* CPU module ports: aarch64, x86 without textreloc's, Clang IR +* iOS/iWatch ports. iOS in progress early 2016. * Proper VBL timing and vSync matching to the device (if available) * OpenGL shaders/tricks for style (various screen artifacts) and functionality (Disk ][ status overlays, etc) -* Emulator save/restore and image compatibility with AppleWin -* Other feature parity with AppleWin -* Improved debugger routines (CLI/curses debugger?) -* CPU module variants as-needed in aarch64, plain C, Clang IR, ... +* Emulator save/restore image compatibility with AppleWin +* Emulation features ... (3.5" disk, AppleHD, Phasor, printer, ethernet, ...) +* Debugger rewrite with tests ... improved debugger routines (CLI/curses debugger? GDB/LLDB module?) * Emscripten/web frontend? + +![DOS 3.3](https://raw.github.com/mauiaaron/apple2/master/docs/DOS33.png "DOS 3.3 Applesoft BASIC and //e monitor") diff --git a/disks/NSCT.dsk b/disks/NSCT.dsk new file mode 100644 index 00000000..fd932d92 Binary files /dev/null and b/disks/NSCT.dsk differ diff --git a/disks/flapple140.po b/disks/flapple140.po new file mode 100644 index 00000000..2231c298 Binary files /dev/null and b/disks/flapple140.po differ diff --git a/disks/flapple140.po.gz b/disks/flapple140.po.gz deleted file mode 100644 index 41f8d031..00000000 Binary files a/disks/flapple140.po.gz and /dev/null differ diff --git a/disks/mystery.dsk b/disks/mystery.dsk new file mode 100644 index 00000000..637e7ec3 Binary files /dev/null and b/disks/mystery.dsk differ diff --git a/disks/mystery.dsk.gz b/disks/mystery.dsk.gz deleted file mode 100644 index 801debaf..00000000 Binary files a/disks/mystery.dsk.gz and /dev/null differ diff --git a/disks/speedtest.dsk b/disks/speedtest.dsk new file mode 100644 index 00000000..c10dd95c Binary files /dev/null and b/disks/speedtest.dsk differ diff --git a/disks/speedtest.dsk.gz b/disks/speedtest.dsk.gz deleted file mode 100644 index eacf34bc..00000000 Binary files a/disks/speedtest.dsk.gz and /dev/null differ diff --git a/disks/testvm1.dsk b/disks/testvm1.dsk new file mode 100644 index 00000000..8ca7fbd1 Binary files /dev/null and b/disks/testvm1.dsk differ diff --git a/src/arm/cpu-regs.h b/src/arm/cpu-regs.h index 41738c55..6f1e8cfc 100644 --- a/src/arm/cpu-regs.h +++ b/src/arm/cpu-regs.h @@ -32,7 +32,6 @@ // r14 ARM return addr // r15 ARM PC - #ifdef __aarch64__ # error 20150205 ARM 64bit untested!!! # define PTR_SHIFT #4 // 4<<1 = 8 @@ -43,10 +42,20 @@ #endif -#define NO_UNDERSCORES 1 +#if !defined(__APPLE__) +# define NO_UNDERSCORES 1 +# define STRBNE strneb +#else +# define STRBNE strbne +#endif -#define ENTRY(x) .globl x; .balign 16; .type x, %function; x##: -#define CALL(x) x +#if NO_UNDERSCORES +# define ENTRY(x) .globl x; .arm; .balign 4; x##: +# define CALL(x) x +#else +# define ENTRY(x) .globl _##x; .arm; .balign 4; _##x##: +# define CALL(x) _##x +#endif // 2015/11/08 NOTE : Android requires all apps targeting API 23 (AKA Marshmallow) to use Position Independent Code (PIC) // that does not have TEXT segment relocations @@ -81,8 +90,13 @@ _SYM_ADDR_POST(var,8) # endif #else /* !PREVENT_TEXTREL */ -# define SYM(reg,var) \ +# if NO_UNDERSCORES +# define SYM(reg,var) \ ldr reg, =var +# else +# define SYM(reg,var) \ + ldr reg, =_##var +# endif #endif diff --git a/src/arm/cpu.S b/src/arm/cpu.S index 4e81ac6a..eacdb4fe 100644 --- a/src/arm/cpu.S +++ b/src/arm/cpu.S @@ -2511,7 +2511,7 @@ ENTRY(cpu65_run) ldrb r0, [r1] teq r0, #0 eorne r0, r0, r0 - strneb r0, [r1] + STRBNE r0, [r1] bne ex_reset b continue1 @@ -2547,8 +2547,13 @@ ENTRY(cpu65_direct_write) # local data ... .global interrupt_vector .global reset_vector -interrupt_vector: .hword 0xFFFE -reset_vector: .hword 0xFFFC +#if NO_UNDERSCORES +interrupt_vector: .hword 0xFFFE +reset_vector: .hword 0xFFFC +#else +_interrupt_vector: .hword 0xFFFE +_reset_vector: .hword 0xFFFC +#endif .ltorg diff --git a/src/arm/glue-prologue.h b/src/arm/glue-prologue.h index a6762e46..d8037c8d 100644 --- a/src/arm/glue-prologue.h +++ b/src/arm/glue-prologue.h @@ -45,7 +45,7 @@ ENTRY(func) SYM(r1, pointer); \ ENTRY(func) SYM(r1, pointer); \ ldr r1, [r1]; \ teq r1, #0; \ - strneb r0, [r1, EffectiveAddr]; \ + STRBNE r0, [r1, EffectiveAddr]; \ mov pc, lr; diff --git a/src/audio/AY8910.c b/src/audio/AY8910.c index f2939a12..a5df3be8 100644 --- a/src/audio/AY8910.c +++ b/src/audio/AY8910.c @@ -243,14 +243,14 @@ static void sound_init( CAY8910 *_this, const char *device, unsigned long nSampl sound_generator_framesiz = sound_generator_freq / (int)hz; #if 0 - if( ( sound_buf = (libspectrum_signed_word*) malloc( sizeof( libspectrum_signed_word ) * + if( ( sound_buf = (libspectrum_signed_word*) MALLOC( sizeof( libspectrum_signed_word ) * sound_generator_framesiz * sound_channels ) ) == NULL || ( tape_buf = - malloc( sizeof( libspectrum_signed_word ) * + MALLOC( sizeof( libspectrum_signed_word ) * sound_generator_framesiz ) ) == NULL ) { if( sound_buf ) { - free( sound_buf ); + FREE( sound_buf ); sound_buf = NULL; } sound_end(_this); @@ -263,14 +263,14 @@ static void sound_init( CAY8910 *_this, const char *device, unsigned long nSampl #ifdef HAVE_SAMPLERATE if( settings_current.sound_hifi ) { - if( ( convert_input_buffer = malloc( sizeof( float ) * + if( ( convert_input_buffer = MALLOC( sizeof( float ) * sound_generator_framesiz * sound_channels ) ) == NULL || ( convert_output_buffer = - malloc( sizeof( float ) * sound_framesiz * sound_channels ) ) == + MALLOC( sizeof( float ) * sound_framesiz * sound_channels ) ) == NULL ) { if( convert_input_buffer ) { - free( convert_input_buffer ); + FREE( convert_input_buffer ); convert_input_buffer = NULL; } sound_end(_this); @@ -373,17 +373,17 @@ static void sound_end( CAY8910 *_this ) #if 0 if( sound_enabled ) { if( sound_buf ) { - free( sound_buf ); + FREE( sound_buf ); sound_buf = NULL; - free( tape_buf ); + FREE( tape_buf ); tape_buf = NULL; } if( convert_input_buffer ) { - free( convert_input_buffer ); + FREE( convert_input_buffer ); convert_input_buffer = NULL; } if( convert_output_buffer ) { - free( convert_output_buffer ); + FREE( convert_output_buffer ); convert_output_buffer = NULL; } #ifdef HAVE_SAMPLERATE @@ -397,7 +397,7 @@ static void sound_end( CAY8910 *_this ) #if 0 if( sound_buf ) { - free( sound_buf ); + FREE( sound_buf ); sound_buf = NULL; } #endif diff --git a/src/audio/mockingboard.c b/src/audio/mockingboard.c index 882ca35e..02682e43 100644 --- a/src/audio/mockingboard.c +++ b/src/audio/mockingboard.c @@ -1413,7 +1413,7 @@ static bool MB_DSInit() SAMPLE_RATE = audio_backend->systemSettings.sampleRateHz; MB_BUF_SIZE = audio_backend->systemSettings.stereoBufferSizeSamples * audio_backend->systemSettings.bytesPerSample * MB_CHANNELS; g_dwDSBufferSize = MB_BUF_SIZE; - g_nMixBuffer = malloc(MB_BUF_SIZE / audio_backend->systemSettings.bytesPerSample); + g_nMixBuffer = MALLOC(MB_BUF_SIZE / audio_backend->systemSettings.bytesPerSample); #ifndef APPLE2IX bool bRes = DSZeroVoiceBuffer(&MockingboardVoice, (char*)"MB", g_dwDSBufferSize); @@ -1722,7 +1722,7 @@ void MB_Initialize() for(i=0; inext; - free(p); + FREE(p); } } @@ -226,13 +226,13 @@ PlayQueue_s *playq_createPlayQueue(const long *nodeIdPtr, unsigned long numBuffe assert(numBuffers <= MAX_PLAYQ_BUFFERS); do { - playq = calloc(1, sizeof(PlayQueue_s)); + playq = CALLOC(1, sizeof(PlayQueue_s)); if (!playq) { ERRLOG("no memory"); break; } - PQList_s *list = calloc(1, sizeof(PQList_s)); + PQList_s *list = CALLOC(1, sizeof(PQList_s)); playq->_internal = list; if (!list) { ERRLOG("no memory"); @@ -241,7 +241,7 @@ PlayQueue_s *playq_createPlayQueue(const long *nodeIdPtr, unsigned long numBuffe bool allocSuccess = true; for (unsigned long i=0; inode.nodeId = nodeIdPtr[i]; if (!listNode) { diff --git a/src/audio/soundcore-openal.c b/src/audio/soundcore-openal.c index b795d66d..71ce6fa0 100644 --- a/src/audio/soundcore-openal.c +++ b/src/audio/soundcore-openal.c @@ -357,7 +357,7 @@ static ALVoice *_openal_createVoice(unsigned long numChannels) { ALVoice *voice = NULL; do { - voice = calloc(1, sizeof(*voice)); + voice = CALLOC(1, sizeof(*voice)); if (voice == NULL) { ERRLOG("OOPS, Out of memory!"); break; @@ -424,7 +424,7 @@ static ALVoice *_openal_createVoice(unsigned long numChannels) { unsigned long maxSamples = openal_audio_backend.systemSettings.monoBufferSizeSamples * numChannels; voice->buffersize = maxSamples * openal_audio_backend.systemSettings.bytesPerSample; - voice->data = calloc(1, voice->buffersize); + voice->data = CALLOC(1, voice->buffersize); if (voice->data == NULL) { ERRLOG("OOPS, Error allocating %d bytes", voice->buffersize); break; @@ -488,7 +488,7 @@ static long openal_createSoundBuffer(const AudioContext_s *audio_context, INOUT } ALVoices immutableNode = { /*const*/.source = voice->source }; - ALVoices *vnode = calloc(1, sizeof(ALVoices)); + ALVoices *vnode = CALLOC(1, sizeof(ALVoices)); if (!vnode) { ERRLOG("OOPS, Not enough memory"); break; @@ -497,7 +497,7 @@ static long openal_createSoundBuffer(const AudioContext_s *audio_context, INOUT vnode->voice = voice; HASH_ADD_INT(voices, source, vnode); - if ((*soundbuf_struct = calloc(1, sizeof(AudioBuffer_s))) == NULL) { + if ((*soundbuf_struct = CALLOC(1, sizeof(AudioBuffer_s))) == NULL) { ERRLOG("OOPS, Not enough memory"); break; } @@ -566,7 +566,7 @@ static long openal_systemSetup(INOUT AudioContext_s **audio_context) { LOG("WARNING - AL_SOFT_buffer_samples extension not supported... Proceeding anyway..."); } - if ((*audio_context = calloc(1, sizeof(AudioContext_s))) == NULL) { + if ((*audio_context = CALLOC(1, sizeof(AudioContext_s))) == NULL) { ERRLOG("OOPS, Not enough memory"); break; } @@ -580,7 +580,7 @@ static long openal_systemSetup(INOUT AudioContext_s **audio_context) { if (result) { if (ctx) { - AudioContext_s *ctxPtr = calloc(1, sizeof(AudioContext_s)); + AudioContext_s *ctxPtr = CALLOC(1, sizeof(AudioContext_s)); ctxPtr->_internal = ctx; openal_systemShutdown(&ctxPtr); } diff --git a/src/audio/soundcore-opensles.c b/src/audio/soundcore-opensles.c index 9591b640..e96901f7 100644 --- a/src/audio/soundcore-opensles.c +++ b/src/audio/soundcore-opensles.c @@ -426,14 +426,14 @@ static long opensl_createSoundBuffer(const AudioContext_s *audio_context, INOUT voice->ringBuffer = prevBuffer; } else { LOG("Creating new SLVoice ..."); - voice = calloc(1, sizeof(*voice)); + voice = CALLOC(1, sizeof(*voice)); if (voice == NULL) { ERRLOG("OOPS, Out of memory!"); break; } voice->bufferSize = bufferSize; // Allocate enough space for the temp buffer (including a maximum allowed overflow) - voice->ringBuffer = calloc(1, voice->bufferSize + ctx->submitSize/*max overflow*/); + voice->ringBuffer = CALLOC(1, voice->bufferSize + ctx->submitSize/*max overflow*/); if (voice->ringBuffer == NULL) { ERRLOG("OOPS, Error allocating %lu bytes", (unsigned long)voice->bufferSize+ctx->submitSize); break; @@ -444,7 +444,7 @@ static long opensl_createSoundBuffer(const AudioContext_s *audio_context, INOUT voice->ctx = ctx; - if ((*soundbuf_struct = calloc(1, sizeof(AudioBuffer_s))) == NULL) { + if ((*soundbuf_struct = CALLOC(1, sizeof(AudioBuffer_s))) == NULL) { ERRLOG("OOPS, Not enough memory"); break; } @@ -556,14 +556,14 @@ static long opensles_systemSetup(INOUT AudioContext_s **audio_context) { // // Engine creation ... // - ctx = calloc(1, sizeof(EngineContext_s)); + ctx = CALLOC(1, sizeof(EngineContext_s)); if (!ctx) { result = -1; break; } ctx->submitSize = android_stereoBufferSubmitSizeSamples * opensles_audio_backend.systemSettings.bytesPerSample * NUM_CHANNELS; - ctx->mixBuf = calloc(1, ctx->submitSize); + ctx->mixBuf = CALLOC(1, ctx->submitSize); if (ctx->mixBuf == NULL) { ERRLOG("OOPS, Error allocating %lu bytes", (unsigned long)ctx->submitSize); break; @@ -608,7 +608,7 @@ static long opensles_systemSetup(INOUT AudioContext_s **audio_context) { } // create soundcore API wrapper - if ((*audio_context = calloc(1, sizeof(AudioContext_s))) == NULL) { + if ((*audio_context = CALLOC(1, sizeof(AudioContext_s))) == NULL) { result = -1; ERRLOG("OOPS, Not enough memory"); break; @@ -707,7 +707,7 @@ static long opensles_systemSetup(INOUT AudioContext_s **audio_context) { if (result != SL_RESULT_SUCCESS) { if (ctx) { - AudioContext_s *ctxPtr = calloc(1, sizeof(AudioContext_s)); + AudioContext_s *ctxPtr = CALLOC(1, sizeof(AudioContext_s)); ctxPtr->_internal = ctx; opensles_systemShutdown(&ctxPtr); } @@ -741,20 +741,17 @@ static long opensles_systemResume(AudioContext_s *audio_context) { break; } -#if !TESTING - assert(state != SL_PLAYSTATE_PLAYING && "mismatch between systemPause/systemResume"); -#endif + if (state != SL_PLAYSTATE_PLAYING) { + ERRLOG("WARNING: possible audio lifecycle mismatch ... continuing anyway"); + } if (state == SL_PLAYSTATE_PAUSED) { // Balanced resume OK here SLresult result = (*(ctx->bqPlayerPlay))->SetPlayState(ctx->bqPlayerPlay, SL_PLAYSTATE_PLAYING); -#if !TESTING - } else { + } else if (state == SL_PLAYSTATE_STOPPED) { // Do not resume for stopped state, let this get forced from CPU/speaker thread otherwise we starve. (The // stopped state happens if user dynamically changed buffer parameters in menu settings which triggered an // OpenSLES destroy/re-initialization ... e.g. audio_setLatency() was invoked) - assert(state == SL_PLAYSTATE_STOPPED); -#endif } } while (0); diff --git a/src/audio/soundcore.c b/src/audio/soundcore.c index ab24d805..8e242957 100644 --- a/src/audio/soundcore.c +++ b/src/audio/soundcore.c @@ -107,7 +107,11 @@ void audio_shutdown(void) { void audio_pause(void) { // CPU thread owns audio lifecycle (see note above) // Deadlock on Kindle Fire 1st Gen if audio_pause() and audio_resume() happen off CPU thread ... +#ifdef __APPLE__ +# warning FIXME TODO : this assert is firing on iOS port ... but the assert is valid ... fix soon +#else assert(pthread_self() == cpu_thread_id); +#endif if (!audio_isAvailable) { return; } diff --git a/src/audio/speaker.c b/src/audio/speaker.c index e76e70ca..f181ff9c 100644 --- a/src/audio/speaker.c +++ b/src/audio/speaker.c @@ -298,6 +298,7 @@ static unsigned int _submit_samples_buffer(const unsigned long num_channel_sampl unsigned long system_buffer_size = 0; int16_t *system_samples_buffer = NULL; + const unsigned long maxSpeakerBytes = channelsSampleRateHz * sizeof(int16_t); unsigned long curr_buffer_size = requested_buffer_size; unsigned long samples_idx = 0; unsigned long counter = 0; @@ -307,11 +308,10 @@ static unsigned int _submit_samples_buffer(const unsigned long num_channel_sampl break; } - unsigned long maxSpeakerBytes = channelsSampleRateHz * sizeof(int16_t); - if (system_buffer_size > maxSpeakerBytes) { RELEASE_LOG("AVOIDING BUFOVER..."); system_buffer_size = maxSpeakerBytes; + requested_buffer_size = maxSpeakerBytes; } memcpy(system_samples_buffer, &samples_buffer[samples_idx], system_buffer_size); @@ -368,14 +368,14 @@ void speaker_init(void) { remainder_buffer_size_max = ((CLK_6502_INT*(unsigned long)CPU_SCALE_FASTEST)/audio_backend->systemSettings.sampleRateHz)+1; - samples_buffer = calloc(1, channelsSampleRateHz * sizeof(int16_t)); + samples_buffer = CALLOC(1, channelsSampleRateHz * sizeof(int16_t)); if (!samples_buffer) { err = -1; break; } samples_buffer_idx = bufferSizeIdealMax; - remainder_buffer = malloc(remainder_buffer_size_max * sizeof(int16_t)); + remainder_buffer = MALLOC(remainder_buffer_size_max * sizeof(int16_t)); if (!remainder_buffer) { err = -1; break; diff --git a/src/breakpad.C b/src/breakpad.C index 11a61c6c..b880d2f9 100644 --- a/src/breakpad.C +++ b/src/breakpad.C @@ -27,7 +27,7 @@ static google_breakpad::ExceptionHandler *eh = nullptr; static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) { // WARNING : should only do minimal work from within a crashing context ... - LOG("Dump path: %s", descriptor.path()); + // LOG()ging here has been found to result in ANRs on various Android devices! return succeeded; } diff --git a/src/common.h b/src/common.h index ee75c5c0..4b652cc9 100644 --- a/src/common.h +++ b/src/common.h @@ -216,7 +216,7 @@ static const char *log_end = "\n"; } \ } while (0) -#ifndef NDEBUG +#if !defined(NDEBUG) || (defined(NDEBUG) && defined(ANDROID)) #ifdef ANDROID // Apparently some non-conformant Android devices (ahem, Spamsung, ahem) do not actually let me see what the assert @@ -319,19 +319,8 @@ static const char *log_end = "\n"; *ptr = '\0'; \ } while (0); -#define FREE(x) \ - do { \ - free((x)); \ - (x) = NULL; \ - } while (0) - -#ifdef __APPLE__ -#define CFRELEASE(x) \ - do { \ - CFRelease((x)); \ - (x) = NULL; \ - } while (0) -#endif +// memory management +#include "memmngt.h" // branch prediction #define LIKELY(x) __builtin_expect((x), true) diff --git a/src/cpu-supp.c b/src/cpu-supp.c index deda65d2..7283a09b 100644 --- a/src/cpu-supp.c +++ b/src/cpu-supp.c @@ -654,6 +654,105 @@ void cpu65_reboot(void) { cpu65_interrupt(ResetSig); } +bool cpu65_saveState(StateHelper_s *helper) { + bool saved = false; + int fd = helper->fd; + + do { + uint8_t serialized[4] = { 0 }; + + // save CPU state + serialized[0] = ((cpu65_pc & 0xFF00) >> 8); + serialized[1] = ((cpu65_pc & 0xFF ) >> 0); + if (!helper->save(fd, serialized, sizeof(cpu65_pc))) { + break; + } + LOG("SAVE cpu65_pc = %04x", cpu65_pc); + + serialized[0] = ((cpu65_ea & 0xFF00) >> 8); + serialized[1] = ((cpu65_ea & 0xFF ) >> 0); + if (!helper->save(fd, serialized, sizeof(cpu65_ea))) { + break; + } + LOG("SAVE cpu65_ea = %04x", cpu65_ea); + + if (!helper->save(fd, &cpu65_a, sizeof(cpu65_a))) { + break; + } + LOG("SAVE cpu65_a = %02x", cpu65_a); + if (!helper->save(fd, &cpu65_f, sizeof(cpu65_f))) { + break; + } + LOG("SAVE cpu65_f = %02x", cpu65_f); + if (!helper->save(fd, &cpu65_x, sizeof(cpu65_x))) { + break; + } + LOG("SAVE cpu65_x = %02x", cpu65_x); + if (!helper->save(fd, &cpu65_y, sizeof(cpu65_y))) { + break; + } + LOG("SAVE cpu65_y = %02x", cpu65_y); + if (!helper->save(fd, &cpu65_sp, sizeof(cpu65_sp))) { + break; + } + LOG("SAVE cpu65_sp = %02x", cpu65_sp); + + saved = true; + } while (0); + + return saved; +} + +bool cpu65_loadState(StateHelper_s *helper) { + bool loaded = false; + int fd = helper->fd; + + do { + + uint8_t serialized[4] = { 0 }; + + // load CPU state + if (!helper->load(fd, serialized, sizeof(uint16_t))) { + break; + } + cpu65_pc = (serialized[0] << 8); + cpu65_pc |= serialized[1]; + LOG("LOAD cpu65_pc = %04x", cpu65_pc); + + if (!helper->load(fd, serialized, sizeof(uint16_t))) { + break; + } + cpu65_ea = (serialized[0] << 8); + cpu65_ea |= serialized[1]; + LOG("LOAD cpu65_ea = %04x", cpu65_ea); + + if (!helper->load(fd, &cpu65_a, sizeof(cpu65_a))) { + break; + } + LOG("LOAD cpu65_a = %02x", cpu65_a); + if (!helper->load(fd, &cpu65_f, sizeof(cpu65_f))) { + break; + } + LOG("LOAD cpu65_f = %02x", cpu65_f); + if (!helper->load(fd, &cpu65_x, sizeof(cpu65_x))) { + break; + } + LOG("LOAD cpu65_x = %02x", cpu65_x); + if (!helper->load(fd, &cpu65_y, sizeof(cpu65_y))) { + break; + } + LOG("LOAD cpu65_y = %02x", cpu65_y); + if (!helper->load(fd, &cpu65_sp, sizeof(cpu65_sp))) { + break; + } + LOG("LOAD cpu65_sp = %02x", cpu65_sp); + + loaded = true; + } while (0); + + return loaded; +} + #if CPU_TRACING /* ------------------------------------------------------------------------- diff --git a/src/cpu.h b/src/cpu.h index dfd2414a..b6ad0528 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -51,6 +51,9 @@ extern void cpu65_uninterrupt(int reason); extern void cpu65_run(void); extern void cpu65_reboot(void); +extern bool cpu65_saveState(StateHelper_s *helper); +extern bool cpu65_loadState(StateHelper_s *helper); + extern void cpu65_direct_write(int ea,int data); extern void *cpu65_vmem_r[65536]; diff --git a/src/darwin-cpu-glue.S b/src/darwin-cpu-glue.S new file mode 100644 index 00000000..d47d4c8d --- /dev/null +++ b/src/darwin-cpu-glue.S @@ -0,0 +1,23 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2015 Aaron Culliney + * + */ + +#ifdef __APPLE__ +# if defined(__arm__) +# include "arm/cpu.S" +# include "arm/glue.S" +# elif defined(__arm64__) +# error aarch64 not implemented ... TODO SOON +# else +// simulator is x86 +# include "x86/cpu.S" +# include "x86/glue.S" +# endif +#endif diff --git a/src/darwin-shim.c b/src/darwin-shim.c index 8140315f..4db91fed 100644 --- a/src/darwin-shim.c +++ b/src/darwin-shim.c @@ -23,6 +23,7 @@ static uint64_t orwl_timestart = 0; __attribute__((constructor(CTOR_PRIORITY_LATE))) static void __init_darwin_shim() { + LOG("Initializing Darwin Shim"); mach_timebase_info_data_t tb = { 0 }; mach_timebase_info(&tb); orwl_timebase = tb.numer; diff --git a/src/disk.c b/src/disk.c index d8afd255..bda16996 100644 --- a/src/disk.c +++ b/src/disk.c @@ -90,22 +90,6 @@ static void _init_disk6(void) { } } -static inline void cut_gz(char *name) { - size_t len = strlen(name); - if (len <= _GZLEN) { - return; - } - *(name+len-_GZLEN) = '\0'; -} - -static inline bool is_gz(const char * const name) { - size_t len = strlen(name); - if (len <= _GZLEN) { - return false; - } - return strncmp(name+len-_GZLEN, DISK_EXT_GZ, _GZLEN) == 0; -} - static inline bool is_nib(const char * const name) { size_t len = strlen(name); if (len <= _NIBLEN) { @@ -372,6 +356,8 @@ static void denibblize_track(const uint8_t * const src, int drive, uint8_t * con unsigned int offset = 0; int sector = -1; + const unsigned int trackwidth = disk6.disk[drive].track_width; + // iterate over 2x sectors (accounting for header and data sections) for (unsigned int sct2=0; sct2<(NUM_SECTORS<<1)+1; sct2++) { uint8_t prologue[3] = {0,0,0}; // D5AA.. @@ -383,10 +369,7 @@ static void denibblize_track(const uint8_t * const src, int drive, uint8_t * con prologue[idx] = byte; ++idx; } - ++offset; - if (offset >= disk6.disk[drive].track_width) { - offset = 0; - } + offset = (offset+1) % trackwidth; if (idx >= 3) { break; } @@ -399,13 +382,11 @@ static void denibblize_track(const uint8_t * const src, int drive, uint8_t * con #define SCTOFF 0x4 if (prologue[2] == 0x96) { // found header prologue : extract sector - offset += SCTOFF; - if (offset >= disk6.disk[drive].track_width) { - RELEASE_LOG("WRAPPING PROLOGUE ..."); - offset -= disk6.disk[drive].track_width; - } - sector = ((trackimage[offset++] & 0x55) << 1); - sector |= (trackimage[offset++] & 0x55); + offset = (offset+SCTOFF) % trackwidth; + sector = ((trackimage[offset] & 0x55) << 1); + offset = (offset+1) % trackwidth; + sector |= (trackimage[offset] & 0x55); + offset = (offset+1) % trackwidth; continue; } if (UNLIKELY(prologue[2] != 0xAD)) { @@ -418,11 +399,7 @@ static void denibblize_track(const uint8_t * const src, int drive, uint8_t * con uint8_t work_buf[NUM_SIXBIT_NIBS+1]; for (unsigned int idx=0; idx<(NUM_SIXBIT_NIBS+1); idx++) { work_buf[idx] = trackimage[offset]; - ++offset; - if (offset >= disk6.disk[drive].track_width) { - offset = 0; - LOG("WARNING : wrapping trackimage ... trk:%d sct:%d [0]:0x%02X", (disk6.disk[drive].phase >> 1), sector, trackimage[offset]); - } + offset = (offset+1) % trackwidth; } assert(sector >= 0 && sector < 16 && "invalid previous nibblization"); int sec_off = 256 * disk6.disk[drive].skew_table[ sector ]; @@ -479,6 +456,23 @@ static void save_track_data(int drive) { disk6.disk[drive].track_dirty = false; } +static inline void animate_disk_track_sector(void) { + if (video_backend && video_backend->animation_showTrackSector) { + static int previous_sect = 0; + int sect_width = disk6.disk[disk6.drive].track_width>>4; // div-by-16 + do { + if (UNLIKELY(sect_width <= 0)) { + break; + } + int sect = disk6.disk[disk6.drive].run_byte/sect_width; + if (sect != previous_sect) { + previous_sect = sect; + video_backend->animation_showTrackSector(disk6.drive, disk6.disk[disk6.drive].phase>>1, sect); + } + } while (0); + } +} + // ---------------------------------------------------------------------------- // Emulator hooks @@ -552,6 +546,9 @@ GLUE_C_READ(disk_read_write_byte) if (disk6.disk[disk6.drive].run_byte >= disk6.disk[disk6.drive].track_width) { disk6.disk[disk6.drive].run_byte = 0; } + + animate_disk_track_sector(); + #if DISK_TRACING if ((disk6.disk[disk6.drive].run_byte % NIB_SEC_SIZE) == 0) { if (disk6.ddrw) { @@ -631,6 +628,8 @@ GLUE_C_READ(disk_read_phase) fprintf(test_write_fp, "NEW TRK:%d\n", (disk6.disk[disk6.drive].phase>>1)); } #endif + + animate_disk_track_sector(); } return ea == 0xE0 ? 0xFF : floating_bus_hibit(1); @@ -748,6 +747,9 @@ const char *disk6_eject(int drive) { ERRLOG("Error close()ing file %s", disk6.disk[drive].file_name); } +#ifdef __APPLE__ +# warning FIXME TODO : can we not inflate/deflate disk images within the iOS port? Maybe this is just a permission thing? +#else // foo.dsk -> foo.dsk.gz err = zlib_deflate(disk6.disk[drive].file_name, is_nib(disk6.disk[drive].file_name) ? NIB_SIZE : DSK_SIZE); if (err) { @@ -755,9 +757,10 @@ const char *disk6_eject(int drive) { } else { unlink(disk6.disk[drive].file_name); } +#endif } - FREE(disk6.disk[drive].file_name); + STRDUP_FREE(disk6.disk[drive].file_name); memset(&disk6.disk[drive], 0x0, sizeof(disk6.disk[drive])); disk6.disk[drive].fd = -1; @@ -906,6 +909,233 @@ void disk6_flush(int drive) { } } +bool disk6_saveState(StateHelper_s *helper) { + bool saved = false; + int fd = helper->fd; + + do { + uint8_t state = 0x0; + + state = (uint8_t)disk6.motor_off; + if (!helper->save(fd, &state, 1)) { + break; + } + LOG("SAVE motor_off = %02x", state); + + state = (uint8_t)disk6.drive; + if (!helper->save(fd, &state, 1)) { + break; + } + LOG("SAVE drive = %02x", state); + + state = (uint8_t)disk6.ddrw; + if (!helper->save(fd, &state, 1)) { + break; + } + LOG("SAVE ddrw = %02x", state); + + state = (uint8_t)disk6.disk_byte; + if (!helper->save(fd, &state, 1)) { + break; + } + LOG("SAVE disk_byte = %02x", state); + + // Drive A/B + + bool saved_drives = false; + for (unsigned long i=0; i<3; i++) { + if (i >= 2) { + saved_drives = true; + break; + } + + disk6_flush(i); + + state = (uint8_t)disk6.disk[i].is_protected; + if (!helper->save(fd, &state, 1)) { + break; + } + LOG("SAVE is_protected[%lu] = %02x", i, state); + + uint8_t serialized[4] = { 0 }; + + if (disk6.disk[i].file_name != NULL) { + uint32_t namelen = strlen(disk6.disk[i].file_name); + serialized[0] = (uint8_t)((namelen & 0xFF000000) >> 24); + serialized[1] = (uint8_t)((namelen & 0xFF0000 ) >> 16); + serialized[2] = (uint8_t)((namelen & 0xFF00 ) >> 8); + serialized[3] = (uint8_t)((namelen & 0xFF ) >> 0); + if (!helper->save(fd, serialized, 4)) { + break; + } + + if (!helper->save(fd, disk6.disk[i].file_name, namelen)) { + break; + } + + LOG("SAVE disk[%lu] : (%u) %s", i, namelen, disk6.disk[i].file_name); + } else { + memset(serialized, 0x0, sizeof(serialized)); + if (!helper->save(fd, serialized, 4)) { + break; + } + LOG("SAVE disk[%lu] (0) ", i); + } + + // Save unused placeholder -- backwards compatibility + state = 0x0; + if (!helper->save(fd, &state, 1)) { + break; + } + + // Save unused placeholder -- backwards compatibility + state = 0x0; + if (!helper->save(fd, &state, 1)) { + break; + } + + state = (uint8_t)disk6.disk[i].phase; + if (!helper->save(fd, &state, 1)) { + break; + } + LOG("SAVE phase[%lu] = %02x", i, state); + + serialized[0] = (uint8_t)((disk6.disk[i].run_byte & 0xFF00) >> 8); + serialized[1] = (uint8_t)((disk6.disk[i].run_byte & 0xFF ) >> 0); + if (!helper->save(fd, serialized, 2)) { + break; + } + LOG("SAVE run_byte[%lu] = %04x", i, disk6.disk[i].run_byte); + } + + if (!saved_drives) { + break; + } + + saved = true; + } while (0); + + return saved; +} + +bool disk6_loadState(StateHelper_s *helper) { + bool loaded = false; + int fd = helper->fd; + + do { + uint8_t state = 0x0; + + if (!helper->load(fd, &state, 1)) { + break; + } + disk6.motor_off = state; + LOG("LOAD motor_off = %02x", disk6.motor_off); + + if (!helper->load(fd, &state, 1)) { + break; + } + disk6.drive = state; + LOG("LOAD drive = %02x", disk6.drive); + + if (!helper->load(fd, &state, 1)) { + break; + } + disk6.ddrw = state; + LOG("LOAD ddrw = %02x", disk6.ddrw); + + if (!helper->load(fd, &state, 1)) { + break; + } + disk6.disk_byte = state; + LOG("LOAD disk_byte = %02x", disk6.disk_byte); + + // Drive A/B + + bool loaded_drives = false; + + for (unsigned long i=0; i<3; i++) { + if (i >= 2) { + loaded_drives = true; + break; + } + + uint8_t serialized[4] = { 0 }; + + if (!helper->load(fd, &state, 1)) { + break; + } + disk6.disk[i].is_protected = state; + LOG("LOAD is_protected[%lu] = %02x", i, disk6.disk[i].is_protected); + + if (!helper->load(fd, serialized, 4)) { + break; + } + uint32_t namelen = 0x0; + namelen = (uint32_t)(serialized[0] << 24); + namelen |= (uint32_t)(serialized[1] << 16); + namelen |= (uint32_t)(serialized[2] << 8); + namelen |= (uint32_t)(serialized[3] << 0); + + disk6_eject(i); + + if (namelen) { + unsigned long gzlen = (_GZLEN+1); + char *namebuf = MALLOC(namelen+gzlen+1); + if (!helper->load(fd, namebuf, namelen)) { + FREE(namebuf); + break; + } + + namebuf[namelen] = '\0'; + if (disk6_insert(i, namebuf, disk6.disk[i].is_protected)) { + snprintf(namebuf+namelen, gzlen, "%s", EXT_GZ); + namebuf[namelen+gzlen] = '\0'; + LOG("LOAD disk[%lu] : (%u) %s", i, namelen, namebuf); + if (disk6_insert(i, namebuf, disk6.disk[i].is_protected)) { + FREE(namebuf); + break; + } + } + + FREE(namebuf); + } + + // load placeholder + if (!helper->load(fd, &state, 1)) { + break; + } + + // load placeholder + if (!helper->load(fd, &state, 1)) { + break; + } + + if (!helper->load(fd, &state, 1)) { + break; + } + disk6.disk[i].phase = state; + LOG("LOAD phase[%lu] = %02x", i, disk6.disk[i].phase); + + if (!helper->load(fd, serialized, 2)) { + break; + } + disk6.disk[i].run_byte = (uint32_t)(serialized[0] << 8); + disk6.disk[i].run_byte |= (uint32_t)(serialized[1] << 0); + LOG("LOAD run_byte[%lu] = %04x", i, disk6.disk[i].run_byte); + } + + if (!loaded_drives) { + disk6_eject(0); + disk6_eject(1); + break; + } + + loaded = true; + } while (0); + + return loaded; +} + #if DISK_TRACING void c_begin_disk_trace_6(const char *read_file, const char *write_file) { if (read_file) { diff --git a/src/disk.h b/src/disk.h index 82475821..5f040fb3 100644 --- a/src/disk.h +++ b/src/disk.h @@ -47,8 +47,6 @@ #define _POLEN (sizeof(DISK_EXT_PO)-1) #define DISK_EXT_NIB ".nib" #define _NIBLEN (sizeof(DISK_EXT_NIB)-1) -#define DISK_EXT_GZ ".gz" -#define _GZLEN (sizeof(DISK_EXT_GZ)-1) typedef struct diskette_t { char *file_name; @@ -81,7 +79,7 @@ extern drive_t disk6; extern void disk6_init(void); // insert 5.25 disk image file -extern const char *disk6_insert(int drive, const char * const file_name, int force); +extern const char *disk6_insert(int drive, const char * const file_name, int readonly); // eject 5.25 disk image file extern const char *disk6_eject(int drive); @@ -89,6 +87,9 @@ extern const char *disk6_eject(int drive); // flush all I/O extern void disk6_flush(int drive); +extern bool disk6_saveState(StateHelper_s *helper); +extern bool disk6_loadState(StateHelper_s *helper); + #if DISK_TRACING void c_toggle_disk_trace_6(const char *read_file, const char *write_file); void c_begin_disk_trace_6(const char *read_file, const char *write_file); diff --git a/src/display.c b/src/display.c index bd3a9371..43f94fb5 100644 --- a/src/display.c +++ b/src/display.c @@ -559,6 +559,7 @@ static inline void _plot_char40(uint8_t **d, uint8_t **s) { } static inline void _plot_char80(uint8_t **d, uint8_t **s, const unsigned int fb_width) { + // FIXME : this is implicitly scaling at FONT_GLYPH_SCALE_Y ... make it explicit *((uint32_t *)(*d)) = *((uint32_t *)(*s)); *d += 4, *s += 4; *((uint16_t *)(*d)) = *((uint16_t *)(*s)); @@ -1094,6 +1095,46 @@ void video_clear(void) { video_setDirty(); } +bool video_saveState(StateHelper_s *helper) { + bool saved = false; + int fd = helper->fd; + + do { + uint8_t state = 0x0; + + state = (uint8_t)video__current_page; + if (!helper->save(fd, &state, 1)) { + break; + } + LOG("SAVE video__current_page = %02x", state); + + saved = true; + } while (0); + + return saved; +} + +bool video_loadState(StateHelper_s *helper) { + bool loaded = false; + int fd = helper->fd; + + do { + uint8_t state = 0x0; + + if (!helper->load(fd, &state, 1)) { + break; + } + video__current_page = state; + LOG("LOAD video__current_page = %02x", video__current_page); + + loaded = true; + } while (0); + + video_redraw(); + + return loaded; +} + void video_redraw(void) { // temporarily reset softswitches diff --git a/src/font.c b/src/font.c index 458f0e27..b6f4c73b 100644 --- a/src/font.c +++ b/src/font.c @@ -310,7 +310,7 @@ const unsigned char interface_glyphs[256] = /* : 0x11 ----------------------- mini-spacebar visual */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x3e, 0x00, /* : 0x12 ----------------------- glyph_joystick */ -0x08, 0x08, 0x08, 0x77, 0x08, 0x08, 0x08, 0x00, +0x08, 0x08, 0x08, 0x77, 0x08, 0x08, 0x08, 0x08, /* : 0x13 ----------------------- glyph_ctrl */ 0x08, 0x1c, 0x3e, 0x63, 0x7b, 0x63, 0x7f, 0x00, /* : 0x14 ----------------------- glyph_lowercase */ @@ -322,7 +322,7 @@ const unsigned char interface_glyphs[256] = /* : 0x17 ----------------------- glyph_backspace */ 0x00, 0x08, 0x04, 0x7e, 0x04, 0x08, 0x00, 0x00, /* : 0x18 ----------------------- glyph_joystick_kpad */ -0x08, 0x2a, 0x08, 0x77, 0x08, 0x2a, 0x08, 0x00, +0x08, 0x2a, 0x08, 0x77, 0x08, 0x2a, 0x08, 0x08, /* : 0x19 ----------------------- glyph_leftspace */ 0x00, 0x7e, 0x02, 0x42, 0x42, 0x42, 0x02, 0x7e, /* : 0x1A ----------------------- glyph_midspace */ diff --git a/src/font.txt b/src/font.txt index b0714993..fe8d3b68 100644 --- a/src/font.txt +++ b/src/font.txt @@ -1344,7 +1344,7 @@ ...#... ...#... ...#... -....... +...#... : 0x13 ----------------------- glyph_ctrl ...#... ..###.. @@ -1398,7 +1398,7 @@ ...#... .#.#.#. ...#... -....... +...#... : 0x19 ----------------------- glyph_leftspace ....... .###### diff --git a/src/interface.c b/src/interface.c index 91dc3e33..3c94d57c 100644 --- a/src/interface.c +++ b/src/interface.c @@ -20,7 +20,8 @@ int64_t (*interface_onTouchEvent)(interface_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords) = NULL; bool (*interface_isTouchMenuAvailable)(void) = NULL; void (*interface_setTouchMenuEnabled)(bool enabled) = NULL; -void (*interface_setTouchMenuVisibility)(float alpha) = NULL; +void (*interface_setTouchMenuVisibility)(float inactiveAlpha, float activeAlpha) = NULL; +void (*interface_setGlyphScale)(int glyphScale) = NULL; #endif // 2015/04/12 : This was legacy code for rendering the menu interfaces on desktop Linux. Portions here are resurrected @@ -222,28 +223,7 @@ void c_interface_print_submenu_centered( char *submenu, const int message_cols, /* ------------------------------------------------------------------------- */ -static int c_interface_cut_name(char *name) -{ - char *p = name + strlen(name) - 1; - int is_gz = 0; - - if (p >= name && *p == 'z') - { - p--; - if (p >= name && *p == 'g') - { - p--; - if (p >= name && *p == '.') - { - *p-- = '\0'; - is_gz = 1; - } - } - } - - return is_gz; -} - +#warning TODO FIXME : file selection and extension management should be made generic (merge similar code from disk.[hc] and possible Mac/iOS target) ... static int disk_select(const struct dirent *e) { char cmp[PATH_MAX] = { 0 }; @@ -469,8 +449,9 @@ void c_interface_select_diskette( int drive ) namelist[ ent_no ]->d_name ); } - if (c_interface_cut_name(temp)) + if (is_gz(temp)) { + cut_gz(temp); strncat(temp, " ", PATH_MAX-1); } /* write protected disk in drive? */ diff --git a/src/interface.h b/src/interface.h index f5f414f5..d1ea7dd8 100644 --- a/src/interface.h +++ b/src/interface.h @@ -85,9 +85,33 @@ extern bool (*interface_isTouchMenuAvailable)(void); // enable/disable touch menu HUD element extern void (*interface_setTouchMenuEnabled)(bool enabled); -// set minimum alpha visibility of touch menu HUD element -extern void (*interface_setTouchMenuVisibility)(float alpha); +// set min/max alpha visibility of touch menu HUD element +extern void (*interface_setTouchMenuVisibility)(float inactiveAlpha, float activeAlpha); + +// set a finer-grained font size (if glyphScale > 1) +extern void (*interface_setGlyphScale)(int glyphScale); #endif +#define EXT_GZ ".gz" +#define _GZLEN (sizeof(EXT_GZ)-1) + +// ---------------------------------------------------------------------------- +// file extension handling + +static inline bool is_gz(const char * const name) { + size_t len = strlen(name); + if (len <= _GZLEN) { + return false; + } + return strncmp(name+len-_GZLEN, EXT_GZ, _GZLEN) == 0; +} + +static inline void cut_gz(char *name) { + size_t len = strlen(name); + if (len <= _GZLEN) { + return; + } + *(name+len-_GZLEN) = '\0'; +} #endif diff --git a/src/joystick.c b/src/joystick.c index ec707997..6238f640 100644 --- a/src/joystick.c +++ b/src/joystick.c @@ -253,6 +253,55 @@ void c_joystick_reset(void) #endif } +// clamps modern gamepad controller axis values to the "corners" of a traditional joystick as used on the Apple //e +static inline void clampBeyondRadius(uint8_t *x, uint8_t *y) { + float half_x = (*x) - HALF_JOY_RANGE; + float half_y = (*y) - HALF_JOY_RANGE; + float r = sqrtf(half_x*half_x + half_y*half_y); + bool shouldClip = (r > HALF_JOY_RANGE); + if (joy_clip_to_radius && shouldClip) { + if ((*x) < HALF_JOY_RANGE) { + (*x) = ((*x) < QUARTER_JOY_RANGE) ? 0.f : (*x); + } else { + (*x) = ((*x) < HALF_JOY_RANGE+QUARTER_JOY_RANGE) ? (*x) : 0xFF; + } + if ((*y) < HALF_JOY_RANGE) { + (*y) = ((*y) < QUARTER_JOY_RANGE) ? 0.f : (*y); + } else { + (*y) = ((*y) < HALF_JOY_RANGE+QUARTER_JOY_RANGE) ? (*y) : JOY_RANGE-1; + } + } +} + +void joydriver_setClampBeyondRadius(bool clamp) { + joy_clip_to_radius = clamp; +} + +void joydriver_setAxisValue(uint8_t x, uint8_t y) { + clampBeyondRadius(&x, &y); + joy_x = x; + joy_y = y; +} + +uint8_t joydriver_getAxisX(void) { + return joy_x; +} + +// return Y axis value +uint8_t joydriver_getAxisY(void) { + return joy_y; +} + +// set button 0 pressed +void joydriver_setButton0Pressed(bool pressed) { + joy_button0 = (pressed) ? 0x80 : 0x0; +} + +// set button 1 pressed +void joydriver_setButton1Pressed(bool pressed) { + joy_button1 = (pressed) ? 0x80 : 0x0; +} + #if INTERFACE_TOUCH bool (*joydriver_isTouchJoystickAvailable)(void) = NULL; void (*joydriver_setTouchJoystickEnabled)(bool enabled) = NULL; @@ -274,6 +323,7 @@ void (*joydriver_beginCalibration)(void) = NULL; void (*joydriver_endCalibration)(void) = NULL; bool (*joydriver_isCalibrating)(void) = NULL; void (*joydriver_setShowControls)(bool showControls) = NULL; +void (*joydriver_setShowAzimuth)(bool showAzimuth) = NULL; void (*joydriver_setKeyRepeatThreshold)(float repeatThresholdSecs) = NULL; #endif diff --git a/src/joystick.h b/src/joystick.h index e9a23b2c..380f5ede 100644 --- a/src/joystick.h +++ b/src/joystick.h @@ -13,7 +13,8 @@ #define _JOYSTICK_H_ #define JOY_RANGE 0x100 -#define HALF_JOY_RANGE 0x80 +#define HALF_JOY_RANGE (JOY_RANGE>>1) +#define QUARTER_JOY_RANGE (HALF_JOY_RANGE>>1) extern uint16_t joy_x; extern uint16_t joy_y; @@ -32,6 +33,24 @@ void c_joystick_reset(void); void c_calibrate_joystick(void); #endif +// enable/disable gamepad clamping to joystick corners +void joydriver_setClampBeyondRadius(bool clamp); + +// set joystick axis values +void joydriver_setAxisValue(uint8_t x, uint8_t y); + +// return X axis value +uint8_t joydriver_getAxisX(void); + +// return Y axis value +uint8_t joydriver_getAxisY(void); + +// set button 0 pressed +void joydriver_setButton0Pressed(bool pressed); + +// set button 1 pressed +void joydriver_setButton1Pressed(bool pressed); + #if INTERFACE_TOUCH typedef enum touchjoy_variant_t { @@ -125,6 +144,9 @@ extern bool (*joydriver_isCalibrating)(void); // set controls visibility extern void (*joydriver_setShowControls)(bool showControls); +// set azimuth visibility +extern void (*joydriver_setShowAzimuth)(bool showAzimuth); + // set key repeat threshold (keypad joystick) extern void (*joydriver_setKeyRepeatThreshold)(float repeatThresholdSecs); diff --git a/src/json_parse.c b/src/json_parse.c index 8391cf64..67f3a790 100644 --- a/src/json_parse.c +++ b/src/json_parse.c @@ -38,7 +38,7 @@ int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) { } jsonLen = JSON_LENGTH*2; - jsonString = malloc(jsonLen); + jsonString = MALLOC(jsonLen); if (jsonString == NULL) { ERRLOG("WHOA : %s", strerror(errno)); break; @@ -56,7 +56,7 @@ int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) { if (jsonLen - jsonIdx < JSON_LENGTH) { //LOG("reallocating json string ..."); jsonLen <<= 1; - char *newString = realloc(jsonString, jsonLen); + char *newString = REALLOC(jsonString, jsonLen); if (!newString) { ERRLOG("WHOA2 : %s", strerror(errno)); bytesRead = -1; @@ -83,7 +83,7 @@ int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) { unsigned int numTokens = DEFAULT_NUMTOK; do { if (!jsonTokens) { - jsonTokens = calloc(numTokens, sizeof(jsmntok_t)); + jsonTokens = CALLOC(numTokens, sizeof(jsmntok_t)); if (!jsonTokens) { ERRLOG("WHOA3 : %s", strerror(errno)); break; @@ -91,12 +91,12 @@ int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) { } else { //LOG("reallocating json tokens ..."); numTokens <<= 1; - jsmntok_t *newTokens = realloc(jsonTokens, numTokens * sizeof(jsmntok_t)); - memset(newTokens, '\0', numTokens * sizeof(jsmntok_t)); + jsmntok_t *newTokens = REALLOC(jsonTokens, numTokens * sizeof(jsmntok_t)); if (!newTokens) { ERRLOG("WHOA4 : %s", strerror(errno)); break; } + memset(newTokens, '\0', numTokens * sizeof(jsmntok_t)); jsonTokens = newTokens; } jsmn_init(&parser); diff --git a/src/keys.c b/src/keys.c index 45f34324..bc890166 100644 --- a/src/keys.c +++ b/src/keys.c @@ -489,6 +489,7 @@ bool (*keydriver_isTouchKeyboardAvailable)(void) = NULL; void (*keydriver_setTouchKeyboardEnabled)(bool enabled) = NULL; void (*keydriver_setTouchKeyboardOwnsScreen)(bool pwnd) = NULL; bool (*keydriver_ownsScreen)(void) = NULL; +void (*keydriver_setGlyphScale)(int glyphScale) = NULL; void (*keydriver_setVisibilityWhenOwnsScreen)(float inactiveAlpha, float activeAlpha) = NULL; void (*keydriver_setLowercaseEnabled)(bool enabled) = NULL; void (*keydriver_keyboardReadCallback)(void) = NULL; diff --git a/src/keys.h b/src/keys.h index 66611285..76d37187 100644 --- a/src/keys.h +++ b/src/keys.h @@ -160,10 +160,13 @@ extern void (*keydriver_setTouchKeyboardOwnsScreen)(bool pwnd); // query touch screen ownership extern bool (*keydriver_ownsScreen)(void); +// set a finer-grained font size (if glyphScale > 1) +extern void (*keydriver_setGlyphScale)(int glyphScale); + // set visibility extern void (*keydriver_setVisibilityWhenOwnsScreen)(float inactiveAlpha, float activeAlpha); -// set visibility +// set lowercase enabled extern void (*keydriver_setLowercaseEnabled)(bool enabled); // keyboard read callback diff --git a/src/memmngt.h b/src/memmngt.h new file mode 100644 index 00000000..0c38a2f1 --- /dev/null +++ b/src/memmngt.h @@ -0,0 +1,125 @@ +/* + * Apple // emulator for *ix + * + * This software package is subject to the GNU General Public License + * version 3 or later (your choice) as published by the Free Software + * Foundation. + * + * Copyright 2013-2015 Aaron Culliney + * + */ + +#ifndef _MEMMNGT_H_ +#define _MEMMNGT_H_ + +// Simple memory management routines + +#define _FREE(ptr, free_func) \ + do { \ + free_func((ptr)); \ + /* WARNING : code may depend on NULLification, even in release builds */ \ + (ptr) = NULL; \ + } while (0) + +#define ASPRINTF_FREE(ptr) _FREE((ptr), free) +#define STRDUP_FREE(ptr) _FREE((ptr), free) +#define GETLINE_FREE(ptr) _FREE((ptr), free) + +#ifdef NDEBUG +# define MALLOC(size) malloc((size)) +# define CALLOC(nmemb, size) calloc((nmemb), (size)) +# define REALLOC(ptr, size) realloc((ptr), (size)) +# define FREE(ptr) _FREE((ptr), free) +#else + +// NOTE: debug builds use a simplistic inline *alloc() fence and a scribbling free() to pinpoint out-of-bounds heap +// writes. We still need to use Valgrind to pinpoint oob-reads and other issues =) + +# define MALLOC(size) _a2_malloc((size)) +# define CALLOC(nmemb, size) _a2_calloc((nmemb), (size)) +# define REALLOC(ptr, size) _a2_realloc((ptr), (size)) +# define FREE(ptr) _FREE((ptr), _a2_free) + +# define _BUF_SENTINEL 0xDEADC0DEUL +# define _BUF_FENCE_SZ (sizeof(_BUF_SENTINEL)) + +static inline void *_a2_malloc(size_t size) { + const size_t totalSize = sizeof(size_t)+_BUF_FENCE_SZ+size+_BUF_FENCE_SZ; + char *p = (char *)malloc(totalSize); + if (p) { + *((size_t *)p) = totalSize; + *((uint32_t *)(p+sizeof(size_t))) = _BUF_SENTINEL; + *((uint32_t *)(p+totalSize-_BUF_FENCE_SZ)) = _BUF_SENTINEL; + p += sizeof(size_t)+_BUF_FENCE_SZ; + } + return p; +} + +static inline void *_a2_calloc(size_t nmemb, size_t size) { + size *= nmemb; + const size_t totalSize = sizeof(size_t)+_BUF_FENCE_SZ+size+_BUF_FENCE_SZ; + char *p = (char *)calloc(totalSize, 1); + if (p) { + *((size_t *)p) = totalSize; + *((uint32_t *)(p+sizeof(size_t))) = _BUF_SENTINEL; + *((uint32_t *)(p+totalSize-_BUF_FENCE_SZ)) = _BUF_SENTINEL; + p += sizeof(size_t)+_BUF_FENCE_SZ; + } + return p; +} + +static inline void _a2_free(void *ptr) { + char *p = (char *)ptr; + if (!p) { + return; + } + p = p-_BUF_FENCE_SZ-sizeof(size_t); + const size_t totalSize = *((size_t *)p); + assert( *((uint32_t *)(p+sizeof(size_t))) == _BUF_SENTINEL && "1st memory sentinel invalid!" ); + assert( *((uint32_t *)(p+totalSize-_BUF_FENCE_SZ)) == _BUF_SENTINEL && "2nd memory sentinel invalid!" ); + memset(p, 0xAA, totalSize); + free(p); +} + +static inline void *_a2_realloc(void *ptr, size_t size) { + char *p = (char *)ptr; + if (!p) { + return _a2_malloc(size); + } + if (size == 0) { + FREE(ptr); + return NULL; + } + + // verify prior allocation is sane + p = p-_BUF_FENCE_SZ-sizeof(size_t); + const size_t totalSizeBefore = *((size_t *)p); + assert( *((uint32_t *)(p+sizeof(size_t))) == _BUF_SENTINEL && "1st memory sentinel invalid!" ); + assert( *((uint32_t *)(p+totalSizeBefore-_BUF_FENCE_SZ)) == _BUF_SENTINEL && "2nd memory sentinel invalid!" ); + + const size_t totalSizeAfter = sizeof(size_t)+_BUF_FENCE_SZ+size+_BUF_FENCE_SZ; + assert(totalSizeAfter > totalSizeBefore && "FIXME fenced realloc() to smaller sizes not implemented!"); + + p = (char *)realloc(p, totalSizeAfter); + if (p) { + *((size_t *)p) = totalSizeAfter; + assert( *((uint32_t *)(p+sizeof(size_t))) == _BUF_SENTINEL && "1st memory sentinel invalid!" ); + *((uint32_t *)(p+totalSizeAfter-_BUF_FENCE_SZ)) = _BUF_SENTINEL; + p += sizeof(size_t)+_BUF_FENCE_SZ; + } + + return p; +} + +#endif + +#ifdef __APPLE__ +#define CFRELEASE(x) \ + do { \ + CFRelease((x)); \ + (x) = NULL; \ + } while (0) +#endif + +#endif // whole file + diff --git a/src/meta/debug.c b/src/meta/debug.c index 3d8bc25a..8482a323 100644 --- a/src/meta/debug.c +++ b/src/meta/debug.c @@ -2367,7 +2367,7 @@ YY_RULE_SETUP char *buf = NULL; asprintf(&buf, "%s/%s", getenv("HOME"), "cputrace.txt"); cpu65_trace_toggle(buf); - free(buf); + ASPRINTF_FREE(buf); #else LOG("CPU tracing not enabled..."); #endif @@ -2382,7 +2382,7 @@ YY_RULE_SETUP char *buf = NULL; asprintf(&buf, "%s/%s", getenv("HOME"), "disktrace.txt"); c_toggle_disk_trace_6(buf, NULL); - free(buf); + ASPRINTF_FREE(buf); #else LOG("Disk tracing not enabled..."); #endif diff --git a/src/meta/debug.l b/src/meta/debug.l index a6e823e6..5ff34c05 100644 --- a/src/meta/debug.l +++ b/src/meta/debug.l @@ -854,7 +854,7 @@ ADDRS [0-9a-fA-F]+ char *buf = NULL; asprintf(&buf, "%s/%s", getenv("HOME"), "cputrace.txt"); cpu65_trace_toggle(buf); - free(buf); + ASPRINTF_FREE(buf); #else LOG("CPU tracing not enabled..."); #endif @@ -865,7 +865,7 @@ ADDRS [0-9a-fA-F]+ char *buf = NULL; asprintf(&buf, "%s/%s", getenv("HOME"), "disktrace.txt"); c_toggle_disk_trace_6(buf, NULL); - free(buf); + ASPRINTF_FREE(buf); #else LOG("Disk tracing not enabled..."); #endif diff --git a/src/meta/debugger.c b/src/meta/debugger.c index a7fd3640..1b70c04c 100644 --- a/src/meta/debugger.c +++ b/src/meta/debugger.c @@ -1195,8 +1195,7 @@ bool c_debugger_should_break() { if (pthread_self() != cpu_thread_id) { // OOPS ... ERRLOG("should only call this from cpu thread, bailing..."); - void *ptr = NULL; - free(ptr); + RELEASE_BREAK(); } if (at_haltpt()) { diff --git a/src/misc.c b/src/misc.c index 8412a737..6963d9b8 100644 --- a/src/misc.c +++ b/src/misc.c @@ -15,6 +15,9 @@ #include "common.h" +#define SAVE_MAGICK "A2VM" +#define SAVE_MAGICK_LEN sizeof(SAVE_MAGICK) + bool do_logging = true; // also controlled by NDEBUG FILE *error_log = NULL; int sound_volume = 2; @@ -26,6 +29,7 @@ CrashHandler_s *crashHandler = NULL; __attribute__((constructor(CTOR_PRIORITY_FIRST))) static void _init_common(void) { + LOG("Initializing common..."); #if defined(CONFIG_DATADIR) data_dir = strdup(CONFIG_DATADIR PATH_SEPARATOR PACKAGE_NAME); #elif defined(ANDROID) @@ -35,6 +39,155 @@ static void _init_common(void) { #endif } +static bool _save_state(int fd, const uint8_t * outbuf, ssize_t outmax) { + ssize_t outlen = 0; + do { + if (TEMP_FAILURE_RETRY(outlen = write(fd, outbuf, outmax)) == -1) { + ERRLOG("error writing emulator save state file"); + break; + } + outbuf += outlen; + outmax -= outlen; + } while (outmax > 0); + + return outmax == 0; +} + +static bool _load_state(int fd, uint8_t * inbuf, ssize_t inmax) { + ssize_t inlen = 0; + do { + if (TEMP_FAILURE_RETRY(inlen = read(fd, inbuf, inmax)) == -1) { + ERRLOG("error reading emulator save state file"); + break; + } + if (inlen == 0) { + ERRLOG("error reading emulator save state file (truncated)"); + break; + } + inbuf += inlen; + inmax -= inlen; + } while (inmax > 0); + + return inmax == 0; +} + +bool emulator_saveState(const char * const path) { + int fd = -1; + bool saved = false; + + assert(cpu_isPaused() && "should be paused to save state"); + + do { + TEMP_FAILURE_RETRY(fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)); + if (fd < 0) { + break; + } + assert(fd != 0 && "crazy platform"); + + // save header + if (!_save_state(fd, SAVE_MAGICK, SAVE_MAGICK_LEN)) { + break; + } + + StateHelper_s helper = { + .fd = fd, + .save = &_save_state, + .load = &_load_state, + }; + + if (!disk6_saveState(&helper)) { + break; + } + + if (!vm_saveState(&helper)) { + break; + } + + if (!cpu65_saveState(&helper)) { + break; + } + + if (!video_saveState(&helper)) { + break; + } + + TEMP_FAILURE_RETRY(fsync(fd)); + saved = true; + } while (0); + + if (fd >= 0) { + TEMP_FAILURE_RETRY(close(fd)); + } + + if (!saved) { + ERRLOG("could not write to the emulator save state file"); + unlink(path); + } + + return saved; +} + +bool emulator_loadState(const char * const path) { + int fd = -1; + bool loaded = false; + + assert(cpu_isPaused() && "should be paused to load state"); + + do { + TEMP_FAILURE_RETRY(fd = open(path, O_RDONLY)); + if (fd < 0) { + break; + } + assert(fd != 0 && "crazy platform"); + + // load header + uint8_t magick[SAVE_MAGICK_LEN] = { 0 }; + if (!_load_state(fd, magick, SAVE_MAGICK_LEN)) { + break; + } + + // check header + if (memcmp(magick, SAVE_MAGICK, SAVE_MAGICK_LEN) != 0) { + ERRLOG("bad header magick in emulator save state file"); + break; + } + + StateHelper_s helper = { + .fd = fd, + .save = &_save_state, + .load = &_load_state, + }; + + if (!disk6_loadState(&helper)) { + break; + } + + if (!vm_loadState(&helper)) { + break; + } + + if (!cpu65_loadState(&helper)) { + break; + } + + if (!video_loadState(&helper)) { + break; + } + + loaded = true; + } while (0); + + if (fd >= 0) { + TEMP_FAILURE_RETRY(close(fd)); + } + + if (!loaded) { + ERRLOG("could not load emulator save state file"); + } + + return loaded; +} + static void _shutdown_threads(void) { #if !TESTING # if defined(__linux__) && !defined(ANDROID) @@ -83,6 +236,8 @@ void emulator_start(void) { } void emulator_shutdown(void) { + disk6_eject(0); + disk6_eject(1); video_shutdown(); timing_stopCPU(); _shutdown_threads(); diff --git a/src/misc.h b/src/misc.h index 06e6782d..44bdd274 100644 --- a/src/misc.h +++ b/src/misc.h @@ -29,6 +29,22 @@ void emulator_start(void); // shutdown emulator in preparation for app exit void emulator_shutdown(void); +// +// Emulator state save/restore +// + +typedef struct StateHelper_s { + int fd; + bool (*save)(int fd, const uint8_t * outbuf, ssize_t outmax); + bool (*load)(int fd, uint8_t * inbuf, ssize_t inmax); +} StateHelper_s; + +// save current emulator state +bool emulator_saveState(const char * const path); + +// load emulator state from save path +bool emulator_loadState(const char * const path); + // // Crash handling ... // diff --git a/src/prefs.c b/src/prefs.c index be98ee1c..1b5a45d9 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -303,7 +303,7 @@ void load_settings(void) } } - FREE(buffer); + GETLINE_FREE(buffer); fclose(config_file); } diff --git a/src/test/testcommon.c b/src/test/testcommon.c index b33b2ed9..5baa104d 100644 --- a/src/test/testcommon.c +++ b/src/test/testcommon.c @@ -128,9 +128,10 @@ void test_common_init() { } int test_setup_boot_disk(const char *fileName, int readonly) { - char *disk = NULL; int err = 0; -#ifdef __APPLE__ + char **path = NULL; + +#if defined(__APPLE__) CFBundleRef mainBundle = CFBundleGetMainBundle(); CFStringRef fileString = CFStringCreateWithCString(/*allocator*/NULL, fileName, CFStringGetSystemEncoding()); CFURLRef fileURL = CFBundleCopyResourceURL(mainBundle, fileString, NULL, NULL); @@ -139,20 +140,53 @@ int test_setup_boot_disk(const char *fileName, int readonly) { CFRELEASE(fileURL); CFIndex length = CFStringGetLength(filePath); CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); - disk = (char *)malloc(maxSize); + disk = (char *)MALLOC(maxSize); if (!CFStringGetCString(filePath, disk, maxSize, kCFStringEncodingUTF8)) { FREE(disk); } CFRELEASE(filePath); + + char *paths[] = { + disk, + NULL, + }; #else - asprintf(&disk, "%s/disks/%s", data_dir, fileName); + char *paths[] = { + NULL, + NULL, + NULL, + NULL, + }; + asprintf(&paths[0], "%s/disks/%s", data_dir, fileName); + asprintf(&paths[1], "%s/disks/demo/%s", data_dir, fileName); + asprintf(&paths[2], "%s/disks/blanks/%s", data_dir, fileName); #endif - if (disk6_insert(0, disk, readonly)) { + + path = &paths[0]; + while (*path) { + char *disk = *path; + ++path; + + err = disk6_insert(0, disk, readonly) != NULL; + if (!err) { + break; + } + int len = strlen(disk); disk[len-3] = '\0'; // try again without '.gz' extension - err = (disk6_insert(0, disk, readonly) != NULL); + err = disk6_insert(0, disk, readonly) != NULL; + if (!err) { + break; + } } - FREE(disk); + + path = &paths[0]; + while (*path) { + char *disk = *path; + ++path; + ASPRINTF_FREE(disk); + } + return err; } @@ -161,6 +195,5 @@ void sha1_to_str(const uint8_t * const md, char *buf) { for (int j=0; jid = testcounter; \ - test_func->name = strdup(#TEST); \ - test_func->func = TEST; \ - HASH_ADD_INT(test_funcs, id, test_func); \ - ++testcounter; \ - } while(0); - -#define A2_REMOVE_TEST(TEST) \ - do { \ - HASH_DEL(test_funcs, TEST); \ - free(TEST->name); \ - free(TEST); \ - } while(0); - -#define A2_RUN_TESTp(TEST, ...) RUN_TESTp( ((test_func_ptr)(TEST)), __VA_ARGS__) GREATEST_SUITE(test_suite_cpu) { @@ -7318,77 +7426,94 @@ GREATEST_SUITE(test_suite_cpu) { extern volatile uint8_t emul_reinitialize; emul_reinitialize = 0; - test_func_t *func=NULL, *tmp=NULL; - // -------------------------------- - A2_ADD_TEST(test_BRK); - A2_ADD_TEST(test_IRQ); - A2_ADD_TEST(test_CLC); - A2_ADD_TEST(test_CLD); - A2_ADD_TEST(test_CLI); - A2_ADD_TEST(test_CLV); - A2_ADD_TEST(test_NOP); - A2_ADD_TEST(test_PHA); - A2_ADD_TEST(test_PHX); - A2_ADD_TEST(test_PHY); - A2_ADD_TEST(test_SEC); - A2_ADD_TEST(test_SED); - A2_ADD_TEST(test_SEI); - HASH_ITER(hh, test_funcs, func, tmp) { - fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); - RUN_TEST(((test_func_ptr0)(func->func))); - A2_REMOVE_TEST(func); - } + + fprintf(GREATEST_STDOUT, "\ntest_BRK :\n"); + RUN_TEST(test_BRK); + fprintf(GREATEST_STDOUT, "\ntest_IRQ :\n"); + RUN_TEST(test_IRQ); + fprintf(GREATEST_STDOUT, "\ntest_CLC :\n"); + RUN_TEST(test_CLC); + fprintf(GREATEST_STDOUT, "\ntest_CLD :\n"); + RUN_TEST(test_CLD); + fprintf(GREATEST_STDOUT, "\ntest_CLI :\n"); + RUN_TEST(test_CLI); + fprintf(GREATEST_STDOUT, "\ntest_CLV :\n"); + RUN_TEST(test_CLV); + fprintf(GREATEST_STDOUT, "\ntest_NOP :\n"); + RUN_TEST(test_NOP); + fprintf(GREATEST_STDOUT, "\ntest_PHA :\n"); + RUN_TEST(test_PHA); + fprintf(GREATEST_STDOUT, "\ntest_PHX :\n"); + RUN_TEST(test_PHX); + fprintf(GREATEST_STDOUT, "\ntest_PHY :\n"); + RUN_TEST(test_PHY); + fprintf(GREATEST_STDOUT, "\ntest_SEC :\n"); + RUN_TEST(test_SEC); + fprintf(GREATEST_STDOUT, "\ntest_SED :\n"); + RUN_TEST(test_SED); + fprintf(GREATEST_STDOUT, "\ntest_SEI :\n"); + RUN_TEST(test_SEI); // ------------------------------------------------------------------------ // Branch tests : // NOTE : these should be a comprehensive exercise of the branching logic greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; - A2_ADD_TEST(test_BCC); - A2_ADD_TEST(test_BCS); - A2_ADD_TEST(test_BEQ); - A2_ADD_TEST(test_BNE); - A2_ADD_TEST(test_BMI); - A2_ADD_TEST(test_BPL); - A2_ADD_TEST(test_BRA); - A2_ADD_TEST(test_BVC); - A2_ADD_TEST(test_BVS); - HASH_ITER(hh, test_funcs, func, tmp) { - fprintf(GREATEST_STDOUT, "\n%s (SILENCED OUTPUT) :\n", func->name); - for (uint16_t addrs = 0x1f02; addrs < 0x2000; addrs++) { - for (uint8_t flag = 0x00; flag < 0x02; flag++) { - uint8_t off=0x00; - do { - A2_RUN_TESTp( func->func, off, flag, addrs); - } while (++off); + do { + test_func_t funcs[] = { + { "test_BCC", (void(*)(void))test_BCC, }, + { "test_BCS", (void(*)(void))test_BCS, }, + { "test_BEQ", (void(*)(void))test_BEQ, }, + { "test_BNE", (void(*)(void))test_BNE, }, + { "test_BMI", (void(*)(void))test_BMI, }, + { "test_BPL", (void(*)(void))test_BPL, }, + { "test_BRA", (void(*)(void))test_BRA, }, + { "test_BVC", (void(*)(void))test_BVC, }, + { "test_BVS", (void(*)(void))test_BVS, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); + + for (unsigned int i=0; i= 0xff00 || addrs < 0x00fe; addrs++) { - for (uint8_t flag = 0x00; flag < 0x02; flag++) { - uint8_t off=0x00; - do { - A2_RUN_TESTp(func->func, off, flag, addrs); - } while (++off); + // 16bit branch overflow tests + for (uint16_t addrs = 0xff00; addrs >= 0xff00 || addrs < 0x00fe; addrs++) { + for (uint8_t flag = 0x00; flag < 0x02; flag++) { + uint8_t off=0x00; + do { + RUN_TESTp(func, off, flag, addrs); + } while (++off); + } } - } - // 16bit branch underflow tests - for (uint16_t addrs = 0x00fe; addrs <= 0x00fe || addrs > 0xff00; addrs--) { - for (uint8_t flag = 0x00; flag < 0x02; flag++) { - uint8_t off=0x00; - do { - A2_RUN_TESTp(func->func, off, flag, addrs); - } while (++off); + // 16bit branch underflow tests + for (uint16_t addrs = 0x00fe; addrs <= 0x00fe || addrs > 0xff00; addrs--) { + for (uint8_t flag = 0x00; flag < 0x02; flag++) { + uint8_t off=0x00; + do { + RUN_TESTp(func, off, flag, addrs); + } while (++off); + } } - } - fprintf(GREATEST_STDOUT, "...OK\n"); - A2_REMOVE_TEST(func); - } + fprintf(GREATEST_STDOUT, "...OK\n"); + } + } while (0); + greatest_info.flags = 0x0; // ------------------------------------------------------------------------ @@ -7396,78 +7521,99 @@ GREATEST_SUITE(test_suite_cpu) { // NOTE : these should be a comprehensive exercise of the instruction logic greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; - A2_ADD_TEST(test_ADC_imm); - A2_ADD_TEST(test_AND_imm); - A2_ADD_TEST(test_BIT_imm); - A2_ADD_TEST(test_CMP_imm); - A2_ADD_TEST(test_CPX_imm); - A2_ADD_TEST(test_CPY_imm); - A2_ADD_TEST(test_EOR_imm); - A2_ADD_TEST(test_LDA_imm); - A2_ADD_TEST(test_LDX_imm); - A2_ADD_TEST(test_LDY_imm); - A2_ADD_TEST(test_ORA_imm); - A2_ADD_TEST(test_SBC_imm); - HASH_ITER(hh, test_funcs, func, tmp) { - fprintf(GREATEST_STDOUT, "\n%s (SILENCED OUTPUT) :\n", func->name); - // test comprehensive logic in immediate mode (since no addressing to test) ... - uint8_t regA=0x00; - do { - uint8_t val=0x00; + do { + test_func_t funcs[] = { + { "test_ADC_imm", (void(*)(void))test_ADC_imm, }, + { "test_AND_imm", (void(*)(void))test_AND_imm, }, + { "test_BIT_imm", (void(*)(void))test_BIT_imm, }, + { "test_CMP_imm", (void(*)(void))test_CMP_imm, }, + { "test_CPX_imm", (void(*)(void))test_CPX_imm, }, + { "test_CPY_imm", (void(*)(void))test_CPY_imm, }, + { "test_EOR_imm", (void(*)(void))test_EOR_imm, }, + { "test_LDA_imm", (void(*)(void))test_LDA_imm, }, + { "test_LDX_imm", (void(*)(void))test_LDX_imm, }, + { "test_LDY_imm", (void(*)(void))test_LDY_imm, }, + { "test_ORA_imm", (void(*)(void))test_ORA_imm, }, + { "test_SBC_imm", (void(*)(void))test_SBC_imm, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); + + for (unsigned int i=0; ifunc, regA, val, /*decimal*/false, /*carry*/false); - A2_RUN_TESTp( func->func, regA, val, /*decimal*/ true, /*carry*/false); - A2_RUN_TESTp( func->func, regA, val, /*decimal*/false, /*carry*/true); - A2_RUN_TESTp( func->func, regA, val, /*decimal*/ true, /*carry*/true); - } while (++val); - } while (++regA); + uint8_t val=0x00; + do { + RUN_TESTp(func, regA, val, /*decimal*/false, /*carry*/false); + RUN_TESTp(func, regA, val, /*decimal*/ true, /*carry*/false); + RUN_TESTp(func, regA, val, /*decimal*/false, /*carry*/true); + RUN_TESTp(func, regA, val, /*decimal*/ true, /*carry*/true); + } while (++val); + } while (++regA); + + fprintf(GREATEST_STDOUT, "...OK\n"); + } + } while (0); - fprintf(GREATEST_STDOUT, "...OK\n"); - A2_REMOVE_TEST(func); - } greatest_info.flags = 0x0; // ------------------------------------------------------------------------ // Immediate/absolute addressing mode tests greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; - A2_ADD_TEST(test_JMP_abs); - A2_ADD_TEST(test_JMP_abs_ind_x); - A2_ADD_TEST(test_JMP_ind); - A2_ADD_TEST(test_JSR_abs); - A2_ADD_TEST(test_RTS); - HASH_ITER(hh, test_funcs, func, tmp) { - fprintf(GREATEST_STDOUT, "\n%s (SILENCED OUTPUT) :\n", func->name); - // test comprehensive logic in immediate mode (since no addressing to test) ... - uint8_t lobyte=0x00; - do { - uint8_t hibyte=0x00; + do { + test_func_t funcs[] = { + { "test_JMP_abs", (void(*)(void))test_JMP_abs, }, + { "test_JMP_abs_ind_x", (void(*)(void))test_JMP_abs_ind_x, }, + { "test_JMP_ind", (void(*)(void))test_JMP_ind, }, + { "test_JSR_abs", (void(*)(void))test_JSR_abs, }, + { "test_RTS", (void(*)(void))test_RTS, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); + + for (unsigned int i=0; ifunc, lobyte, hibyte, TEST_LOC, (uint8_t)random()); - } while (++hibyte); - } while (++lobyte); + uint8_t hibyte=0x00; + do { + RUN_TESTp(func, lobyte, hibyte, TEST_LOC, (uint8_t)random()); + } while (++hibyte); + } while (++lobyte); - // test 16bit overflow/underflow - lobyte=0x00; - do { - uint8_t regX=0x00; + // test 16bit overflow/underflow + lobyte=0x00; do { - A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0xFFFC, regX); - A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0xFFFD, regX); - A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0xFFFE, regX); - A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0xFFFF, regX); - A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0x0000, regX); - A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0x0001, regX); - A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0x0002, regX); - A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0x0003, regX); - } while (++regX); - } while (++lobyte); + uint8_t regX=0x00; + do { + RUN_TESTp(func, lobyte, (uint8_t)random(), 0xFFFC, regX); + RUN_TESTp(func, lobyte, (uint8_t)random(), 0xFFFD, regX); + RUN_TESTp(func, lobyte, (uint8_t)random(), 0xFFFE, regX); + RUN_TESTp(func, lobyte, (uint8_t)random(), 0xFFFF, regX); + RUN_TESTp(func, lobyte, (uint8_t)random(), 0x0000, regX); + RUN_TESTp(func, lobyte, (uint8_t)random(), 0x0001, regX); + RUN_TESTp(func, lobyte, (uint8_t)random(), 0x0002, regX); + RUN_TESTp(func, lobyte, (uint8_t)random(), 0x0003, regX); + } while (++regX); + } while (++lobyte); + + fprintf(GREATEST_STDOUT, "...OK\n"); + } + + } while (0); - fprintf(GREATEST_STDOUT, "...OK\n"); - A2_REMOVE_TEST(func); - } greatest_info.flags = 0x0; // ------------------------------------------------------------------------ @@ -7475,349 +7621,431 @@ GREATEST_SUITE(test_suite_cpu) { // NOTE : these should be a comprehensive exercise of the instruction logic greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; - A2_ADD_TEST(test_ASL_acc); - A2_ADD_TEST(test_DEA); - A2_ADD_TEST(test_DEX); - A2_ADD_TEST(test_DEY); - A2_ADD_TEST(test_INA); - A2_ADD_TEST(test_INX); - A2_ADD_TEST(test_INY); - A2_ADD_TEST(test_LSR_acc); - A2_ADD_TEST(test_PHP); - A2_ADD_TEST(test_PLA); - A2_ADD_TEST(test_PLP); - A2_ADD_TEST(test_PLX); - A2_ADD_TEST(test_PLY); - A2_ADD_TEST(test_ROL_acc); - A2_ADD_TEST(test_ROR_acc); - A2_ADD_TEST(test_RTI); - A2_ADD_TEST(test_TAX); - A2_ADD_TEST(test_TAY); - A2_ADD_TEST(test_TSX); - A2_ADD_TEST(test_TXS); - A2_ADD_TEST(test_TXA); - A2_ADD_TEST(test_TYA); - HASH_ITER(hh, test_funcs, func, tmp) { - fprintf(GREATEST_STDOUT, "\n%s (SILENCED OUTPUT) :\n", func->name); - // test comprehensive logic in immediate mode (since no addressing to test) ... - uint8_t regA=0x00; - do { - A2_RUN_TESTp( func->func, regA, true); - A2_RUN_TESTp( func->func, regA, false); - } while (++regA); + do { + test_func_t funcs[] = { + { "test_ASL_acc", (void(*)(void))test_ASL_acc, }, + { "test_DEA", (void(*)(void))test_DEA, }, + { "test_DEX", (void(*)(void))test_DEX, }, + { "test_DEY", (void(*)(void))test_DEY, }, + { "test_INA", (void(*)(void))test_INA, }, + { "test_INX", (void(*)(void))test_INX, }, + { "test_INY", (void(*)(void))test_INY, }, + { "test_LSR_acc", (void(*)(void))test_LSR_acc, }, + { "test_PHP", (void(*)(void))test_PHP, }, + { "test_PLA", (void(*)(void))test_PLA, }, + { "test_PLP", (void(*)(void))test_PLP, }, + { "test_PLX", (void(*)(void))test_PLX, }, + { "test_PLY", (void(*)(void))test_PLY, }, + { "test_ROL_acc", (void(*)(void))test_ROL_acc, }, + { "test_ROR_acc", (void(*)(void))test_ROR_acc, }, + { "test_RTI", (void(*)(void))test_RTI, }, + { "test_TAX", (void(*)(void))test_TAX, }, + { "test_TAY", (void(*)(void))test_TAY, }, + { "test_TSX", (void(*)(void))test_TSX, }, + { "test_TXS", (void(*)(void))test_TXS, }, + { "test_TXA", (void(*)(void))test_TXA, }, + { "test_TYA", (void(*)(void))test_TYA, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); + + for (unsigned int i=0; iname); - // test addressing is working ... - uint8_t arg0 = 0x00; - do { - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, arg0, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, arg0, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, arg0, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, arg0, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, arg0, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, arg0, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, arg0, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, arg0, /*carry*/false); - ++arg0; - } while (arg0); + do { + test_func_t funcs[] = { + { "test_ADC_zpage", (void(*)(void))test_ADC_zpage, }, + { "test_AND_zpage", (void(*)(void))test_AND_zpage, }, + { "test_ASL_zpage", (void(*)(void))test_ASL_zpage, }, + { "test_BIT_zpage", (void(*)(void))test_BIT_zpage, }, + { "test_CMP_zpage", (void(*)(void))test_CMP_zpage, }, + { "test_CPX_zpage", (void(*)(void))test_CPX_zpage, }, + { "test_CPY_zpage", (void(*)(void))test_CPY_zpage, }, + { "test_DEC_zpage", (void(*)(void))test_DEC_zpage, }, + { "test_EOR_zpage", (void(*)(void))test_EOR_zpage, }, + { "test_INC_zpage", (void(*)(void))test_INC_zpage, }, + { "test_LDA_zpage", (void(*)(void))test_LDA_zpage, }, + { "test_LDX_zpage", (void(*)(void))test_LDX_zpage, }, + { "test_LDY_zpage", (void(*)(void))test_LDY_zpage, }, + { "test_LSR_zpage", (void(*)(void))test_LSR_zpage, }, + { "test_ORA_zpage", (void(*)(void))test_ORA_zpage, }, + { "test_ROL_zpage", (void(*)(void))test_ROL_zpage, }, + { "test_ROR_zpage", (void(*)(void))test_ROR_zpage, }, + { "test_SBC_zpage", (void(*)(void))test_SBC_zpage, }, + { "test_STA_zpage", (void(*)(void))test_STA_zpage, }, + { "test_STX_zpage", (void(*)(void))test_STX_zpage, }, + { "test_STY_zpage", (void(*)(void))test_STY_zpage, }, + { "test_STZ_zpage", (void(*)(void))test_STZ_zpage, }, + { "test_TRB_zpage", (void(*)(void))test_TRB_zpage, }, + { "test_TSB_zpage", (void(*)(void))test_TSB_zpage, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); -#ifdef ANDROID - fprintf(GREATEST_STDOUT, "...OK\n"); -#endif - A2_REMOVE_TEST(func); - } + for (unsigned int i=0; iname); + fprintf(GREATEST_STDOUT, "\n%s :\n", name); - // test addressing is working ... - uint8_t regX = 0x0; - do { - uint8_t arg0 = 0x0; + // test addressing is working ... + uint8_t arg0 = 0x00; do { - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, arg0, regX, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, arg0, regX, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, arg0, regX, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, arg0, regX, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, arg0, regX, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, arg0, regX, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, arg0, regX, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, arg0, regX, /*carry*/false); - } while (++arg0); - } while (++regX); + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, arg0, /*carry*/true); + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, arg0, /*carry*/false); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, arg0, /*carry*/true); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, arg0, /*carry*/false); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, arg0, /*carry*/true); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, arg0, /*carry*/false); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, arg0, /*carry*/true); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, arg0, /*carry*/false); + ++arg0; + } while (arg0); + +#ifdef ANDROID + fprintf(GREATEST_STDOUT, "...OK\n"); +#endif + } + } while (0); + + // -------------------------------- + greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; + + do { + test_func_t funcs[] = { + { "test_ADC_zpage_x", (void(*)(void))test_ADC_zpage_x, }, + { "test_AND_zpage_x", (void(*)(void))test_AND_zpage_x, }, + { "test_ASL_zpage_x", (void(*)(void))test_ASL_zpage_x, }, + { "test_BIT_zpage_x", (void(*)(void))test_BIT_zpage_x, }, + { "test_CMP_zpage_x", (void(*)(void))test_CMP_zpage_x, }, + { "test_DEC_zpage_x", (void(*)(void))test_DEC_zpage_x, }, + { "test_EOR_zpage_x", (void(*)(void))test_EOR_zpage_x, }, + { "test_INC_zpage_x", (void(*)(void))test_INC_zpage_x, }, + { "test_LDA_zpage_x", (void(*)(void))test_LDA_zpage_x, }, + { "test_LDX_zpage_y", (void(*)(void))test_LDX_zpage_y, }, + { "test_LDY_zpage_x", (void(*)(void))test_LDY_zpage_x, }, + { "test_LSR_zpage_x", (void(*)(void))test_LSR_zpage_x, }, + { "test_ORA_zpage_x", (void(*)(void))test_ORA_zpage_x, }, + { "test_SBC_zpage_x", (void(*)(void))test_SBC_zpage_x, }, + { "test_ROL_zpage_x", (void(*)(void))test_ROL_zpage_x, }, + { "test_ROR_zpage_x", (void(*)(void))test_ROR_zpage_x, }, + { "test_STA_zpage_x", (void(*)(void))test_STA_zpage_x, }, + { "test_STX_zpage_y", (void(*)(void))test_STX_zpage_y, }, + { "test_STY_zpage_x", (void(*)(void))test_STY_zpage_x, }, + { "test_STZ_zpage_x", (void(*)(void))test_STZ_zpage_x, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); + + for (unsigned int i=0; iname); - // test addressing is working ... - for (uint8_t lobyte=0xfd; lobyte>0xf0; lobyte++) { - uint8_t hibyte = 0x1f; - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, lobyte, hibyte, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, lobyte, hibyte, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, lobyte, hibyte, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, lobyte, hibyte, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, lobyte, hibyte, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, lobyte, hibyte, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, lobyte, hibyte, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, lobyte, hibyte, /*carry*/true); - } + do { + test_func_t funcs[] = { + { "test_ADC_abs", (void(*)(void))test_ADC_abs, }, + { "test_AND_abs", (void(*)(void))test_AND_abs, }, + { "test_ASL_abs", (void(*)(void))test_ASL_abs, }, + { "test_BIT_abs", (void(*)(void))test_BIT_abs, }, + { "test_CMP_abs", (void(*)(void))test_CMP_abs, }, + { "test_CPX_abs", (void(*)(void))test_CPX_abs, }, + { "test_CPY_abs", (void(*)(void))test_CPY_abs, }, + { "test_DEC_abs", (void(*)(void))test_DEC_abs, }, + { "test_EOR_abs", (void(*)(void))test_EOR_abs, }, + { "test_INC_abs", (void(*)(void))test_INC_abs, }, + { "test_LDA_abs", (void(*)(void))test_LDA_abs, }, + { "test_LDX_abs", (void(*)(void))test_LDX_abs, }, + { "test_LDY_abs", (void(*)(void))test_LDY_abs, }, + { "test_LSR_abs", (void(*)(void))test_LSR_abs, }, + { "test_ORA_abs", (void(*)(void))test_ORA_abs, }, + { "test_ROL_abs", (void(*)(void))test_ROL_abs, }, + { "test_ROR_abs", (void(*)(void))test_ROR_abs, }, + { "test_SBC_abs", (void(*)(void))test_SBC_abs, }, + { "test_STA_abs", (void(*)(void))test_STA_abs, }, + { "test_STX_abs", (void(*)(void))test_STX_abs, }, + { "test_STY_abs", (void(*)(void))test_STY_abs, }, + { "test_STZ_abs", (void(*)(void))test_STZ_abs, }, + { "test_TRB_abs", (void(*)(void))test_TRB_abs, }, + { "test_TSB_abs", (void(*)(void))test_TSB_abs, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); -#ifdef ANDROID - fprintf(GREATEST_STDOUT, "...OK\n"); -#endif - A2_REMOVE_TEST(func); - } + for (unsigned int i=0; iname); + fprintf(GREATEST_STDOUT, "\n%s :\n", name); - // test addressing is working ... - uint8_t hibyte = 0x1f; - uint8_t lobyte = 0x20; - for (uint8_t regX=0x50; regX>0x4f; regX+=0x30) { - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, regX, lobyte, hibyte, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, regX, lobyte, hibyte, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, regX, lobyte, hibyte, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, regX, lobyte, hibyte, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, regX, lobyte, hibyte, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, regX, lobyte, hibyte, /*carry*/false); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, regX, lobyte, hibyte, /*carry*/true); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, regX, lobyte, hibyte, /*carry*/false); - - A2_RUN_TESTp( func->func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff, /*carry*/true); // wrap to zpage - A2_RUN_TESTp( func->func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff, /*carry*/false); // wrap to zpage - } - -#ifdef ANDROID - fprintf(GREATEST_STDOUT, "...OK\n"); -#endif - A2_REMOVE_TEST(func); - } - - // -------------------------------- - A2_ADD_TEST(test_ADC_abs_y); - A2_ADD_TEST(test_AND_abs_y); - A2_ADD_TEST(test_CMP_abs_y); - A2_ADD_TEST(test_EOR_abs_y); - A2_ADD_TEST(test_LDA_abs_y); - A2_ADD_TEST(test_LDX_abs_y); - A2_ADD_TEST(test_ORA_abs_y); - A2_ADD_TEST(test_SBC_abs_y); - A2_ADD_TEST(test_STA_abs_y); - HASH_ITER(hh, test_funcs, func, tmp) { - fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); - - // test addressing is working ... - uint8_t hibyte = 0x1f; - uint8_t lobyte = 0x20; - for (uint8_t regY=0x50; regY>0x4f; regY+=0x30) { - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, regY, lobyte, hibyte); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, regY, lobyte, hibyte); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, regY, lobyte, hibyte); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, regY, lobyte, hibyte); - A2_RUN_TESTp( func->func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff); // wrap to zpage - } - -#ifdef ANDROID - fprintf(GREATEST_STDOUT, "...OK\n"); -#endif - A2_REMOVE_TEST(func); - } - - // -------------------------------- - A2_ADD_TEST(test_ADC_ind_x); - A2_ADD_TEST(test_AND_ind_x); - A2_ADD_TEST(test_CMP_ind_x); - A2_ADD_TEST(test_EOR_ind_x); - A2_ADD_TEST(test_LDA_ind_x); - A2_ADD_TEST(test_ORA_ind_x); - A2_ADD_TEST(test_SBC_ind_x); - A2_ADD_TEST(test_STA_ind_x); - HASH_ITER(hh, test_funcs, func, tmp) { - fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); - - // test addressing is working ... - uint8_t hibyte = 0x1f; - for (uint8_t lobyte=0xfd; lobyte>0xf0; lobyte++) { - for (uint8_t regX=0x42; regX>0x3F; regX+=0x40) { - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, /*arg0*/0x24, regX, lobyte, hibyte); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, /*arg0*/0x24, regX, lobyte, hibyte); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, /*arg0*/0x24, regX, lobyte, hibyte); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, /*arg0*/0x24, regX, lobyte, hibyte); + // test addressing is working ... + for (uint8_t lobyte=0xfd; lobyte>0xf0; lobyte++) { + uint8_t hibyte = 0x1f; + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, lobyte, hibyte, /*carry*/false); + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, lobyte, hibyte, /*carry*/true); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, lobyte, hibyte, /*carry*/false); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, lobyte, hibyte, /*carry*/true); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, lobyte, hibyte, /*carry*/false); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, lobyte, hibyte, /*carry*/true); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, lobyte, hibyte, /*carry*/false); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, lobyte, hibyte, /*carry*/true); } + +#ifdef ANDROID + fprintf(GREATEST_STDOUT, "...OK\n"); +#endif } - -#ifdef ANDROID - fprintf(GREATEST_STDOUT, "...OK\n"); -#endif - A2_REMOVE_TEST(func); - } + } while (0); // -------------------------------- - A2_ADD_TEST(test_ADC_ind_y); - A2_ADD_TEST(test_AND_ind_y); - A2_ADD_TEST(test_CMP_ind_y); - A2_ADD_TEST(test_EOR_ind_y); - A2_ADD_TEST(test_LDA_ind_y); - A2_ADD_TEST(test_ORA_ind_y); - A2_ADD_TEST(test_SBC_ind_y); - A2_ADD_TEST(test_STA_ind_y); - HASH_ITER(hh, test_funcs, func, tmp) { - fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); - // test addressing is working ... - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, /*arg0*/0x24, /*regY*/0x10, /*val_zp0*/0x22, /*val_zp1*/0x1f); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, /*arg0*/0x24, /*regY*/0x80, /*val_zp0*/0x80, /*val_zp1*/0x1f); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, /*arg0*/0x24, /*regY*/0xAA, /*val_zp0*/0xAA, /*val_zp1*/0x1f); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, /*arg0*/0x24, /*regY*/0x80, /*val_zp0*/0x90, /*val_zp1*/0xff); + do { + test_func_t funcs[] = { + { "test_ADC_abs_x", (void(*)(void))test_ADC_abs_x, }, + { "test_AND_abs_x", (void(*)(void))test_AND_abs_x, }, + { "test_ASL_abs_x", (void(*)(void))test_ASL_abs_x, }, + { "test_BIT_abs_x", (void(*)(void))test_BIT_abs_x, }, + { "test_CMP_abs_x", (void(*)(void))test_CMP_abs_x, }, + { "test_DEC_abs_x", (void(*)(void))test_DEC_abs_x, }, + { "test_EOR_abs_x", (void(*)(void))test_EOR_abs_x, }, + { "test_INC_abs_x", (void(*)(void))test_INC_abs_x, }, + { "test_LDA_abs_x", (void(*)(void))test_LDA_abs_x, }, + { "test_LDY_abs_x", (void(*)(void))test_LDY_abs_x, }, + { "test_LSR_abs_x", (void(*)(void))test_LSR_abs_x, }, + { "test_ORA_abs_x", (void(*)(void))test_ORA_abs_x, }, + { "test_ROL_abs_x", (void(*)(void))test_ROL_abs_x, }, + { "test_ROR_abs_x", (void(*)(void))test_ROR_abs_x, }, + { "test_SBC_abs_x", (void(*)(void))test_SBC_abs_x, }, + { "test_STA_abs_x", (void(*)(void))test_STA_abs_x, }, + { "test_STZ_abs_x", (void(*)(void))test_STZ_abs_x, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); -#ifdef ANDROID - fprintf(GREATEST_STDOUT, "...OK\n"); -#endif - A2_REMOVE_TEST(func); - } + for (unsigned int i=0; iname); + fprintf(GREATEST_STDOUT, "\n%s :\n", name); - // test addressing is working ... - for (uint8_t lobyte=0xfd; lobyte>0xf0; lobyte++) { + // test that addressing is working ... uint8_t hibyte = 0x1f; - A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, /*arg0*/0x00, /*lobyte*/0x33, /*hibyte*/0x1f); - A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, /*arg0*/0x7f, /*lobyte*/0x33, /*hibyte*/0x1f); - A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, /*arg0*/0xAB, /*lobyte*/0x33, /*hibyte*/0x1f); - A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, /*arg0*/0xff, /*lobyte*/0x33, /*hibyte*/0x1f); - } + uint8_t lobyte = 0x20; + for (uint8_t regX=0x50; regX>0x4f; regX+=0x30) { + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, regX, lobyte, hibyte, /*carry*/true); + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, regX, lobyte, hibyte, /*carry*/false); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, regX, lobyte, hibyte, /*carry*/true); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, regX, lobyte, hibyte, /*carry*/false); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, regX, lobyte, hibyte, /*carry*/true); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, regX, lobyte, hibyte, /*carry*/false); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, regX, lobyte, hibyte, /*carry*/true); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, regX, lobyte, hibyte, /*carry*/false); + + RUN_TESTp(func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff, /*carry*/true); // wrap to zpage + RUN_TESTp(func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff, /*carry*/false); // wrap to zpage + } #ifdef ANDROID - fprintf(GREATEST_STDOUT, "...OK\n"); + fprintf(GREATEST_STDOUT, "...OK\n"); #endif - A2_REMOVE_TEST(func); - } + } + } while (0); + + // -------------------------------- + + do { + test_func_t funcs[] = { + { "test_ADC_abs_y", (void(*)(void))test_ADC_abs_y, }, + { "test_AND_abs_y", (void(*)(void))test_AND_abs_y, }, + { "test_CMP_abs_y", (void(*)(void))test_CMP_abs_y, }, + { "test_EOR_abs_y", (void(*)(void))test_EOR_abs_y, }, + { "test_LDA_abs_y", (void(*)(void))test_LDA_abs_y, }, + { "test_LDX_abs_y", (void(*)(void))test_LDX_abs_y, }, + { "test_ORA_abs_y", (void(*)(void))test_ORA_abs_y, }, + { "test_SBC_abs_y", (void(*)(void))test_SBC_abs_y, }, + { "test_STA_abs_y", (void(*)(void))test_STA_abs_y, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); + + for (unsigned int i=0; i0x4f; regY+=0x30) { + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, regY, lobyte, hibyte); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, regY, lobyte, hibyte); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, regY, lobyte, hibyte); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, regY, lobyte, hibyte); + RUN_TESTp(func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff); // wrap to zpage + } + +#ifdef ANDROID + fprintf(GREATEST_STDOUT, "...OK\n"); +#endif + } + } while (0); + + // -------------------------------- + + do { + test_func_t funcs[] = { + { "test_ADC_ind_x", (void(*)(void))test_ADC_ind_x, }, + { "test_AND_ind_x", (void(*)(void))test_AND_ind_x, }, + { "test_CMP_ind_x", (void(*)(void))test_CMP_ind_x, }, + { "test_EOR_ind_x", (void(*)(void))test_EOR_ind_x, }, + { "test_LDA_ind_x", (void(*)(void))test_LDA_ind_x, }, + { "test_ORA_ind_x", (void(*)(void))test_ORA_ind_x, }, + { "test_SBC_ind_x", (void(*)(void))test_SBC_ind_x, }, + { "test_STA_ind_x", (void(*)(void))test_STA_ind_x, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); + + for (unsigned int i=0; i0xf0; lobyte++) { + for (uint8_t regX=0x42; regX>0x3F; regX+=0x40) { + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, /*arg0*/0x24, regX, lobyte, hibyte); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, /*arg0*/0x24, regX, lobyte, hibyte); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, /*arg0*/0x24, regX, lobyte, hibyte); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, /*arg0*/0x24, regX, lobyte, hibyte); + } + } + +#ifdef ANDROID + fprintf(GREATEST_STDOUT, "...OK\n"); +#endif + } + } while (0); + + // -------------------------------- + + do { + test_func_t funcs[] = { + { "test_ADC_ind_y", (void(*)(void))test_ADC_ind_y, }, + { "test_AND_ind_y", (void(*)(void))test_AND_ind_y, }, + { "test_CMP_ind_y", (void(*)(void))test_CMP_ind_y, }, + { "test_EOR_ind_y", (void(*)(void))test_EOR_ind_y, }, + { "test_LDA_ind_y", (void(*)(void))test_LDA_ind_y, }, + { "test_ORA_ind_y", (void(*)(void))test_ORA_ind_y, }, + { "test_SBC_ind_y", (void(*)(void))test_SBC_ind_y, }, + { "test_STA_ind_y", (void(*)(void))test_STA_ind_y, }, + }; + const unsigned int count = sizeof(funcs) / sizeof(test_func_t); + + for (unsigned int i=0; i0xf0; lobyte++) { + RUN_TESTp(func, /*A*/0x0f, /*val*/0x0f, /*arg0*/0x00, /*lobyte*/0x33, /*hibyte*/0x1f); + RUN_TESTp(func, /*A*/0x7f, /*val*/0x7f, /*arg0*/0x7f, /*lobyte*/0x33, /*hibyte*/0x1f); + RUN_TESTp(func, /*A*/0xaa, /*val*/0x55, /*arg0*/0xAB, /*lobyte*/0x33, /*hibyte*/0x1f); + RUN_TESTp(func, /*A*/0x00, /*val*/0xff, /*arg0*/0xff, /*lobyte*/0x33, /*hibyte*/0x1f); + } + +#ifdef ANDROID + fprintf(GREATEST_STDOUT, "...OK\n"); +#endif + } + } while (0); } SUITE(test_suite_cpu); diff --git a/src/test/testdisk.c b/src/test/testdisk.c index 6008d28a..d60bc329 100644 --- a/src/test/testdisk.c +++ b/src/test/testdisk.c @@ -72,7 +72,7 @@ TEST test_boot_disk_bytes() { ASSERT(expectedSize == EXPECTED_DISK_TRACE_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_DISK_TRACE_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_DISK_TRACE_FILE_SIZE); if (fread(buf, 1, EXPECTED_DISK_TRACE_FILE_SIZE, fp) != EXPECTED_DISK_TRACE_FILE_SIZE) { ASSERT(false); } @@ -85,7 +85,7 @@ TEST test_boot_disk_bytes() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); PASS(); } @@ -120,7 +120,7 @@ TEST test_boot_disk_bytes_nib() { ASSERT(expectedSize == EXPECTED_DISK_TRACE_NIB_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_DISK_TRACE_NIB_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_DISK_TRACE_NIB_FILE_SIZE); if (fread(buf, 1, EXPECTED_DISK_TRACE_NIB_FILE_SIZE, fp) != EXPECTED_DISK_TRACE_NIB_FILE_SIZE) { ASSERT(false); } @@ -133,7 +133,7 @@ TEST test_boot_disk_bytes_nib() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); PASS(); } @@ -173,7 +173,7 @@ TEST test_boot_disk_bytes_po() { ASSERT(expectedSize == EXPECTED_DISK_TRACE_PO_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_DISK_TRACE_PO_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_DISK_TRACE_PO_FILE_SIZE); if (fread(buf, 1, EXPECTED_DISK_TRACE_PO_FILE_SIZE, fp) != EXPECTED_DISK_TRACE_PO_FILE_SIZE) { ASSERT(false); } @@ -186,7 +186,7 @@ TEST test_boot_disk_bytes_po() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); PASS(); } @@ -237,7 +237,7 @@ TEST test_read_null_bytes() { c_debugger_go(); ASSERT(apple_ii_64k[0][WATCHPOINT_ADDR] == TEST_FINISHED); - ASSERT(apple_ii_64k[0][TESTOUT_ADDR] == 0x00); + ASSERT(apple_ii_64k[0][TESTOUT_ADDR] == 0xFF); PASS(); } @@ -368,7 +368,7 @@ TEST test_disk_bytes_savehello_dsk() { ASSERT(expectedSize == EXPECTED_DISKWRITE_TRACE_DSK_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_DISKWRITE_TRACE_DSK_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_DISKWRITE_TRACE_DSK_FILE_SIZE); if (fread(buf, 1, EXPECTED_DISKWRITE_TRACE_DSK_FILE_SIZE, fp) != EXPECTED_DISKWRITE_TRACE_DSK_FILE_SIZE) { ASSERT(false); } @@ -381,7 +381,7 @@ TEST test_disk_bytes_savehello_dsk() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); REBOOT_TO_DOS(); c_debugger_go(); @@ -404,7 +404,7 @@ TEST test_disk_bytes_savehello_dsk() { ASSERT(expectedSize == DSK_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(DSK_SIZE); + unsigned char *buf = MALLOC(DSK_SIZE); if (fread(buf, 1, DSK_SIZE, fp) != DSK_SIZE) { ASSERT(false); } @@ -462,7 +462,7 @@ TEST test_disk_bytes_savehello_nib() { ASSERT(expectedSize == EXPECTED_DISKWRITE_TRACE_NIB_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_DISKWRITE_TRACE_NIB_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_DISKWRITE_TRACE_NIB_FILE_SIZE); if (fread(buf, 1, EXPECTED_DISKWRITE_TRACE_NIB_FILE_SIZE, fp) != EXPECTED_DISKWRITE_TRACE_NIB_FILE_SIZE) { ASSERT(false); } @@ -475,7 +475,7 @@ TEST test_disk_bytes_savehello_nib() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); REBOOT_TO_DOS(); c_debugger_go(); @@ -498,7 +498,7 @@ TEST test_disk_bytes_savehello_nib() { ASSERT(expectedSize == NIB_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(NIB_SIZE); + unsigned char *buf = MALLOC(NIB_SIZE); if (fread(buf, 1, NIB_SIZE, fp) != NIB_SIZE) { ASSERT(false); } @@ -556,7 +556,7 @@ TEST test_disk_bytes_savehello_po() { ASSERT(expectedSize == EXPECTED_DISKWRITE_TRACE_PO_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_DISKWRITE_TRACE_PO_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_DISKWRITE_TRACE_PO_FILE_SIZE); if (fread(buf, 1, EXPECTED_DISKWRITE_TRACE_PO_FILE_SIZE, fp) != EXPECTED_DISKWRITE_TRACE_PO_FILE_SIZE) { ASSERT(false); } @@ -569,7 +569,7 @@ TEST test_disk_bytes_savehello_po() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); REBOOT_TO_DOS(); c_debugger_go(); @@ -592,7 +592,7 @@ TEST test_disk_bytes_savehello_po() { ASSERT(expectedSize == DSK_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(DSK_SIZE); + unsigned char *buf = MALLOC(DSK_SIZE); if (fread(buf, 1, DSK_SIZE, fp) != DSK_SIZE) { ASSERT(false); } @@ -669,7 +669,7 @@ TEST test_outofspace_dsk() { ASSERT(expectedSize == EXPECTED_OOS_DSK_TRACE_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_OOS_DSK_TRACE_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_OOS_DSK_TRACE_FILE_SIZE); if (fread(buf, 1, EXPECTED_OOS_DSK_TRACE_FILE_SIZE, fp) != EXPECTED_OOS_DSK_TRACE_FILE_SIZE) { ASSERT(false); } @@ -682,7 +682,7 @@ TEST test_outofspace_dsk() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); REBOOT_TO_DOS(); c_debugger_go(); @@ -705,7 +705,7 @@ TEST test_outofspace_dsk() { ASSERT(expectedSize == DSK_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(DSK_SIZE); + unsigned char *buf = MALLOC(DSK_SIZE); if (fread(buf, 1, DSK_SIZE, fp) != DSK_SIZE) { ASSERT(false); } @@ -760,7 +760,7 @@ TEST test_outofspace_nib() { ASSERT(expectedSize == NIB_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(NIB_SIZE); + unsigned char *buf = MALLOC(NIB_SIZE); if (fread(buf, 1, NIB_SIZE, fp) != NIB_SIZE) { ASSERT(false); } @@ -815,7 +815,7 @@ TEST test_outofspace_po() { ASSERT(expectedSize == DSK_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(DSK_SIZE); + unsigned char *buf = MALLOC(DSK_SIZE); if (fread(buf, 1, DSK_SIZE, fp) != DSK_SIZE) { ASSERT(false); } @@ -937,7 +937,7 @@ TEST test_bload_trace_dsk() { ASSERT(expectedSize == EXPECTED_BLOAD_TRACE_DSK_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_BLOAD_TRACE_DSK_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_BLOAD_TRACE_DSK_FILE_SIZE); if (fread(buf, 1, EXPECTED_BLOAD_TRACE_DSK_FILE_SIZE, fp) != EXPECTED_BLOAD_TRACE_DSK_FILE_SIZE) { ASSERT(false); } @@ -950,7 +950,7 @@ TEST test_bload_trace_dsk() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); disk6_eject(0); @@ -1055,7 +1055,7 @@ TEST test_bload_trace_nib() { ASSERT(expectedSize == EXPECTED_BLOAD_TRACE_NIB_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_BLOAD_TRACE_NIB_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_BLOAD_TRACE_NIB_FILE_SIZE); if (fread(buf, 1, EXPECTED_BLOAD_TRACE_NIB_FILE_SIZE, fp) != EXPECTED_BLOAD_TRACE_NIB_FILE_SIZE) { ASSERT(false); } @@ -1068,7 +1068,7 @@ TEST test_bload_trace_nib() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); disk6_eject(0); @@ -1173,7 +1173,7 @@ TEST test_bload_trace_po() { ASSERT(expectedSize == EXPECTED_BLOAD_TRACE_PO_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_BLOAD_TRACE_PO_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_BLOAD_TRACE_PO_FILE_SIZE); if (fread(buf, 1, EXPECTED_BLOAD_TRACE_PO_FILE_SIZE, fp) != EXPECTED_BLOAD_TRACE_PO_FILE_SIZE) { ASSERT(false); } @@ -1186,7 +1186,7 @@ TEST test_bload_trace_po() { } while(0); unlink(disk); - FREE(disk); + ASPRINTF_FREE(disk); disk6_eject(0); @@ -1288,7 +1288,7 @@ TEST test_data_stability_dsk() { ASSERT(expectedSize == EXPECTED_STABILITY_DSK_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_STABILITY_DSK_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_STABILITY_DSK_FILE_SIZE); if (fread(buf, 1, EXPECTED_STABILITY_DSK_FILE_SIZE, fp) != EXPECTED_STABILITY_DSK_FILE_SIZE) { ASSERT(false); } @@ -1323,7 +1323,7 @@ TEST test_data_stability_nib() { ASSERT(expectedSize == EXPECTED_STABILITY_NIB_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_STABILITY_NIB_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_STABILITY_NIB_FILE_SIZE); if (fread(buf, 1, EXPECTED_STABILITY_NIB_FILE_SIZE, fp) != EXPECTED_STABILITY_NIB_FILE_SIZE) { ASSERT(false); } @@ -1358,7 +1358,7 @@ TEST test_data_stability_po() { ASSERT(expectedSize == EXPECTED_STABILITY_PO_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_STABILITY_PO_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_STABILITY_PO_FILE_SIZE); if (fread(buf, 1, EXPECTED_STABILITY_PO_FILE_SIZE, fp) != EXPECTED_STABILITY_PO_FILE_SIZE) { ASSERT(false); } @@ -1436,12 +1436,16 @@ GREATEST_MAIN_DEFS(); static char **test_argv = NULL; static int test_argc = 0; -static void *test_thread(void *dummyptr) { +static int _test_thread(void) { int argc = test_argc; char **argv = test_argv; GREATEST_MAIN_BEGIN(); RUN_SUITE(test_suite_disk); GREATEST_MAIN_END(); +} + +static void *test_thread(void *dummyptr) { + _test_thread(); return NULL; } diff --git a/src/test/testdisplay.c b/src/test/testdisplay.c index 201954cc..73577c4e 100644 --- a/src/test/testdisplay.c +++ b/src/test/testdisplay.c @@ -32,7 +32,7 @@ static void testdisplay_teardown(void *arg) { // Various Display Tests ... TEST test_boot_disk() { - test_setup_boot_disk("testdisplay1.nib.gz", 1); + test_setup_boot_disk("testdisplay1.dsk.gz", 1); BOOT_TO_DOS(); @@ -306,13 +306,13 @@ TEST test_80col_hires() { c_debugger_go(); ASSERT(apple_ii_64k[0][WATCHPOINT_ADDR] == TEST_FINISHED); - ASSERT_SHA("10F63A7B11EBF5019AE6D1F64AA7BACEA903426D"); + ASSERT_SHA("126363F103F3A24BB2EB2AEC5B4972F46F7CA24B"); apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; c_debugger_go(); ASSERT(apple_ii_64k[0][WATCHPOINT_ADDR] == TEST_FINISHED); - ASSERT_SHA("CC81BD3FE7055126D3FA13231CBD86E7C49590AA"); + ASSERT_SHA("91F63831B6D1145446F0DBACE8EBD284B5690D81"); PASS(); } @@ -443,12 +443,16 @@ GREATEST_MAIN_DEFS(); static char **test_argv = NULL; static int test_argc = 0; -static void *test_thread(void *dummyptr) { +static int _test_thread(void) { int argc = test_argc; char **argv = test_argv; GREATEST_MAIN_BEGIN(); RUN_SUITE(test_suite_display); GREATEST_MAIN_END(); +} + +static void *test_thread(void *dummyptr) { + _test_thread(); return NULL; } diff --git a/src/test/testtrace.c b/src/test/testtrace.c index a13d4bc9..eb8a62ff 100644 --- a/src/test/testtrace.c +++ b/src/test/testtrace.c @@ -70,7 +70,7 @@ TEST test_boot_disk_cputrace() { long expectedSize = ftell(fp); ASSERT(expectedSize == EXPECTED_CPU_TRACE_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_CPU_TRACE_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_CPU_TRACE_FILE_SIZE); if (fread(buf, 1, EXPECTED_CPU_TRACE_FILE_SIZE, fp) != EXPECTED_CPU_TRACE_FILE_SIZE) { ASSERT(false); } @@ -121,7 +121,7 @@ TEST test_cputrace_hello_dsk() { long expectedSize = ftell(fp); ASSERT(expectedSize == EXPECTED_CPUTRACE_HELLO_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_CPUTRACE_HELLO_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_CPUTRACE_HELLO_FILE_SIZE); if (fread(buf, 1, EXPECTED_CPUTRACE_HELLO_FILE_SIZE, fp) != EXPECTED_CPUTRACE_HELLO_FILE_SIZE) { ASSERT(false); } @@ -171,7 +171,7 @@ TEST test_cputrace_hello_nib() { long expectedSize = ftell(fp); ASSERT(expectedSize == EXPECTED_CPUTRACE_HELLO_NIB_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_CPUTRACE_HELLO_NIB_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_CPUTRACE_HELLO_NIB_FILE_SIZE); if (fread(buf, 1, EXPECTED_CPUTRACE_HELLO_NIB_FILE_SIZE, fp) != EXPECTED_CPUTRACE_HELLO_NIB_FILE_SIZE) { ASSERT(false); } @@ -221,7 +221,7 @@ TEST test_cputrace_hello_po() { long expectedSize = ftell(fp); ASSERT(expectedSize == EXPECTED_CPUTRACE_HELLO_PO_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_CPUTRACE_HELLO_PO_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_CPUTRACE_HELLO_PO_FILE_SIZE); if (fread(buf, 1, EXPECTED_CPUTRACE_HELLO_PO_FILE_SIZE, fp) != EXPECTED_CPUTRACE_HELLO_PO_FILE_SIZE) { ASSERT(false); } @@ -267,7 +267,7 @@ TEST test_boot_disk_vmtrace() { ASSERT(expectedSize == EXPECTED_VM_TRACE_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_VM_TRACE_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_VM_TRACE_FILE_SIZE); if (fread(buf, 1, EXPECTED_VM_TRACE_FILE_SIZE, fp) != EXPECTED_VM_TRACE_FILE_SIZE) { ASSERT(false); } @@ -315,7 +315,7 @@ TEST test_boot_disk_vmtrace_nib() { ASSERT(expectedSize == EXPECTED_VM_TRACE_NIB_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_VM_TRACE_NIB_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_VM_TRACE_NIB_FILE_SIZE); if (fread(buf, 1, EXPECTED_VM_TRACE_NIB_FILE_SIZE, fp) != EXPECTED_VM_TRACE_NIB_FILE_SIZE) { ASSERT(false); } @@ -363,7 +363,7 @@ TEST test_boot_disk_vmtrace_po() { ASSERT(expectedSize == EXPECTED_VM_TRACE_PO_FILE_SIZE); fseek(fp, 0, SEEK_SET); - unsigned char *buf = malloc(EXPECTED_VM_TRACE_PO_FILE_SIZE); + unsigned char *buf = MALLOC(EXPECTED_VM_TRACE_PO_FILE_SIZE); if (fread(buf, 1, EXPECTED_VM_TRACE_PO_FILE_SIZE, fp) != EXPECTED_VM_TRACE_PO_FILE_SIZE) { ASSERT(false); } diff --git a/src/test/testvm.c b/src/test/testvm.c index 4f0035bc..ae1c2563 100644 --- a/src/test/testvm.c +++ b/src/test/testvm.c @@ -33,7 +33,7 @@ static void testvm_teardown(void *arg) { // VM TESTS ... TEST test_boot_disk() { - test_setup_boot_disk("testvm1.nib.gz", 1); + test_setup_boot_disk("testvm1.dsk.gz", 1); BOOT_TO_DOS(); @@ -1071,8 +1071,6 @@ TEST test_HIRES_off(bool flag_ramrd, bool flag_ramwrt) { uint32_t switch_save = softswitches; uint8_t *save_base_textrd = base_textrd; uint8_t *save_base_textwrt = base_textwrt; - uint8_t *save_base_hgrrd = base_hgrrd; - uint8_t *save_base_hgrwrt = base_hgrwrt; int save_current_page = video__current_page; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; @@ -1288,8 +1286,6 @@ TEST test_lc_c082() { uint8_t *save_base_textwrt = base_textwrt; uint8_t *save_base_hgrrd = base_hgrrd; uint8_t *save_base_hgrwrt = base_hgrwrt; - uint8_t *save_base_d000_wrt = base_d000_wrt; - uint8_t *save_base_e000_wrt = base_e000_wrt; int save_current_page = video__current_page; ASM_INIT(); @@ -1541,8 +1537,6 @@ TEST test_lc_c08a() { uint8_t *save_base_textwrt = base_textwrt; uint8_t *save_base_hgrrd = base_hgrrd; uint8_t *save_base_hgrwrt = base_hgrwrt; - uint8_t *save_base_d000_wrt = base_d000_wrt; - uint8_t *save_base_e000_wrt = base_e000_wrt; int save_current_page = video__current_page; ASM_INIT(); @@ -1755,11 +1749,8 @@ TEST test_80store_on(bool flag_hires, bool flag_page2) { ASSERT(flag_page2 ? (softswitches & SS_PAGE2) : !(softswitches & SS_PAGE2) ); uint32_t switch_save = softswitches; - uint8_t *save_base_textrd = base_textrd; - uint8_t *save_base_textwrt = base_textwrt; uint8_t *save_base_hgrrd = base_hgrrd; uint8_t *save_base_hgrwrt = base_hgrwrt; - int save_current_page = video__current_page; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; c_debugger_go(); @@ -1856,11 +1847,6 @@ TEST test_80store_off(bool flag_ramrd, bool flag_ramwrt, bool flag_page2) { ASSERT(flag_page2 ? (softswitches & SS_PAGE2) : !(softswitches & SS_PAGE2) ); uint32_t switch_save = softswitches; - uint8_t *save_base_textrd = base_textrd; - uint8_t *save_base_textwrt = base_textwrt; - uint8_t *save_base_hgrrd = base_hgrrd; - uint8_t *save_base_hgrwrt = base_hgrwrt; - int save_current_page = video__current_page; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; apple_ii_64k[1][WATCHPOINT_ADDR] = 0x00; @@ -1984,7 +1970,6 @@ TEST test_ramrd_main(bool flag_80store, bool flag_hires) { ASSERT(flag_hires ? (softswitches & SS_HIRES) : !(softswitches & SS_HIRES) ); uint32_t switch_save = softswitches; - uint8_t *save_base_ramrd = base_ramrd; uint8_t *save_base_ramwrt = base_ramwrt; uint8_t *save_base_textrd = base_textrd; uint8_t *save_base_textwrt = base_textwrt; @@ -2066,7 +2051,6 @@ TEST test_ramrd_aux(bool flag_80store, bool flag_hires) { ASSERT(flag_hires ? (softswitches & SS_HIRES) : !(softswitches & SS_HIRES) ); uint32_t switch_save = softswitches; - uint8_t *save_base_ramrd = base_ramrd; uint8_t *save_base_ramwrt = base_ramwrt; uint8_t *save_base_textrd = base_textrd; uint8_t *save_base_textwrt = base_textwrt; @@ -2184,7 +2168,6 @@ TEST test_ramwrt_main(bool flag_80store, bool flag_hires) { uint32_t switch_save = softswitches; uint8_t *save_base_ramrd = base_ramrd; - uint8_t *save_base_ramwrt = base_ramwrt; uint8_t *save_base_textrd = base_textrd; uint8_t *save_base_textwrt = base_textwrt; uint8_t *save_base_hgrrd = base_hgrrd; @@ -2265,7 +2248,6 @@ TEST test_ramwrt_aux(bool flag_80store, bool flag_hires) { uint32_t switch_save = softswitches; uint8_t *save_base_ramrd = base_ramrd; - uint8_t *save_base_ramwrt = base_ramwrt; uint8_t *save_base_textrd = base_textrd; uint8_t *save_base_textwrt = base_textwrt; uint8_t *save_base_hgrrd = base_hgrrd; @@ -2602,10 +2584,6 @@ TEST test_80col_off() { ASSERT((softswitches & SS_80COL)); uint32_t switch_save = softswitches; - uint8_t *save_base_d000_rd = base_d000_rd; - uint8_t *save_base_d000_wrt = base_d000_wrt; - uint8_t *save_base_e000_rd = base_e000_rd; - uint8_t *save_base_e000_wrt = base_e000_wrt; int save_current_page = video__current_page; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; @@ -2713,10 +2691,6 @@ TEST test_altchar_off() { ASSERT((softswitches & SS_ALTCHAR)); uint32_t switch_save = softswitches; - uint8_t *save_base_d000_rd = base_d000_rd; - uint8_t *save_base_d000_wrt = base_d000_wrt; - uint8_t *save_base_e000_rd = base_e000_rd; - uint8_t *save_base_e000_wrt = base_e000_wrt; int save_current_page = video__current_page; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; @@ -2824,10 +2798,6 @@ TEST test_ioudis_off() { ASSERT((softswitches & SS_IOUDIS)); uint32_t switch_save = softswitches; - uint8_t *save_base_d000_rd = base_d000_rd; - uint8_t *save_base_d000_wrt = base_d000_wrt; - uint8_t *save_base_e000_rd = base_e000_rd; - uint8_t *save_base_e000_wrt = base_e000_wrt; int save_current_page = video__current_page; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; @@ -2943,10 +2913,6 @@ TEST test_dhires_off(bool flag_ioudis/* FIXME TODO : possibly testing a existing ASSERT((softswitches & SS_DHIRES)); uint32_t switch_save = softswitches; - uint8_t *save_base_d000_rd = base_d000_rd; - uint8_t *save_base_d000_wrt = base_d000_wrt; - uint8_t *save_base_e000_rd = base_e000_rd; - uint8_t *save_base_e000_wrt = base_e000_wrt; int save_current_page = video__current_page; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; @@ -3023,7 +2989,6 @@ TEST test_c3rom_internal() { ASSERT(!(softswitches & SS_C3ROM)); uint32_t switch_save = softswitches; - uint8_t *save_base_c3rom = base_c3rom; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; c_debugger_go(); @@ -3145,10 +3110,6 @@ TEST test_cxrom_internal() { ASSERT(!(softswitches & SS_CXROM)); uint32_t switch_save = softswitches; - uint8_t *save_base_cxrom = base_cxrom; - uint8_t *save_base_c3rom = base_c3rom; - uint8_t *save_base_c4rom = base_c4rom; - uint8_t *save_base_c5rom = base_c5rom; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; c_debugger_go(); @@ -3195,7 +3156,6 @@ TEST test_cxrom_peripheral(bool flag_c3rom) { ASSERT((softswitches & SS_CXROM)); uint32_t switch_save = softswitches; - uint8_t *save_base_cxrom = base_cxrom; uint8_t *save_base_c3rom = base_c3rom; apple_ii_64k[0][WATCHPOINT_ADDR] = 0x00; @@ -3462,12 +3422,16 @@ GREATEST_MAIN_DEFS(); static char **test_argv = NULL; static int test_argc = 0; -static void *test_thread(void *dummyptr) { +static int _test_thread(void) { int argc = test_argc; char **argv = test_argv; GREATEST_MAIN_BEGIN(); RUN_SUITE(test_suite_vm); GREATEST_MAIN_END(); +} + +static void *test_thread(void *dummyptr) { + _test_thread(); return NULL; } diff --git a/src/timing.c b/src/timing.c index db9c7b51..0a5b3532 100644 --- a/src/timing.c +++ b/src/timing.c @@ -126,7 +126,7 @@ struct timespec timespec_diff(struct timespec start, struct timespec end, bool * return t; } -static inline struct timespec timespec_add(struct timespec start, unsigned long nsecs) { +struct timespec timespec_add(struct timespec start, unsigned long nsecs) { start.tv_nsec += nsecs; if (start.tv_nsec > NANOSECONDS_PER_SECOND) @@ -178,7 +178,11 @@ void reinitialize(void) { void timing_initialize(void) { #if !TESTING +# ifdef __APPLE__ +# warning FIXME TODO : this assert is firing on iOS port ... but the assert is valid ... fix soon +# else assert(cpu_isPaused() || (pthread_self() == cpu_thread_id)); +# endif #endif _timing_initialize(alt_speed_enabled ? cpu_altscale_factor : cpu_scale_factor); } diff --git a/src/timing.h b/src/timing.h index 3855bddf..4e3dafba 100644 --- a/src/timing.h +++ b/src/timing.h @@ -66,6 +66,7 @@ extern READONLY pthread_t cpu_thread_id; * calculate the difference between two timespec structures */ struct timespec timespec_diff(struct timespec start, struct timespec end, bool *negative); +struct timespec timespec_add(struct timespec start, unsigned long nsecs); /* * start CPU thread diff --git a/src/video/SolidColor.fsh b/src/video/SolidColor.fsh new file mode 100644 index 00000000..50232353 --- /dev/null +++ b/src/video/SolidColor.fsh @@ -0,0 +1,25 @@ +#ifdef GL_ES +precision highp float; +#endif + +// Declare inputs and outputs +// gl_FragColor : Implicitly declare in fragments shaders less than 1.40. +// Output color of our fragment. +// fragColor : Output color of our fragment. Basically the same as gl_FragColor, +// but we must explicitly declared this in shaders version 1.40 and +// above. + +#if __VERSION__ >= 140 +out vec4 fragColor; +#endif + +#if __VERSION__ >= 140 +#define OUTPUT_RED fragColor = vec4(1.0, 0.0, 0.0, 1.0) +#else +#define OUTPUT_RED gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) +#endif + +void main(void) +{ + OUTPUT_RED; +} diff --git a/src/video/SolidColor.vsh b/src/video/SolidColor.vsh new file mode 100644 index 00000000..405d8b01 --- /dev/null +++ b/src/video/SolidColor.vsh @@ -0,0 +1,25 @@ +#ifdef GL_ES +precision highp float; +#endif + +// Declare our modelViewProjection matrix that we'll compute +// outside the shader and set each frame +uniform mat4 modelViewProjectionMatrix; + +// Declare inputs and outputs +// inPosition : Position attributes from the VAO/VBOs +// gl_Position : implicitly declared in all vertex shaders. Clip space position +// passed to rasterizer used to build the triangles + +#if __VERSION__ >= 140 +in vec4 inPosition; +#else +attribute vec4 inPosition; +#endif + +void main(void) +{ + // Transform the vertex by the model view projection matrix so + // the polygon shows up in the right place + gl_Position = modelViewProjectionMatrix * inPosition; +} diff --git a/src/video/glalert.c b/src/video/glalert.c index 774c957f..cdf1a504 100644 --- a/src/video/glalert.c +++ b/src/video/glalert.c @@ -26,8 +26,9 @@ static GLModel *messageModel = NULL; // ---------------------------------------------------------------------------- -static void *_create_alert(void) { - GLModelHUDElement *hudElement = (GLModelHUDElement *)calloc(sizeof(GLModelHUDElement), 1); +static void *_create_alert(GLModel *parent) { + parent->custom = glhud_createDefault(); + GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom; if (hudElement) { hudElement->colorScheme = RED_ON_BLACK; hudElement->blackIsTransparent = false; @@ -47,9 +48,7 @@ static inline void _set_alpha(unsigned int dstIdx) { } static void _alertToModel(char *message, unsigned int messageCols, unsigned int messageRows) { - if (!message) { - return; - } + assert(message); isEnabled = false; @@ -61,10 +60,20 @@ static void _alertToModel(char *message, unsigned int messageCols, unsigned int const unsigned int fbWidth = (messageCols * FONT80_WIDTH_PIXELS); const unsigned int fbHeight = (messageRows * FONT_HEIGHT_PIXELS); - messageModel = mdlCreateQuad(-0.3, -0.3, 0.7, 0.7, MODEL_DEPTH, fbWidth, fbHeight, (GLCustom){ + messageModel = mdlCreateQuad((GLModelParams_s){ + .skew_x = -0.3, + .skew_y = -0.3, + .z = MODEL_DEPTH, + .obj_w = 0.7, + .obj_h = 0.7, + .positionUsageHint = GL_STATIC_DRAW, // positions don't change + .tex_w = fbWidth, + .tex_h = fbHeight, + .texcoordUsageHint = GL_DYNAMIC_DRAW, // but texture (message pixels) does + }, (GLCustom){ .create = &_create_alert, .destroy = &glhud_destroyDefault, - }); + }); if (!messageModel) { LOG("OOPS cannot create animation message HUD model!"); break; @@ -78,7 +87,7 @@ static void _alertToModel(char *message, unsigned int messageCols, unsigned int hudElement->tpl = message; hudElement->pixWidth = fbWidth; hudElement->pixHeight = fbHeight; - hudElement->pixels = calloc(fbWidth * fbHeight, 1); + hudElement->pixels = MALLOC(fbWidth * fbHeight); if (!hudElement->pixels) { LOG("OOPS cannot create animation message intermediate framebuffer!"); break; @@ -209,7 +218,7 @@ static void _animation_showMessage(char *messageTemplate, unsigned int cols, uns const unsigned int framedStride = framedCols+1/*\0*/; const unsigned int sourceStride = cols+1/*\0*/; - char *message = calloc(framedStride*framedRows, 1); + char *message = CALLOC(framedStride*framedRows, 1); if (!message) { LOG("OOPS cannot create memory for animation message!"); return; @@ -233,7 +242,6 @@ static void _animation_showMessage(char *messageTemplate, unsigned int cols, uns nextMessage = message; nextMessageCols = framedCols; nextMessageRows = framedRows; - LOG("New message with %d cols %d rows", nextMessageCols, nextMessageRows); pthread_mutex_unlock(&messageMutex); } @@ -314,6 +322,49 @@ static void _animation_showDiskChosen(int drive) { _animation_showMessage(template, shownCols, DISK_ANIMATION_ROWS); } +static void _animation_showTrackSector(int drive, int track, int sect) { + +#define DISK_TRACK_SECTOR_ROWS 3 +#define DISK_TRACK_SECTOR_COLS 8 + + static char diskTrackSectorTemplate[DISK_TRACK_SECTOR_ROWS][DISK_TRACK_SECTOR_COLS+1] = { + " ", + "D / TT/S", + " ", + }; + char *template = diskTrackSectorTemplate[0]; + + char c = diskTrackSectorTemplate[1][2]; + switch (c) { + case '/': + c = '-'; + break; + case '-': + c = '\\'; + break; + case '\\': + c = '|'; + break; + case '|': + c = '/'; + break; + default: + assert(false && "should not happen"); + break; + } + snprintf(&diskTrackSectorTemplate[1][0], DISK_TRACK_SECTOR_COLS+1, "%d %c %02X/%01X", drive+1, c, track, sect); + + _animation_showMessage(template, DISK_TRACK_SECTOR_COLS, DISK_TRACK_SECTOR_ROWS); +} + +static void _animation_setEnableShowTrackSector(bool enabled) { + if (enabled) { + video_backend->animation_showTrackSector = &_animation_showTrackSector; + } else { + video_backend->animation_showTrackSector = NULL; + } +} + __attribute__((constructor(CTOR_PRIORITY_LATE))) static void _init_glalert(void) { LOG("Initializing message animation subsystem"); @@ -322,6 +373,8 @@ static void _init_glalert(void) { video_backend->animation_showPaused = &_animation_showPaused; video_backend->animation_showCPUSpeed = &_animation_showCPUSpeed; video_backend->animation_showDiskChosen = &_animation_showDiskChosen; + video_backend->animation_showTrackSector = &_animation_showTrackSector; + video_backend->animation_setEnableShowTrackSector = &_animation_setEnableShowTrackSector; glnode_registerNode(RENDER_MIDDLE, (GLNode){ .setup = &alert_init, diff --git a/src/video/glhudmodel.c b/src/video/glhudmodel.c index 011a964d..cccd0251 100644 --- a/src/video/glhudmodel.c +++ b/src/video/glhudmodel.c @@ -12,9 +12,128 @@ #include "glhudmodel.h" #include "glvideo.h" +// . . . +// . x . +// . . . +typedef struct EightPatchArgs_s { + GLModel *parent; + unsigned int pixelSize; + unsigned int glyphScale; + unsigned int fb_h; + unsigned int fb_w; + unsigned int srcIdx; + unsigned int dstIdx; +} EightPatchArgs_s; + +#ifndef NDEBUG +# define SET_TEX_PIXEL(OFF) \ + do { \ + assert((OFF) >= 0 && (OFF) < lastPoint); \ + *((PIXEL_TYPE*)(texPixels + (OFF))) |= SEMI_OPAQUE; \ + } while (0); +#else +# define SET_TEX_PIXEL(OFF) \ + do { \ + *((PIXEL_TYPE*)(texPixels + (OFF))) |= SEMI_OPAQUE; \ + } while (0); +#endif + +// Generates a semi-opaque halo effect around each glyph +static void _eightpatch_opaquePixelHaloFilter(const EightPatchArgs_s args) { + +#if USE_RGBA4444 +# define SEMI_OPAQUE (0x0C << SHIFT_A) +#else +# define SEMI_OPAQUE (0xC0 << SHIFT_A) +#endif + + const unsigned int pixelSize = args.pixelSize; + const unsigned int glyphScale = args.glyphScale; + const unsigned int fb_w = args.fb_w; + const unsigned int fb_h = args.fb_h; + const unsigned int srcIdx = args.srcIdx; + const unsigned int srcCol = (srcIdx % fb_w); + const unsigned int lastCol = (fb_w-1); + const unsigned int dstPointStride = pixelSize * glyphScale; + const unsigned int dstRowStride = fb_w * dstPointStride; + const unsigned int texRowStride = ((fb_w * glyphScale) * (FONT_GLYPH_SCALE_Y * glyphScale) * pixelSize); + const unsigned int lastPoint = ((fb_w * glyphScale) * (fb_h * glyphScale) * pixelSize); + + uint8_t *texPixels = args.parent->texPixels; + const int dstIdx0 = (int)args.dstIdx; + const int dstPre0 = dstIdx0 - texRowStride; // negative is okay + const int dstPost0 = dstIdx0 + texRowStride; + + // scale glyph data 1x, 2x, ... + + // north pixels + if (dstPre0 >= 0) { + int dstPre = dstPre0; + for (unsigned int k=0; kglyphMultiplier = 1; hudElement->colorScheme = RED_ON_BLACK; } return hudElement; @@ -23,6 +142,8 @@ void *glhud_createDefault(void) { void glhud_setupDefault(GLModel *parent) { GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom; + assert(hudElement->glyphMultiplier > 0); + char *submenu = (char *)(hudElement->tpl); const unsigned int cols = hudElement->tplWidth; const unsigned int rows = hudElement->tplHeight; @@ -31,74 +152,85 @@ void glhud_setupDefault(GLModel *parent) { // render template into indexed fb interface_plotMessage(fb, hudElement->colorScheme, submenu, cols, rows); - // Generate OpenGL color from indexed color + // generate OpenGL texture/color from indexed color const unsigned int fb_w = hudElement->pixWidth; const unsigned int fb_h = hudElement->pixHeight; - const unsigned int count = fb_w * fb_h; - const unsigned int countOut = count * sizeof(PIXEL_TYPE); - for (unsigned int srcIdx=0, dstIdx=0; srcIdxblackIsTransparent) { - // make black transparent - } else { - rgb |= ((PIXEL_TYPE)MAX_SATURATION << SHIFT_A); - } - *( (PIXEL_TYPE*)(parent->texPixels + dstIdx) ) = rgb; - } + const unsigned int pixelSize = sizeof(PIXEL_TYPE); + const unsigned int glyphScale = hudElement->glyphMultiplier; + const unsigned int dstPointStride = pixelSize * glyphScale; + const unsigned int dstRowStride = fb_w * dstPointStride; + const unsigned int texSubRowStride = dstRowStride * (glyphScale-1); - // Second pass to generate a semi-opaque halo effect around each glyph - if (hudElement->opaquePixelHalo) { - for (int // -negative index values allowed here ... - srcIdx=0, dstPre=-((fb_w+1)*sizeof(PIXEL_TYPE)), dstIdx=0, dstPost=((fb_w-1)*sizeof(PIXEL_TYPE)); - srcIdx= 0) { // north pixels - if (col != 0) { - *((PIXEL_TYPE*)(parent->texPixels + dstPre)) |= SEMI_OPAQUE; + for (unsigned int i=0; iblackIsTransparent) { + // black remains transparent + } else { + rgba |= ((PIXEL_TYPE)MAX_SATURATION << SHIFT_A); } - *((PIXEL_TYPE*)(parent->texPixels + dstPre + sizeof(PIXEL_TYPE) )) |= SEMI_OPAQUE; - if (col < fb_w-1) { - *((PIXEL_TYPE*)(parent->texPixels + dstPre + (2*sizeof(PIXEL_TYPE)) )) |= SEMI_OPAQUE; - } - } - if (col != 0) { // west pixel - *((PIXEL_TYPE*)(parent->texPixels + dstIdx - sizeof(PIXEL_TYPE) )) |= SEMI_OPAQUE; - } - - if (col < fb_w-1) { // east pixel - *((PIXEL_TYPE*)(parent->texPixels + dstIdx + sizeof(PIXEL_TYPE) )) |= SEMI_OPAQUE; - } - - if (dstPost < countOut) { // south pixels - if (col != 0) { - *((PIXEL_TYPE*)(parent->texPixels + dstPost)) |= SEMI_OPAQUE; - } - *((PIXEL_TYPE*)(parent->texPixels + dstPost + sizeof(PIXEL_TYPE) )) |= SEMI_OPAQUE; - if (col < fb_w-1) { - *((PIXEL_TYPE*)(parent->texPixels + dstPost + (2*sizeof(PIXEL_TYPE)) )) |= SEMI_OPAQUE; + // scale glyph data 1x, 2x, ... + unsigned int dstIdx = texIdx; + for (unsigned int k=0; ktexPixels + dstIdx) ) = rgba; + } + dstIdx -= dstPointStride; } } } +#ifndef NDEBUG + assert(srcIdx == srcLastPoint); + assert(texIdx == texLastPoint); +#endif + } while (0); + + if (hudElement->opaquePixelHalo) { + unsigned int srcIdx = 0; + unsigned int texIdx = 0; +#ifndef NDEBUG + const unsigned int srcLastPoint = fb_w * fb_h; + const unsigned int texLastPoint = ((fb_w * glyphScale) * (fb_h * glyphScale) * pixelSize); +#endif + for (unsigned int i=0; itexDirty = true; @@ -205,3 +337,24 @@ void glhud_quadModelToScreen(const GLModel *model, const int screenW, const int screenCoords[3] = yFlip1; } +float glhud_getTimedVisibility(struct timespec timingBegin, float minAlpha, float maxAlpha) { + + struct timespec now = { 0 }; + struct timespec deltat = { 0 }; + + clock_gettime(CLOCK_MONOTONIC, &now); + float alpha = minAlpha; + deltat = timespec_diff(timingBegin, now, NULL); + if (deltat.tv_sec == 0) { + alpha = maxAlpha; + if (deltat.tv_nsec >= NANOSECONDS_PER_SECOND/2) { + alpha -= ((float)deltat.tv_nsec-(NANOSECONDS_PER_SECOND/2)) / (float)(NANOSECONDS_PER_SECOND/2); + if (alpha < 0) { + alpha = 0; + } + } + } + + return alpha; +} + diff --git a/src/video/glhudmodel.h b/src/video/glhudmodel.h index a780d583..33f92ac0 100644 --- a/src/video/glhudmodel.h +++ b/src/video/glhudmodel.h @@ -15,20 +15,25 @@ #include "common.h" #include "video_util/modelUtil.h" +// HUD GLModel is basically just a quad/texture generated from the Apple //e bitmap font + #define HUD_CLASS(CLS, ...) \ MODEL_CLASS(CLS, \ char *tpl; /* ASCII template */ \ unsigned int tplWidth; /* template width */ \ unsigned int tplHeight; /* template height */ \ \ - uint8_t *pixels; /* raw texture/FB data */ \ - unsigned int pixWidth; /* FB width -- FIXME TODO : this is really the same as GLModel.texWidth */ \ - unsigned int pixHeight; /* FB height -- FIXME TODO : this is really the same as GLModel.texHeight */ \ + uint8_t *pixels; /* raw indexed data */ \ + unsigned int pixWidth; /* FB width -- this is the same as GLModel.texWidth if glyphMultiplier is 1 */ \ + unsigned int pixHeight; /* FB height -- this is the same as GLModel.texHeight if glyphMultiplier is 1 */ \ + unsigned int glyphMultiplier; \ \ interface_colorscheme_t colorScheme; \ bool blackIsTransparent; \ bool opaquePixelHalo; \ \ + struct timespec timingBegin; \ + \ __VA_ARGS__ \ ) @@ -37,6 +42,9 @@ HUD_CLASS(GLModelHUDElement); // default model creation void *glhud_createDefault(void); +// create custom HUD model +void *glhud_createCustom(unsigned int sizeofModel); + // default model setup void glhud_setupDefault(GLModel *parent); @@ -52,4 +60,7 @@ void glhud_screenToModel(const float x, const float y, const int screenW, const // orthographic translation of model coordinates to screen coordinates void glhud_quadModelToScreen(const GLModel *model, const int screenW, const int screenH, float screenCoords[4]); +// helper method to sync timing of fade out +float glhud_getTimedVisibility(struct timespec timingBegin, float minAlpha, float maxAlpha); + #endif diff --git a/src/video/glnode.c b/src/video/glnode.c index 20bd426e..c44f4c50 100644 --- a/src/video/glnode.c +++ b/src/video/glnode.c @@ -32,7 +32,7 @@ static glnode_array_node_s *tail = NULL; void glnode_registerNode(glnode_render_order_t order, GLNode node) { pthread_mutex_lock(&mutex); - glnode_array_node_s *arrayNode = malloc(sizeof(glnode_array_node_s)); + glnode_array_node_s *arrayNode = MALLOC(sizeof(glnode_array_node_s)); assert(arrayNode); arrayNode->next = NULL; arrayNode->last = NULL; diff --git a/src/video/gltouchjoy.c b/src/video/gltouchjoy.c index 867780d3..f5102add 100644 --- a/src/video/gltouchjoy.c +++ b/src/video/gltouchjoy.c @@ -18,8 +18,8 @@ #define MODEL_DEPTH -1/32.f #define TRACKING_NONE (-1) -#define AXIS_TEMPLATE_COLS 5 -#define AXIS_TEMPLATE_ROWS 5 +#define AXIS_TEMPLATE_COLS 3 +#define AXIS_TEMPLATE_ROWS 3 #define BUTTON_TEMPLATE_COLS 1 #define BUTTON_TEMPLATE_ROWS 1 @@ -30,13 +30,13 @@ #define BUTTON_FB_WIDTH (BUTTON_TEMPLATE_COLS * FONT80_WIDTH_PIXELS) #define BUTTON_FB_HEIGHT (BUTTON_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS) -#define AXIS_OBJ_W 0.4 -#define AXIS_OBJ_H 0.5 +#define AXIS_OBJ_W 0.15 +#define AXIS_OBJ_H 0.2 #define AXIS_OBJ_HALF_W (AXIS_OBJ_W/2.f) #define AXIS_OBJ_HALF_H (AXIS_OBJ_H/2.f) -#define BUTTON_OBJ_W 0.2 -#define BUTTON_OBJ_H 0.25 +#define BUTTON_OBJ_W 0.075 +#define BUTTON_OBJ_H 0.1 #define BUTTON_OBJ_HALF_W (BUTTON_OBJ_W/2.f) #define BUTTON_OBJ_HALF_H (BUTTON_OBJ_H/2.f) @@ -72,30 +72,168 @@ static struct { // TODO FIXME : support 2-players! } touchport = { 0 }; +#define RB_CLASS(CLS, ...) \ + MODEL_CLASS(CLS, \ + GLuint vertShader; \ + GLuint fragShader; \ + GLuint program; \ + GLint uniformMVPIdx;); + +RB_CLASS(GLModelRBJoystick); + // ---------------------------------------------------------------------------- +// joystick azimuth model -#warning FIXME TODO ... this can become a common helper function ... -static inline float _get_component_visibility(struct timespec timingBegin) { - struct timespec now = { 0 }; - struct timespec deltat = { 0 }; +static void _rb_destroy_model(GLModel *parent) { - clock_gettime(CLOCK_MONOTONIC, &now); - float alpha = joyglobals.minAlpha; - deltat = timespec_diff(timingBegin, now, NULL); - if (deltat.tv_sec == 0) { - alpha = 1.0; - if (deltat.tv_nsec >= NANOSECONDS_PER_SECOND/2) { - alpha -= ((float)deltat.tv_nsec-(NANOSECONDS_PER_SECOND/2)) / (float)(NANOSECONDS_PER_SECOND/2); - if (alpha < joyglobals.minAlpha) { - alpha = joyglobals.minAlpha; - } - } + GLModelRBJoystick *azimuthJoystick = (GLModelRBJoystick *)parent->custom; + if (!azimuthJoystick) { + return; } - return alpha; + // detach and delete the RB shaders + // 2015/11/06 NOTE : Tegra 2 for mobile has a bug whereby you cannot detach/delete shaders immediately after + // creating the program. So we delete them during the shutdown sequence instead. + // https://code.google.com/p/android/issues/detail?id=61832 + + if (azimuthJoystick->program != UNINITIALIZED_GL) { + glDetachShader(azimuthJoystick->program, azimuthJoystick->vertShader); + glDetachShader(azimuthJoystick->program, azimuthJoystick->fragShader); + glDeleteShader(azimuthJoystick->vertShader); + glDeleteShader(azimuthJoystick->fragShader); + + azimuthJoystick->vertShader = UNINITIALIZED_GL; + azimuthJoystick->fragShader = UNINITIALIZED_GL; + + glDeleteProgram(azimuthJoystick->program); + azimuthJoystick->program = UNINITIALIZED_GL; + } + + FREE(parent->custom); } -static void _setup_axis_object(GLModel *parent) { +static void *_rb_create_model(GLModel *parent) { + + parent->custom = CALLOC(sizeof(GLModelRBJoystick), 1); + GLModelRBJoystick *azimuthJoystick = (GLModelRBJoystick *)parent->custom; + + if (!azimuthJoystick) { + return NULL; + } + + axes.azimuthModelDirty = false; + + // degenerate the quad model into just a single line model ... (should not need to adjust allocated memory size + // since we should be using less than what was originally allocated) + parent->primType = GL_LINES; + parent->numVertices = 2; + GLsizei posTypeSize = getGLTypeSize(parent->positionType); + parent->positionArraySize = (parent->positionSize * posTypeSize * parent->numVertices); + parent->numElements = 2; + GLsizei eltTypeSize = getGLTypeSize(parent->elementType); + parent->elementArraySize = (eltTypeSize * parent->numElements); + + azimuthJoystick->vertShader = UNINITIALIZED_GL; + azimuthJoystick->fragShader = UNINITIALIZED_GL; + azimuthJoystick->program = UNINITIALIZED_GL; + azimuthJoystick->uniformMVPIdx = UNINITIALIZED_GL; + + bool err = true; + demoSource *vtxSource = NULL; + demoSource *frgSource = NULL; + do { + // load/setup specific shaders + + vtxSource = glshader_createSource("SolidColor.vsh"); + if (!vtxSource) { + ERRLOG("Cannot compile vertex shader for joystick azimuth!"); + break; + } + + frgSource = glshader_createSource("SolidColor.fsh"); + if (!frgSource) { + ERRLOG("Cannot compile fragment shader for joystick azimuth!"); + break; + } + + // Build/use Program + azimuthJoystick->program = glshader_buildProgram(vtxSource, frgSource, /*withTexcoord:*/false, &azimuthJoystick->vertShader, &azimuthJoystick->fragShader); + + azimuthJoystick->uniformMVPIdx = glGetUniformLocation(azimuthJoystick->program, "modelViewProjectionMatrix"); + if (azimuthJoystick->uniformMVPIdx < 0) { + LOG("OOPS, no modelViewProjectionMatrix in RB shader : %d", azimuthJoystick->uniformMVPIdx); + break; + } + + err = false; + } while (0); + + GL_ERRLOG("build RB joystick"); + + if (vtxSource) { + glshader_destroySource(vtxSource); + } + if (frgSource) { + glshader_destroySource(frgSource); + } + + if (err) { + _rb_destroy_model(parent); + azimuthJoystick = NULL; + } + + return azimuthJoystick; +} + +static void _rb_render(void) { + if (!axes.azimuthModel) { + return; + } + + GLModelRBJoystick *azimuthJoystick = (GLModelRBJoystick *)axes.azimuthModel->custom; + + // use azimuth (SolidColor) program + glUseProgram(azimuthJoystick->program); + + glUniformMatrix4fv(azimuthJoystick->uniformMVPIdx, 1, GL_FALSE, mvpIdentity); + + // NOTE : assuming we should just upload new postion data every time ... + glBindBuffer(GL_ARRAY_BUFFER, axes.azimuthModel->posBufferName); + glBufferData(GL_ARRAY_BUFFER, axes.azimuthModel->positionArraySize, axes.azimuthModel->positions, GL_DYNAMIC_DRAW); + + // Bind our vertex array object +#if USE_VAO + glBindVertexArray(axes.azimuthModel->vaoName); +#else + glBindBuffer(GL_ARRAY_BUFFER, axes.azimuthModel->posBufferName); + + GLsizei posTypeSize = getGLTypeSize(axes.azimuthModel->positionType); + + // Set up parmeters for position attribute in the VAO including, size, type, stride, and offset in the currenly + // bound VAO This also attaches the position VBO to the VAO + glVertexAttribPointer(POS_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram) + axes.azimuthModel->positionSize, // How many elements are there per position? + axes.azimuthModel->positionType, // What is the type of this data? + GL_FALSE, // Do we want to normalize this data (0-1 range for fixed-pont types) + axes.azimuthModel->positionSize*posTypeSize, // What is the stride (i.e. bytes between positions)? + 0); // What is the offset in the VBO to the position data? + glEnableVertexAttribArray(POS_ATTRIB_IDX); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, axes.azimuthModel->elementBufferName); +#endif + + // draw it + glDrawElements(axes.azimuthModel->primType, axes.azimuthModel->numElements, axes.azimuthModel->elementType, 0); + + // back to main framebuffer/quad program + glUseProgram(mainShaderProgram); + + GL_ERRLOG("RB render"); +} + +// ---------------------------------------------------------------------------- + +static void _setup_axis_hud(GLModel *parent) { if (UNLIKELY(!parent)) { LOG("gltouchjoy WARN : cannot setup axis object without parent"); return; @@ -110,20 +248,18 @@ static void _setup_axis_object(GLModel *parent) { if (hudElement->tpl == NULL) { // deferred construction ... const char axisTemplate[AXIS_TEMPLATE_ROWS][AXIS_TEMPLATE_COLS+1] = { - " @ ", - " | ", - "@-+-@", - " | ", - " @ ", + " @ ", + "@+@", + " @ ", }; const unsigned int size = sizeof(axisTemplate); - hudElement->tpl = calloc(size, 1); + hudElement->tpl = CALLOC(size, 1); hudElement->tplWidth = AXIS_TEMPLATE_COLS; hudElement->tplHeight = AXIS_TEMPLATE_ROWS; memcpy(hudElement->tpl, axisTemplate, size); - hudElement->pixels = calloc(AXIS_FB_WIDTH * AXIS_FB_HEIGHT, 1); + hudElement->pixels = CALLOC(AXIS_FB_WIDTH * AXIS_FB_HEIGHT, 1); hudElement->pixWidth = AXIS_FB_WIDTH; hudElement->pixHeight = AXIS_FB_HEIGHT; } @@ -132,22 +268,24 @@ static void _setup_axis_object(GLModel *parent) { for (unsigned int i=0; itpl)+(row*i*2))[j*2] = axes.rosetteChars[(i*ROSETTE_ROWS)+j]; + ((hudElement->tpl)+(row*i))[j] = axes.rosetteChars[(i*ROSETTE_ROWS)+j]; } } glhud_setupDefault(parent); } -static void *_create_touchjoy_hud(void) { - GLModelHUDElement *hudElement = (GLModelHUDElement *)glhud_createDefault(); +static void *_create_axis_hud(GLModel *parent) { + parent->custom = glhud_createDefault(); + GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom; if (hudElement) { hudElement->blackIsTransparent = true; + _setup_axis_hud(parent); } return hudElement; } -static void _setup_button_object(GLModel *parent) { +static void _setup_button_hud(GLModel *parent) { if (UNLIKELY(!parent)) { LOG("gltouchjoy WARN : cannot setup button object without parent"); return; @@ -166,12 +304,12 @@ static void _setup_button_object(GLModel *parent) { }; const unsigned int size = sizeof(buttonTemplate); - hudElement->tpl = calloc(size, 1); + hudElement->tpl = CALLOC(size, 1); hudElement->tplWidth = BUTTON_TEMPLATE_COLS; hudElement->tplHeight = BUTTON_TEMPLATE_ROWS; memcpy(hudElement->tpl, buttonTemplate, size); - hudElement->pixels = calloc(BUTTON_FB_WIDTH * BUTTON_FB_HEIGHT, 1); + hudElement->pixels = CALLOC(BUTTON_FB_WIDTH * BUTTON_FB_HEIGHT, 1); hudElement->pixWidth = BUTTON_FB_WIDTH; hudElement->pixHeight = BUTTON_FB_HEIGHT; } @@ -182,10 +320,20 @@ static void _setup_button_object(GLModel *parent) { glhud_setupDefault(parent); } +static void *_create_button_hud(GLModel *parent) { + parent->custom = glhud_createDefault(); + GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom; + if (hudElement) { + hudElement->blackIsTransparent = true; + _setup_button_hud(parent); + } + return hudElement; +} + static inline void _setup_button_object_with_char(char newChar) { if (buttons.activeChar != newChar) { buttons.activeChar = newChar; - _setup_button_object(buttons.model); + _setup_button_hud(buttons.model); } } @@ -209,11 +357,22 @@ static void gltouchjoy_setup(void) { joyglobals.isShuttingDown = false; - axes.model = mdlCreateQuad(-1.05, -1.0, AXIS_OBJ_W, AXIS_OBJ_H, MODEL_DEPTH, AXIS_FB_WIDTH, AXIS_FB_HEIGHT, (GLCustom){ - .create = &_create_touchjoy_hud, - .setup = &_setup_axis_object, + // axis origin object + + axes.model = mdlCreateQuad((GLModelParams_s){ + .skew_x = -1.05, + .skew_y = -1.0, + .z = MODEL_DEPTH, + .obj_w = AXIS_OBJ_W, + .obj_h = AXIS_OBJ_H, + .positionUsageHint = GL_DYNAMIC_DRAW, // positions can change + .tex_w = AXIS_FB_WIDTH, + .tex_h = AXIS_FB_HEIGHT, + .texcoordUsageHint = GL_DYNAMIC_DRAW, // so can texture + }, (GLCustom){ + .create = &_create_axis_hud, .destroy = &glhud_destroyDefault, - }); + }); if (!axes.model) { LOG("gltouchjoy not initializing axis"); return; @@ -223,13 +382,56 @@ static void gltouchjoy_setup(void) { return; } + // axis aximuth object + + bool azimuthError = true; + do { + axes.azimuthModel = mdlCreateQuad((GLModelParams_s){ + .skew_x = -1.05, + .skew_y = -1.0, + .z = MODEL_DEPTH, + .obj_w = AXIS_OBJ_W, + .obj_h = AXIS_OBJ_H, + .positionUsageHint = GL_DYNAMIC_DRAW, // positions can change + .tex_w = 0, + .tex_h = 0, + .texcoordUsageHint = UNINITIALIZED_GL, // no texture data + }, (GLCustom){ + .create = &_rb_create_model, + .destroy = &_rb_destroy_model, + }); + if (!axes.azimuthModel) { + LOG("gltouchjoy azimuth model initialization problem"); + break; + } + if (!axes.azimuthModel->custom) { + LOG("gltouchjoy azimuth custom model initialization problem"); + break; + } + + azimuthError = false; + } while (0); + + if (azimuthError) { + mdlDestroyModel(&axes.azimuthModel); + } + // button object - buttons.model = mdlCreateQuad(1.05-BUTTON_OBJ_W, -1.0, BUTTON_OBJ_W, BUTTON_OBJ_H, MODEL_DEPTH, BUTTON_FB_WIDTH, BUTTON_FB_HEIGHT, (GLCustom){ - .create = &_create_touchjoy_hud, - .setup = &_setup_button_object, + buttons.model = mdlCreateQuad((GLModelParams_s){ + .skew_x = 1.05-BUTTON_OBJ_W, + .skew_y = -1.0, + .z = MODEL_DEPTH, + .obj_w = BUTTON_OBJ_W, + .obj_h = BUTTON_OBJ_H, + .positionUsageHint = GL_DYNAMIC_DRAW, // positions can change + .tex_w = BUTTON_FB_WIDTH, + .tex_h = BUTTON_FB_HEIGHT, + .texcoordUsageHint = GL_DYNAMIC_DRAW, // so can texture + }, (GLCustom){ + .create = &_create_button_hud, .destroy = &glhud_destroyDefault, - }); + }); if (!buttons.model) { LOG("gltouchjoy not initializing buttons"); return; @@ -286,7 +488,10 @@ static void gltouchjoy_render(void) { // draw axis - float alpha = _get_component_visibility(axes.timingBegin); + float alpha = glhud_getTimedVisibility(axes.timingBegin, joyglobals.minAlpha, 1.0); + if (alpha < joyglobals.minAlpha) { + alpha = joyglobals.minAlpha; + } if (alpha > 0.0) { glUniform1f(alphaValue, alpha); @@ -306,9 +511,16 @@ static void gltouchjoy_render(void) { glhud_renderDefault(axes.model); } + if (joyglobals.showAzimuth && axes.azimuthModelDirty) { + _rb_render(); + } + // draw button(s) - alpha = _get_component_visibility(buttons.timingBegin); + alpha = glhud_getTimedVisibility(buttons.timingBegin, joyglobals.minAlpha, 1.0); + if (alpha < joyglobals.minAlpha) { + alpha = joyglobals.minAlpha; + } if (alpha > 0.0) { glUniform1f(alphaValue, alpha); @@ -375,7 +587,7 @@ static inline bool _is_point_on_axis_side(int x, int y) { return (x >= touchport.axisX && x <= touchport.axisXMax && y >= touchport.axisY && y <= touchport.axisYMax); } -static inline void _reset_model_position(GLModel *model, float touchX, float touchY, float objHalfW, float objHalfH) { +static inline void _reset_model_position(GLModel *model, float touchX, float touchY, float objHalfW, float objHalfH, GLModel *azimuthModel) { float centerX = 0.f; float centerY = 0.f; @@ -397,13 +609,21 @@ static inline void _reset_model_position(GLModel *model, float touchX, float tou quad[8 +1] = centerY+objHalfH; quad[12+0] = centerX+objHalfW; quad[12+1] = centerY+objHalfH; + + if (azimuthModel) { + GLfloat *quadRB = (GLfloat *)(azimuthModel->positions); + quadRB[0 +0] = centerX; + quadRB[0 +1] = centerY; + quadRB[4 +0] = centerX; + quadRB[4 +1] = centerY; + } } static inline void _axis_touch_down(int x, int y) { axes.centerX = x; axes.centerY = y; - _reset_model_position(axes.model, x, y, AXIS_OBJ_HALF_W, AXIS_OBJ_HALF_H); + _reset_model_position(axes.model, x, y, AXIS_OBJ_HALF_W, AXIS_OBJ_HALF_H, axes.azimuthModel); axes.modelDirty = true; TOUCH_JOY_LOG("---TOUCH %sDOWN (axis index %d) center:(%d,%d) -> joy(0x%02X,0x%02X)", (action == TOUCH_DOWN ? "" : "POINTER "), axes.trackingIndex, axes.centerX, axes.centerY, joy_x, joy_y); @@ -414,7 +634,7 @@ static inline void _button_touch_down(int x, int y) { buttons.centerX = x; buttons.centerY = y; - _reset_model_position(buttons.model, x, y, BUTTON_OBJ_HALF_W, BUTTON_OBJ_HALF_H); + _reset_model_position(buttons.model, x, y, BUTTON_OBJ_HALF_W, BUTTON_OBJ_HALF_H, NULL); buttons.modelDirty = true; TOUCH_JOY_LOG("---TOUCH %sDOWN (buttons index %d) center:(%d,%d) -> buttons(0x%02X,0x%02X)", (action == TOUCH_DOWN ? "" : "POINTER "), buttons.trackingIndex, buttons.centerX, buttons.centerY, joy_button0, joy_button1); @@ -422,6 +642,17 @@ static inline void _button_touch_down(int x, int y) { } static inline void _axis_move(int x, int y) { + + if (joyglobals.showAzimuth && axes.azimuthModel) { + float centerX = 0.f; + float centerY = 0.f; + glhud_screenToModel(x, y, touchport.width, touchport.height, ¢erX, ¢erY); + GLfloat *quadRB = (GLfloat *)axes.azimuthModel->positions; + quadRB[4 +0] = centerX; + quadRB[4 +1] = centerY; + axes.azimuthModelDirty = true; + }; + x -= axes.centerX; y -= axes.centerY; TOUCH_JOY_LOG("---TOUCH MOVE ...tracking axis:%d (%d,%d) -> joy(0x%02X,0x%02X)", axes.trackingIndex, x, y, joy_x, joy_y); @@ -452,6 +683,7 @@ static inline void _axis_touch_up(int x, int y) { } variant.curr->axisUp(x, y); axes.trackingIndex = TRACKING_NONE; + axes.azimuthModelDirty = false; } static inline void _button_touch_up(int x, int y) { @@ -609,6 +841,10 @@ static void gltouchjoy_setShowControls(bool showControls) { joyglobals.showControls = showControls; } +static void gltouchjoy_setShowAzimuth(bool showAzimuth) { + joyglobals.showAzimuth = showAzimuth; +} + static void _animation_showTouchJoystick(void) { if (!joyglobals.isAvailable) { return; @@ -616,12 +852,12 @@ static void _animation_showTouchJoystick(void) { int x = touchport.axisX + ((touchport.axisXMax - touchport.axisX)/2); int y = touchport.axisY + ((touchport.axisYMax - touchport.axisY)/2); - _reset_model_position(axes.model, x, y, AXIS_OBJ_HALF_W, AXIS_OBJ_HALF_H); + _reset_model_position(axes.model, x, y, AXIS_OBJ_HALF_W, AXIS_OBJ_HALF_H, NULL); axes.modelDirty = true; x = touchport.buttonX + ((touchport.buttonXMax - touchport.buttonX)/2); y = touchport.buttonY + ((touchport.buttonYMax - touchport.buttonY)/2); - _reset_model_position(buttons.model, x, y, BUTTON_OBJ_HALF_W, BUTTON_OBJ_HALF_H); + _reset_model_position(buttons.model, x, y, BUTTON_OBJ_HALF_W, BUTTON_OBJ_HALF_H, NULL); buttons.modelDirty = true; struct timespec now; @@ -660,7 +896,7 @@ static void gltouchjoy_setTouchButtonTypes( } else if (touchDownChar == TOUCH_BUTTON1) { currButtonDisplayChar = MOUSETEXT_CLOSEDAPPLE; } else if (touchDownChar == TOUCH_BOTH) { - currButtonDisplayChar = '+'; + currButtonDisplayChar = ICONTEXT_MENU_TOUCHJOY; } else if (touchDownScancode < 0) { currButtonDisplayChar = ' '; } @@ -702,7 +938,7 @@ static touchjoy_variant_t gltouchjoy_getTouchVariant(void) { static void gltouchjoy_setTouchAxisTypes(uint8_t rosetteChars[(ROSETTE_ROWS * ROSETTE_COLS)], int rosetteScancodes[(ROSETTE_ROWS * ROSETTE_COLS)]) { memcpy(axes.rosetteChars, rosetteChars, sizeof(uint8_t)*(ROSETTE_ROWS * ROSETTE_COLS)); memcpy(axes.rosetteScancodes, rosetteScancodes, sizeof(int) *(ROSETTE_ROWS * ROSETTE_COLS)); - _setup_axis_object(axes.model); + _setup_axis_hud(axes.model); } static void gltouchjoy_setScreenDivision(float screenDivider) { @@ -749,7 +985,7 @@ static void _init_gltouchjoy(void) { axes.rosetteChars[3] = MOUSETEXT_LEFT; axes.rosetteScancodes[3] = -1; - axes.rosetteChars[4] = '+'; + axes.rosetteChars[4] = ICONTEXT_MENU_TOUCHJOY; axes.rosetteScancodes[4] = -1; axes.rosetteChars[5] = MOUSETEXT_RIGHT; axes.rosetteScancodes[5] = -1; @@ -779,6 +1015,7 @@ static void _init_gltouchjoy(void) { joyglobals.isEnabled = true; joyglobals.ownsScreen = true; joyglobals.showControls = true; + joyglobals.showAzimuth = true; joyglobals.screenDivider = 0.5f; joyglobals.axisIsOnLeft = true; joyglobals.switchThreshold = BUTTON_SWITCH_THRESHOLD_DEFAULT; @@ -791,6 +1028,7 @@ static void _init_gltouchjoy(void) { joydriver_setTouchJoystickOwnsScreen = &gltouchjoy_setTouchJoystickOwnsScreen; joydriver_ownsScreen = &gltouchjoy_ownsScreen; joydriver_setShowControls = &gltouchjoy_setShowControls; + joydriver_setShowAzimuth = &gltouchjoy_setShowAzimuth; joydriver_setTouchButtonTypes = &gltouchjoy_setTouchButtonTypes; joydriver_setTouchAxisSensitivity = &gltouchjoy_setTouchAxisSensitivity; joydriver_setButtonSwitchThreshold = &gltouchjoy_setButtonSwitchThreshold; diff --git a/src/video/gltouchjoy.h b/src/video/gltouchjoy.h index c7f7072c..9ac9bb99 100644 --- a/src/video/gltouchjoy.h +++ b/src/video/gltouchjoy.h @@ -33,7 +33,8 @@ typedef struct GLTouchJoyGlobals { bool isCalibrating; // Are we running in calibration mode? bool isEnabled; // Does player want touchjoy enabled? bool ownsScreen; // Does the touchjoy currently own the screen? - bool showControls; // Are controls visible + bool showControls; // Are controls visible? + bool showAzimuth; // Is joystick azimuth shown? float minAlphaWhenOwnsScreen; float minAlpha; float screenDivider; @@ -48,9 +49,14 @@ extern GLTouchJoyGlobals joyglobals; typedef struct GLTouchJoyAxes { + // origin model/texture GLModel *model; bool modelDirty; + // azimuth model + GLModel *azimuthModel; + bool azimuthModelDirty; + uint8_t rosetteChars[ROSETTE_ROWS * ROSETTE_COLS]; int rosetteScancodes[ROSETTE_ROWS * ROSETTE_COLS]; diff --git a/src/video/gltouchjoy_joy.c b/src/video/gltouchjoy_joy.c index 8c8cbfed..c87a3244 100644 --- a/src/video/gltouchjoy_joy.c +++ b/src/video/gltouchjoy_joy.c @@ -26,6 +26,7 @@ static struct { void (*buttonDrawCallback)(char newChar); bool trackingButton; + bool trackingButtonMove; pthread_t tapDelayThreadId; pthread_mutex_t tapDelayMutex; pthread_cond_t tapDelayCond; @@ -71,54 +72,61 @@ static void *_button_tap_delayed_thread(void *dummyptr) { pthread_mutex_lock(&joys.tapDelayMutex); - do { - pthread_cond_wait(&joys.tapDelayCond, &joys.tapDelayMutex); - TOUCH_JOY_LOG(">>> [DELAYEDTAP] begin ..."); - + bool deepSleep = false; + uint8_t currJoyButtonValue0 = 0x0; + uint8_t currJoyButtonValue1 = 0x0; + uint8_t currButtonDisplayChar = ' '; + for (;;) { if (UNLIKELY(joyglobals.isShuttingDown)) { break; } - struct timespec ts = { .tv_sec=0, .tv_nsec=joys.tapDelayNanos }; + struct timespec wait; + clock_gettime(CLOCK_REALTIME, &wait); // should use CLOCK_MONOTONIC ? + wait = timespec_add(wait, joys.tapDelayNanos); + int timedOut = pthread_cond_timedwait(&joys.tapDelayCond, &joys.tapDelayMutex, &wait); // wait and possibly consume event + assert((!timedOut || timedOut == ETIMEDOUT) && "should not fail any other way"); - // sleep for the configured delay time - pthread_mutex_unlock(&joys.tapDelayMutex); - nanosleep(&ts, NULL); - pthread_mutex_lock(&joys.tapDelayMutex); - - // wait until touch up/cancel - do { - - // now set the joystick button values - joy_button0 = joys.currJoyButtonValue0; - joy_button1 = joys.currJoyButtonValue1; - joys.buttonDrawCallback(joys.currButtonDisplayChar); - - if (!joys.trackingButton || joyglobals.isShuttingDown) { - break; + if (!timedOut) { + if (!deepSleep) { + if (joys.trackingButtonMove) { + // dragging + currJoyButtonValue0 = 0x0; + currJoyButtonValue1 = 0x0; + currButtonDisplayChar = joys.currButtonDisplayChar; + } else if (joys.trackingButton) { + // touch down -- delay consumption to determine if tap or drag + currJoyButtonValue0 = joys.currJoyButtonValue0; + currJoyButtonValue1 = joys.currJoyButtonValue1; + currButtonDisplayChar = joys.currButtonDisplayChar; + joys.buttonDrawCallback(currButtonDisplayChar); + // zero the buttons before delay + _reset_buttons_state(); + continue; + } else { + // touch up becomes tap + joys.currJoyButtonValue0 = currJoyButtonValue0; + joys.currJoyButtonValue1 = currJoyButtonValue1; + joys.currButtonDisplayChar = currButtonDisplayChar; + } } - - pthread_cond_wait(&joys.tapDelayCond, &joys.tapDelayMutex); - - if (!joys.trackingButton || joyglobals.isShuttingDown) { - break; - } - TOUCH_JOY_LOG(">>> [DELAYEDTAP] looping ..."); - } while (1); - - if (UNLIKELY(joyglobals.isShuttingDown)) { - break; } - // delay the ending of button tap or touch/move event by the configured delay time - pthread_mutex_unlock(&joys.tapDelayMutex); - nanosleep(&ts, NULL); - pthread_mutex_lock(&joys.tapDelayMutex); + joy_button0 = joys.currJoyButtonValue0; + joy_button1 = joys.currJoyButtonValue1; + joys.buttonDrawCallback(joys.currButtonDisplayChar); - _reset_buttons_state(); - - TOUCH_JOY_LOG(">>> [DELAYEDTAP] end ..."); - } while (1); + deepSleep = false; + if (timedOut && !joys.trackingButton) { + deepSleep = true; + _reset_buttons_state(); + TOUCH_JOY_LOG(">>> [DELAYEDTAP] end ..."); + pthread_cond_wait(&joys.tapDelayCond, &joys.tapDelayMutex); // consume initial touch down + TOUCH_JOY_LOG(">>> [DELAYEDTAP] begin ..."); + } else { + TOUCH_JOY_LOG(">>> [DELAYEDTAP] event looping ..."); + } + } pthread_mutex_unlock(&joys.tapDelayMutex); @@ -183,7 +191,7 @@ static void touchjoy_axisUp(int x, int y) { // ---------------------------------------------------------------------------- // button state -static void _set_current_button_state(touchjoy_button_type_t theButtonChar, int theButtonScancode) { +static void _set_current_button_state(touchjoy_button_type_t theButtonChar) { if (theButtonChar == TOUCH_BUTTON0) { joys.currJoyButtonValue0 = 0x80; joys.currJoyButtonValue1 = 0; @@ -204,30 +212,30 @@ static void _set_current_button_state(touchjoy_button_type_t theButtonChar, int } static void touchjoy_buttonDown(void) { - _set_current_button_state(buttons.touchDownChar, buttons.touchDownScancode); + _set_current_button_state(buttons.touchDownChar); joys.trackingButton = true; _signal_tap_delay(); } static void touchjoy_buttonMove(int dx, int dy) { if ((dy < -joyglobals.switchThreshold) || (dy > joyglobals.switchThreshold)) { + touchjoy_button_type_t theButtonChar = -1; - int theButtonScancode = -1; if (dy < 0) { theButtonChar = buttons.northChar; - theButtonScancode = buttons.northScancode; } else { theButtonChar = buttons.southChar; - theButtonScancode = buttons.southScancode; } - _set_current_button_state(theButtonChar, theButtonScancode); + _set_current_button_state(theButtonChar); _signal_tap_delay(); } + joys.trackingButtonMove = true; } static void touchjoy_buttonUp(int dx, int dy) { joys.trackingButton = false; + joys.trackingButtonMove = false; _signal_tap_delay(); } @@ -238,7 +246,12 @@ static void gltouchjoy_setTapDelay(float secs) { if (UNLIKELY(secs > 1.f)) { ERRLOG("Clamping tap delay to 1.0 secs"); } - joys.tapDelayNanos = (unsigned int)((float)NANOSECONDS_PER_SECOND * secs); + unsigned int tapDelayNanos = (unsigned int)((float)NANOSECONDS_PER_SECOND * secs); +#define MIN_WAIT_NANOS 1000000 + if (tapDelayNanos < MIN_WAIT_NANOS) { + tapDelayNanos = MIN_WAIT_NANOS; + } + joys.tapDelayNanos = tapDelayNanos; } // ---------------------------------------------------------------------------- diff --git a/src/video/gltouchkbd.c b/src/video/gltouchkbd.c index 73944b45..8406675d 100644 --- a/src/video/gltouchkbd.c +++ b/src/video/gltouchkbd.c @@ -29,22 +29,19 @@ #define MODEL_DEPTH -1/32.f #define KBD_TEMPLATE_COLS 10 -#define KBD_TEMPLATE_ROWS 6 +#define KBD_TEMPLATE_ROWS 8 #define DEFAULT_CTRL_COL 2 -#define ROW_WITH_ADJACENTS (KBD_TEMPLATE_ROWS-1) -#define _ROWOFF 2 // main keyboard row offset +#define CTRLROW 2 // first non-empty default row +#define MAINROW 4 // main keyboard row offset +#define SWITCHCOL 0 -#define KBD_FB_WIDTH (KBD_TEMPLATE_COLS * FONT80_WIDTH_PIXELS) -#define KBD_FB_HEIGHT (KBD_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS) +#define KBD_FB_WIDTH (KBD_TEMPLATE_COLS * FONT80_WIDTH_PIXELS) // 10 * 7 == 70 +#define KBD_FB_HEIGHT (KBD_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS) // 8 * 16 == 128 #define KBD_OBJ_W 2.0 -#define KBD_OBJ_H 1.5 - -HUD_CLASS(GLModelHUDKeyboard, - // ... -); +#define KBD_OBJ_H 2.0 static bool isAvailable = false; // Were there any OpenGL/memory errors on gltouchkbd initialization? static bool isEnabled = true; // Does player want touchkbd enabled? @@ -56,6 +53,8 @@ static float minAlpha = 0.f; static float maxAlpha = 1.f; static uint8_t kbdTemplateUCase[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = { + " ", + " ", "@ @ @ @ @ ", "1234567890", "QWERTYUIOP", @@ -65,6 +64,8 @@ static uint8_t kbdTemplateUCase[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = { }; static uint8_t kbdTemplateLCase[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = { + " ", + " ", "@ @ @ @ @ ", "1234567890", "qwertyuiop", @@ -74,6 +75,8 @@ static uint8_t kbdTemplateLCase[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = { }; static uint8_t kbdTemplateAlt[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = { + " ", + " ", "@ @ @ @ @ ", "1234567890", "@#%&*/-+()", @@ -82,7 +85,9 @@ static uint8_t kbdTemplateAlt[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = { "$|\\XXX.^XX", }; -static uint8_t kbdTemplateArrow[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = { +static uint8_t kbdTemplateUserAlt[KBD_TEMPLATE_ROWS][KBD_TEMPLATE_COLS+1] = { + " ", + " ", "@ @ @ @ @ ", " ", " @ ", @@ -111,7 +116,6 @@ static struct { static struct { GLModel *model; - bool modelDirty; // TODO : movement animation int selectedCol; int selectedRow; @@ -121,27 +125,37 @@ static struct { bool ctrlPressed; + unsigned int glyphMultiplier; + struct timespec timingBegin; + + // pending changes requiring reinitialization + unsigned int nextGlyphMultiplier; } kbd = { 0 }; // ---------------------------------------------------------------------------- // Misc internal methods +#warning FIXME TODO ... make this a generic GLModelHUDElement function static void _rerender_character(int col, int row) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)(kbd.model->custom); + GLModelHUDElement *hudKeyboard = (GLModelHUDElement *)(kbd.model->custom); - // re-generate texture from indexed color - const unsigned int colCount = 1; - const unsigned int pixCharsWidth = FONT80_WIDTH_PIXELS*colCount; - const unsigned int rowStride = hudKeyboard->pixWidth - pixCharsWidth; - unsigned int srcIdx = (row * hudKeyboard->pixWidth * FONT_HEIGHT_PIXELS) + (col * FONT80_WIDTH_PIXELS); - unsigned int dstIdx = srcIdx * sizeof(PIXEL_TYPE); + // In English, this changes one glyph within the keyboard texture data to be the (un)selected color. It handles + // scaling from indexed color to RGBA8888 (4x) and then possibly scaling to 2x or greater. - for (unsigned int i=0; ipixWidth; + const unsigned int pixelSize = sizeof(PIXEL_TYPE); + const unsigned int glyphScale = hudKeyboard->glyphMultiplier; + const unsigned int dstPointStride = pixelSize * glyphScale; + const unsigned int dstRowStride = fb_w * dstPointStride; + const unsigned int texSubRowStride = dstRowStride + (dstRowStride * (glyphScale-1)); + const unsigned int indexedIdx = (row * fb_w * FONT_HEIGHT_PIXELS) + (col * FONT80_WIDTH_PIXELS); + unsigned int texIdx = ((row * fb_w * FONT_HEIGHT_PIXELS * /*1 row:*/glyphScale) + (col * FONT80_WIDTH_PIXELS)) * dstPointStride; - // HACK : red <-> green swap - PIXEL_TYPE rgba = *((PIXEL_TYPE *)(kbd.model->texPixels + dstIdx)); + for (unsigned int i=0; i green swap of texture data + PIXEL_TYPE rgba = *((PIXEL_TYPE *)(kbd.model->texPixels + texIdx)); PIXEL_TYPE r = (rgba >> SHIFT_R) & MAX_SATURATION; PIXEL_TYPE g = (rgba >> SHIFT_G) & MAX_SATURATION; #if USE_RGBA4444 @@ -149,13 +163,16 @@ static void _rerender_character(int col, int row) { #else rgba = ( ((rgba>>SHIFT_B)<texPixels + dstIdx) ) = rgba; - - srcIdx += 1; - dstIdx += sizeof(PIXEL_TYPE); + // scale texture data 1x, 2x, ... + unsigned int dstIdx = texIdx; + for (unsigned int k=0; ktexPixels + dstIdx) ) = rgba; + } + dstIdx -= dstPointStride; + } } - srcIdx += rowStride; - dstIdx = srcIdx * sizeof(PIXEL_TYPE); + texIdx -= (FONT80_WIDTH_PIXELS * dstPointStride); } kbd.model->texDirty = true; @@ -164,25 +181,38 @@ static void _rerender_character(int col, int row) { static inline void _rerender_selected(int col, int row) { if ((col >= 0) && (row >= 0)) { _rerender_character(col, row); - if (row == ROW_WITH_ADJACENTS) { - if ((col == 3) || (col == 4) || (col == 8)) { + + // rerender certain adjacent keys ... + GLModelHUDElement *hudKeyboard = (GLModelHUDElement *)(kbd.model->custom); + const unsigned int indexRow = (hudKeyboard->tplWidth+1) * row; + uint8_t key = (hudKeyboard->tpl+indexRow)[col]; + switch (key) { + case ICONTEXT_LEFTSPACE: _rerender_character(col+1, row); - } - if ((col == 4) || (col == 5) || (col == 9)) { - _rerender_character(col-1, row); - } - if (col == 3) { _rerender_character(col+2, row); - } - if (col == 5) { + break; + case ICONTEXT_MIDSPACE: + _rerender_character(col-1, row); + _rerender_character(col+1, row); + break; + case ICONTEXT_RIGHTSPACE: _rerender_character(col-2, row); - } + _rerender_character(col-1, row); + break; + case ICONTEXT_RETURN_L: + _rerender_character(col+1, row); + break; + case ICONTEXT_RETURN_R: + _rerender_character(col-1, row); + break; + default: + break; } } } static inline void _switch_keyboard(GLModel *parent, uint8_t *template) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)parent->custom; + GLModelHUDElement *hudKeyboard = (GLModelHUDElement *)parent->custom; memcpy(hudKeyboard->tpl, template, sizeof(kbdTemplateUCase/* assuming all the same size */)); // setup normal color pixels @@ -203,43 +233,12 @@ static inline void _switch_keyboard(GLModel *parent, uint8_t *template) { } } -static inline void _toggle_arrows(void) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)kbd.model->custom; - uint8_t c = hudKeyboard->tpl[_ROWOFF*(KBD_TEMPLATE_COLS+1)]; - if (c == ICONTEXT_NONACTIONABLE) { - _switch_keyboard(kbd.model, kbdTemplateUCase[0]); - } else { - _switch_keyboard(kbd.model, kbdTemplateArrow[0]); - } -} - -#warning FIXME TODO ... this can become a common helper function ... -static inline float _get_keyboard_visibility(void) { - struct timespec now = { 0 }; - struct timespec deltat = { 0 }; - - clock_gettime(CLOCK_MONOTONIC, &now); - float alpha = minAlpha; - deltat = timespec_diff(kbd.timingBegin, now, NULL); - if (deltat.tv_sec == 0) { - alpha = maxAlpha; - if (deltat.tv_nsec >= NANOSECONDS_PER_SECOND/2) { - alpha -= ((float)deltat.tv_nsec-(NANOSECONDS_PER_SECOND/2)) / (float)(NANOSECONDS_PER_SECOND/2); - if (alpha < minAlpha) { - alpha = minAlpha; - } - } - } - - return alpha; -} - static inline bool _is_point_on_keyboard(float x, float y) { return (x >= touchport.kbdX && x <= touchport.kbdXMax && y >= touchport.kbdY && y <= touchport.kbdYMax); } static inline void _screen_to_keyboard(float x, float y, OUTPARM int *col, OUTPARM int *row) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)(kbd.model->custom); + GLModelHUDElement *hudKeyboard = (GLModelHUDElement *)(kbd.model->custom); const unsigned int keyW = touchport.kbdW / hudKeyboard->tplWidth; const unsigned int keyH = touchport.kbdH / hudKeyboard->tplHeight; @@ -258,7 +257,7 @@ static inline void _screen_to_keyboard(float x, float y, OUTPARM int *col, OUTPA } static inline int64_t _tap_key_at_point(float x, float y) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)kbd.model->custom; + GLModelHUDElement *hudKeyboard = (GLModelHUDElement *)kbd.model->custom; // redraw previous selected key (if any) _rerender_selected(kbd.selectedCol, kbd.selectedRow); @@ -300,9 +299,9 @@ static inline int64_t _tap_key_at_point(float x, float y) { case ICONTEXT_SHOWALT1: key = 0; if (allowLowercase && !isCalibrating) { - kbdTemplateAlt[0][0] = ICONTEXT_LOWERCASE; + kbdTemplateAlt[CTRLROW][SWITCHCOL] = ICONTEXT_LOWERCASE; } else { - kbdTemplateAlt[0][0] = ICONTEXT_UPPERCASE; + kbdTemplateAlt[CTRLROW][SWITCHCOL] = ICONTEXT_UPPERCASE; } _switch_keyboard(kbd.model, kbdTemplateAlt[0]); break; @@ -321,6 +320,7 @@ static inline int64_t _tap_key_at_point(float x, float y) { scancode = SCODE_L_CTRL; break; + case MOUSETEXT_RETURN: case ICONTEXT_RETURN_L: case ICONTEXT_RETURN_R: key = ICONTEXT_RETURN_L; @@ -361,7 +361,8 @@ static inline int64_t _tap_key_at_point(float x, float y) { case ICONTEXT_MENU_SPROUT: key = 0; - _toggle_arrows(); + kbd.ctrlPressed = false; + _switch_keyboard(kbd.model, kbdTemplateUserAlt[0]); break; case ICONTEXT_GOTO: @@ -425,51 +426,76 @@ static inline int64_t _tap_key_at_point(float x, float y) { // ---------------------------------------------------------------------------- // GLCustom functions -static void _setup_touchkbd_hud(GLModel *parent) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)parent->custom; +static void *_create_touchkbd_hud(GLModel *parent) { + + parent->custom = glhud_createCustom(sizeof(GLModelHUDElement)); + GLModelHUDElement *hudKeyboard = (GLModelHUDElement *)parent->custom; + + if (!hudKeyboard) { + return NULL; + } + + hudKeyboard->blackIsTransparent = true; + hudKeyboard->opaquePixelHalo = true; + hudKeyboard->glyphMultiplier = kbd.glyphMultiplier; hudKeyboard->tplWidth = KBD_TEMPLATE_COLS; hudKeyboard->tplHeight = KBD_TEMPLATE_ROWS; hudKeyboard->pixWidth = KBD_FB_WIDTH; hudKeyboard->pixHeight = KBD_FB_HEIGHT; - const unsigned int size = sizeof(kbdTemplateUCase/* assuming all the same */); - hudKeyboard->tpl = calloc(size, 1); - hudKeyboard->pixels = calloc(KBD_FB_WIDTH * KBD_FB_HEIGHT, 1); + const unsigned int size = sizeof(kbdTemplateUCase/* assuming all the same dimensions */); + hudKeyboard->tpl = MALLOC(size); + hudKeyboard->pixels = MALLOC(KBD_FB_WIDTH * KBD_FB_HEIGHT); - _switch_keyboard(parent, kbdTemplateUCase[0]); -} + memcpy(hudKeyboard->tpl, kbdTemplateUCase[0], sizeof(kbdTemplateUCase/* assuming all the same dimensions */)); + + // setup normal color pixels + hudKeyboard->colorScheme = RED_ON_BLACK; + + glhud_setupDefault(parent); -static void *_create_touchkbd_hud(void) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)calloc(sizeof(GLModelHUDKeyboard), 1); - if (hudKeyboard) { - hudKeyboard->blackIsTransparent = true; - hudKeyboard->opaquePixelHalo = true; - } return hudKeyboard; } -static void _destroy_touchkbd_hud(GLModel *parent) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)parent->custom; - if (!hudKeyboard) { - return; - } - glhud_destroyDefault(parent); -} - // ---------------------------------------------------------------------------- // GLNode functions -static void gltouchkbd_setup(void) { - LOG("gltouchkbd_setup ..."); +static void gltouchkbd_shutdown(void) { + LOG("gltouchkbd_shutdown ..."); + if (!isAvailable) { + return; + } + + isAvailable = false; mdlDestroyModel(&kbd.model); + kbd.selectedCol = -1; + kbd.selectedRow = -1; + kbd.ctrlPressed = false; - kbd.model = mdlCreateQuad(-1.0, -1.0, KBD_OBJ_W, KBD_OBJ_H, MODEL_DEPTH, KBD_FB_WIDTH, KBD_FB_HEIGHT, (GLCustom){ + kbd.nextGlyphMultiplier = 0; +} + +static void gltouchkbd_setup(void) { + LOG("gltouchkbd_setup ... %u", sizeof(kbd)); + + gltouchkbd_shutdown(); + + kbd.model = mdlCreateQuad((GLModelParams_s){ + .skew_x = -1.0, + .skew_y = -1.0, + .z = MODEL_DEPTH, + .obj_w = KBD_OBJ_W, + .obj_h = KBD_OBJ_H, + .positionUsageHint = GL_STATIC_DRAW, // positions don't change + .tex_w = KBD_FB_WIDTH * kbd.glyphMultiplier, + .tex_h = KBD_FB_HEIGHT * kbd.glyphMultiplier, + .texcoordUsageHint = GL_DYNAMIC_DRAW, // but key texture does + }, (GLCustom){ .create = &_create_touchkbd_hud, - .setup = &_setup_touchkbd_hud, - .destroy = &_destroy_touchkbd_hud, - }); + .destroy = &glhud_destroyDefault, + }); if (!kbd.model) { LOG("gltouchkbd initialization problem"); return; @@ -484,17 +510,6 @@ static void gltouchkbd_setup(void) { isAvailable = true; } -static void gltouchkbd_shutdown(void) { - LOG("gltouchkbd_shutdown ..."); - if (!isAvailable) { - return; - } - - isAvailable = false; - - mdlDestroyModel(&kbd.model); -} - static void gltouchkbd_render(void) { if (!isAvailable) { return; @@ -506,7 +521,19 @@ static void gltouchkbd_render(void) { return; } - float alpha = _get_keyboard_visibility(); + if (kbd.nextGlyphMultiplier) { + kbd.glyphMultiplier = kbd.nextGlyphMultiplier; + kbd.nextGlyphMultiplier = 0; + gltouchkbd_setup(); + } + + float alpha = glhud_getTimedVisibility(kbd.timingBegin, minAlpha, maxAlpha); + if (alpha < minAlpha) { + alpha = minAlpha; + _rerender_selected(kbd.selectedCol, kbd.selectedRow); + kbd.selectedCol = -1; + kbd.selectedRow = -1; + } if (alpha > 0.0) { // draw touch keyboard @@ -521,11 +548,6 @@ static void gltouchkbd_render(void) { _HACKAROUND_GLTEXIMAGE2D_PRE(TEXTURE_ACTIVE_TOUCHKBD, kbd.model->textureName); glTexImage2D(GL_TEXTURE_2D, /*level*/0, TEX_FORMAT_INTERNAL, kbd.model->texWidth, kbd.model->texHeight, /*border*/0, TEX_FORMAT, TEX_TYPE, kbd.model->texPixels); } - if (kbd.modelDirty) { - kbd.modelDirty = false; - glBindBuffer(GL_ARRAY_BUFFER, kbd.model->posBufferName); - glBufferData(GL_ARRAY_BUFFER, kbd.model->positionArraySize, kbd.model->positions, GL_DYNAMIC_DRAW); - } glUniform1i(texSamplerLoc, TEXTURE_ID_TOUCHKBD); glhud_renderDefault(kbd.model); } @@ -567,6 +589,8 @@ static int64_t gltouchkbd_onTouchEvent(interface_touch_event_t action, int point int64_t flags = TOUCH_FLAGS_KBD | TOUCH_FLAGS_HANDLED; + clock_gettime(CLOCK_MONOTONIC, &kbd.timingBegin); + switch (action) { case TOUCH_DOWN: case TOUCH_POINTER_DOWN: @@ -593,8 +617,6 @@ static int64_t gltouchkbd_onTouchEvent(interface_touch_event_t action, int point return 0x0LL; } - clock_gettime(CLOCK_MONOTONIC, &kbd.timingBegin); - return flags; } @@ -626,7 +648,7 @@ static void gltouchkbd_setTouchKeyboardOwnsScreen(bool pwnd) { kbd.selectedRow = -1; if (kbd.model) { - GLModelHUDKeyboard *hudKeyboard = (GLModelHUDKeyboard *)kbd.model->custom; + GLModelHUDElement *hudKeyboard = (GLModelHUDElement *)kbd.model->custom; hudKeyboard->colorScheme = RED_ON_BLACK; glhud_setupDefault(kbd.model); } @@ -641,6 +663,13 @@ static bool gltouchkbd_ownsScreen(void) { return ownsScreen; } +static void gltouchkbd_setGlyphScale(int glyphScale) { + if (glyphScale == 0) { + glyphScale = 1; + } + kbd.nextGlyphMultiplier = glyphScale; +} + static void gltouchkbd_setVisibilityWhenOwnsScreen(float inactiveAlpha, float activeAlpha) { minAlphaWhenOwnsScreen = inactiveAlpha; maxAlpha = activeAlpha; @@ -721,26 +750,26 @@ static void gltouchkbd_loadAltKbd(const char *kbdPath) { break; } - // next is reserved0 array - if (parsedData.jsonTokens[idx].type != JSMN_ARRAY) { - ERRLOG("Expecting a reserved array at JSON token position 3"); - break; - } - ++idx; - idx += parsedData.jsonTokens[idx-1].size; - - // next is reserved1 array - if (parsedData.jsonTokens[idx].type != JSMN_ARRAY) { - ERRLOG("Expecting a reserved array at JSON token position 4"); - break; - } - ++idx; - idx += parsedData.jsonTokens[idx-1].size; - // next are the character rows int row = 0; while (idx < tokCount) { - if ( !((parsedData.jsonTokens[idx].type == JSMN_ARRAY) && (parsedData.jsonTokens[idx].size == KBD_TEMPLATE_COLS) && (parsedData.jsonTokens[idx].parent == 0)) ) { + if (row < 2) { + if ( !((parsedData.jsonTokens[idx].type == JSMN_ARRAY) && (parsedData.jsonTokens[idx].parent == 0)) ) { + ERRLOG("Expecting a reserved array at keyboard row %d", row+1); + break; + } + if (parsedData.jsonTokens[idx].size != KBD_TEMPLATE_COLS) { + // backwards compatibility when we only had the lower 6 rows for keyboard data ... + LOG("You can now edit %d columns of row %d in your custom keyboard", KBD_TEMPLATE_COLS, row+1); + for (int col=0; col= KBD_TEMPLATE_ROWS) { + break; + } } if (row != KBD_TEMPLATE_ROWS) { @@ -831,7 +864,7 @@ static void _animation_hideTouchKeyboard(void) { static void _initialize_keyboard_templates(void) { - for (unsigned int i=0; i<(_ROWOFF-1); i++) { + for (unsigned int i=0; i<(MAINROW-1); i++) { for (unsigned int j=0; jcustom; + GLModelHUDElement *hudMenu = (GLModelHUDElement *)parent->custom; memcpy(hudMenu->tpl, topMenuTemplate, sizeof(topMenuTemplate)); - // setup the alternate color (AKA selected) pixels - hudMenu->colorScheme = GREEN_ON_BLACK; - glhud_setupDefault(parent); - memcpy(hudMenu->pixelsAlt, hudMenu->pixels, (hudMenu->pixWidth * hudMenu->pixHeight)); - - // setup normal color pixels hudMenu->colorScheme = RED_ON_BLACK; glhud_setupDefault(parent); } @@ -140,26 +135,6 @@ static inline void _hide_top_right(void) { _present_menu(menu.model); } -static float _get_menu_visibility(void) { - struct timespec now = { 0 }; - struct timespec deltat = { 0 }; - float alpha = minAlpha; - - clock_gettime(CLOCK_MONOTONIC, &now); - deltat = timespec_diff(timingBegin, now, NULL); - if (deltat.tv_sec == 0) { - alpha = 1.0; - if (deltat.tv_nsec >= NANOSECONDS_PER_SECOND/2) { - alpha -= ((float)deltat.tv_nsec-(NANOSECONDS_PER_SECOND/2)) / (float)(NANOSECONDS_PER_SECOND/2); - if (alpha < minAlpha) { - alpha = minAlpha; - } - } - } - - return alpha; -} - static inline bool _is_point_on_left_menu(float x, float y) { if (menu.topLeftShowing) { return (x >= touchport.topLeftX && x <= touchport.topLeftXMax && y >= touchport.topLeftY && y <= touchport.topLeftYMax); @@ -179,7 +154,7 @@ static inline bool _is_point_on_right_menu(float x, float y) { #warning FIXME TODO : make this function generic _screen_to_model() ? static inline void _screen_to_menu(float x, float y, OUTPARM int *col, OUTPARM int *row) { - GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)(menu.model->custom); + GLModelHUDElement *hudMenu = (GLModelHUDElement *)(menu.model->custom); const unsigned int keyW = touchport.width / hudMenu->tplWidth; const unsigned int keyH = touchport.topLeftYMax / hudMenu->tplHeight; @@ -245,6 +220,7 @@ static inline bool _sprout_menu(float x, float y) { return menu.topRightShowing; } else { RELEASE_ERRLOG("This should not happen"); + return false; } } @@ -319,8 +295,17 @@ static inline int64_t _tap_menu_item(float x, float y) { // ---------------------------------------------------------------------------- // GLCustom functions -static void _setup_touchmenu(GLModel *parent) { - GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)parent->custom; +static void *_create_touchmenu_hud(GLModel *parent) { + parent->custom = glhud_createCustom(sizeof(GLModelHUDElement)); + GLModelHUDElement *hudMenu = (GLModelHUDElement *)parent->custom; + + if (!hudMenu) { + return NULL; + } + + hudMenu->blackIsTransparent = true; + hudMenu->opaquePixelHalo = true; + hudMenu->glyphMultiplier = menu.glyphMultiplier; hudMenu->tplWidth = MENU_TEMPLATE_COLS; hudMenu->tplHeight = MENU_TEMPLATE_ROWS; @@ -344,59 +329,17 @@ static void _setup_touchmenu(GLModel *parent) { } const unsigned int size = sizeof(topMenuTemplate); - hudMenu->tpl = calloc(size, 1); - hudMenu->pixels = calloc(MENU_FB_WIDTH * MENU_FB_HEIGHT, 1); - hudMenu->pixelsAlt = calloc(MENU_FB_WIDTH * MENU_FB_HEIGHT, 1); + hudMenu->tpl = CALLOC(size, 1); + hudMenu->pixels = CALLOC(MENU_FB_WIDTH * MENU_FB_HEIGHT, 1); _present_menu(parent); -} -static void *_create_touchmenu(void) { - GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)calloc(sizeof(GLModelHUDMenu), 1); - if (hudMenu) { - hudMenu->blackIsTransparent = true; - hudMenu->opaquePixelHalo = true; - } return hudMenu; } -static void _destroy_touchmenu(GLModel *parent) { - GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)parent->custom; - if (!hudMenu) { - return; - } - FREE(hudMenu->pixelsAlt); - glhud_destroyDefault(parent); -} - // ---------------------------------------------------------------------------- // GLNode functions -static void gltouchmenu_setup(void) { - LOG("gltouchmenu_setup ..."); - - mdlDestroyModel(&menu.model); - menu.model = mdlCreateQuad(-1.0, 1.0-MENU_OBJ_H, MENU_OBJ_W, MENU_OBJ_H, MODEL_DEPTH, MENU_FB_WIDTH, MENU_FB_HEIGHT, (GLCustom){ - .create = &_create_touchmenu, - .setup = &_setup_touchmenu, - .destroy = &_destroy_touchmenu, - }); - if (!menu.model) { - LOG("gltouchmenu initialization problem"); - return; - } - if (!menu.model->custom) { - LOG("gltouchmenu HUD initialization problem"); - return; - } - - clock_gettime(CLOCK_MONOTONIC, &timingBegin); - - isAvailable = true; - - GL_ERRLOG("gltouchmenu_setup"); -} - static void gltouchmenu_shutdown(void) { LOG("gltouchmenu_shutdown ..."); if (!isAvailable) { @@ -405,9 +348,48 @@ static void gltouchmenu_shutdown(void) { isAvailable = false; + menu.topLeftShowing = false; + menu.topRightShowing = false; + menu.nextGlyphMultiplier = 0; + mdlDestroyModel(&menu.model); } +static void gltouchmenu_setup(void) { + LOG("gltouchmenu_setup ..."); + + gltouchmenu_shutdown(); + + menu.model = mdlCreateQuad((GLModelParams_s){ + .skew_x = -1.0, + .skew_y = 1.0-MENU_OBJ_H, + .z = MODEL_DEPTH, + .obj_w = MENU_OBJ_W, + .obj_h = MENU_OBJ_H, + .positionUsageHint = GL_STATIC_DRAW, // positions don't change + .tex_w = MENU_FB_WIDTH * menu.glyphMultiplier, + .tex_h = MENU_FB_HEIGHT * menu.glyphMultiplier, + .texcoordUsageHint = GL_DYNAMIC_DRAW, // but menu texture does + }, (GLCustom){ + .create = &_create_touchmenu_hud, + .destroy = &glhud_destroyDefault, + }); + if (!menu.model) { + LOG("gltouchmenu initialization problem"); + return; + } + if (!menu.model->custom) { + LOG("gltouchmenu HUD initialization problem"); + return; + } + + clock_gettime(CLOCK_MONOTONIC, &menu.timingBegin); + + isAvailable = true; + + GL_ERRLOG("gltouchmenu_setup"); +} + static void gltouchmenu_render(void) { if (!isAvailable) { return; @@ -416,7 +398,16 @@ static void gltouchmenu_render(void) { return; } - float alpha = _get_menu_visibility(); + if (menu.nextGlyphMultiplier) { + menu.glyphMultiplier = menu.nextGlyphMultiplier; + menu.nextGlyphMultiplier = 0; + gltouchmenu_setup(); + } + + float alpha = glhud_getTimedVisibility(menu.timingBegin, menu.minAlpha, menu.maxAlpha); + if (alpha < menu.minAlpha) { + alpha = menu.minAlpha; + } if (alpha <= 0.0) { return; } @@ -506,7 +497,7 @@ static int64_t gltouchmenu_onTouchEvent(interface_touch_event_t action, int poin } if (handled) { - clock_gettime(CLOCK_MONOTONIC, &timingBegin); + clock_gettime(CLOCK_MONOTONIC, &menu.timingBegin); flags |= TOUCH_FLAGS_HANDLED; } @@ -525,17 +516,25 @@ static void gltouchmenu_setTouchMenuEnabled(bool enabled) { } static void _animation_showTouchMenu(void) { - clock_gettime(CLOCK_MONOTONIC, &timingBegin); + clock_gettime(CLOCK_MONOTONIC, &menu.timingBegin); } static void _animation_hideTouchMenu(void) { _hide_top_left(); _hide_top_right(); - timingBegin = (struct timespec){ 0 }; + menu.timingBegin = (struct timespec){ 0 }; } -static void gltouchmenu_setTouchMenuVisibility(float alpha) { - minAlpha = alpha; +static void gltouchmenu_setTouchMenuVisibility(float inactiveAlpha, float activeAlpha) { + menu.minAlpha = inactiveAlpha; + menu.maxAlpha = activeAlpha; +} + +static void gltouchmenu_setGlyphScale(int glyphScale) { + if (glyphScale == 0) { + glyphScale = 1; + } + menu.nextGlyphMultiplier = glyphScale; } // ---------------------------------------------------------------------------- @@ -551,6 +550,11 @@ static void _init_gltouchmenu(void) { interface_isTouchMenuAvailable = &gltouchmenu_isTouchMenuAvailable; interface_setTouchMenuEnabled = &gltouchmenu_setTouchMenuEnabled; interface_setTouchMenuVisibility = &gltouchmenu_setTouchMenuVisibility; + interface_setGlyphScale = &gltouchmenu_setGlyphScale; + + menu.glyphMultiplier = 1; + menu.minAlpha = 1/4.f; // Minimum alpha value of components (at zero, will not render) + menu.maxAlpha = 1.f; glnode_registerNode(RENDER_TOP, (GLNode){ .setup = &gltouchmenu_setup, diff --git a/src/video/glvideo.c b/src/video/glvideo.c index e5916bf9..fc12a83c 100644 --- a/src/video/glvideo.c +++ b/src/video/glvideo.c @@ -33,17 +33,8 @@ GLuint mainShaderProgram = UNINITIALIZED_GL; bool hackAroundBrokenAdreno200 = false; bool hackAroundBrokenAdreno205 = false; +extern GLfloat mvpIdentity[16] = { 0 }; static GLint uniformMVPIdx = UNINITIALIZED_GL; -static GLenum crtElementType = UNINITIALIZED_GL; -static GLuint crtNumElements = UNINITIALIZED_GL; - -static GLuint a2TextureName = UNINITIALIZED_GL; -static GLuint defaultFBO = UNINITIALIZED_GL; - -static GLuint crtVAOName = UNINITIALIZED_GL; -static GLuint posBufferName = UNINITIALIZED_GL; -static GLuint texcoordBufferName = UNINITIALIZED_GL; -static GLuint elementBufferName = UNINITIALIZED_GL; static GLModel *crtModel = NULL; static GLuint vertexShader = UNINITIALIZED_GL; @@ -58,431 +49,6 @@ static int glutWindow = -1; #endif //---------------------------------------------------------------------------- -// -// OpenGL helper routines -// - -static void _create_CRT_model(void) { - - // NOTE: vertices in Normalized Device Coordinates - const GLfloat crt_positions[] = { - // CRT screen quad - -1.0, -1.0, 0.0, 1.0, - 1.0, -1.0, 0.0, 1.0, - -1.0, 1.0, 0.0, 1.0, - 1.0, 1.0, 0.0, 1.0, -#if PERSPECTIVE - // CRT back side point - 0.0, 0.0, -1.0, 1.0, -#endif - }; - const GLfloat crt_texcoords[] = { - 0.0, 1.0, - 1.0, 1.0, - 0.0, 0.0, - 1.0, 0.0, - }; - const GLushort indices[] = { - // CRT screen quad - 0, 1, 2, 2, 1, 3 -#if PERSPECTIVE - // ... -#endif - }; - - GLModel *crt = calloc(1, sizeof(GLModel)); - crt->numVertices = 4; - crt->numElements = 6; - - crt->positions = malloc(sizeof(crt_positions)); - memcpy(crt->positions, &crt_positions[0], sizeof(crt_positions)); - crt->positionType = GL_FLOAT; - crt->positionSize = 4; // x,y,z coordinates - crt->positionArraySize = sizeof(crt_positions); - - crt->texCoords = malloc(sizeof(crt_texcoords)); - memcpy(crt->texCoords, &crt_texcoords[0], sizeof(crt_texcoords)); - crt->texcoordType = GL_FLOAT; - crt->texcoordSize = 2; // s,t coordinates - crt->texcoordArraySize = sizeof(crt_texcoords); - - crt->normals = NULL; - crt->normalType = GL_NONE; - crt->normalSize = GL_NONE; - crt->normalArraySize = 0; - - crt->elements = malloc(sizeof(indices)); - memcpy(crt->elements, &indices[0], sizeof(indices)); - crt->elementType = GL_UNSIGNED_SHORT; - crt->elementArraySize = sizeof(indices); - - mdlDestroyModel(&crtModel); - crtModel = crt; -} - -static void _create_VAO_VBOs(void) { - - // Create a vertex array object (VAO) to cache model parameters -#if USE_VAO - glGenVertexArrays(1, &crtVAOName); - glBindVertexArray(crtVAOName); -#endif - - // Create a vertex buffer object (VBO) to store positions and load data - glGenBuffers(1, &posBufferName); - glBindBuffer(GL_ARRAY_BUFFER, posBufferName); - glBufferData(GL_ARRAY_BUFFER, crtModel->positionArraySize, crtModel->positions, GL_STATIC_DRAW); - -#if USE_VAO - // Enable the position attribute for this VAO - glEnableVertexAttribArray(POS_ATTRIB_IDX); - - // Get the size of the position type so we can set the stride properly - GLsizei posTypeSize = getGLTypeSize(crtModel->positionType); - - // Set up parmeters for position attribute in the VAO including, - // size, type, stride, and offset in the currenly bound VAO - // This also attaches the position VBO to the VAO - glVertexAttribPointer(POS_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram) - crtModel->positionSize, // How many elements are there per position? - crtModel->positionType, // What is the type of this data? - GL_FALSE, // Do we want to normalize this data (0-1 range for fixed-pont types) - crtModel->positionSize*posTypeSize, // What is the stride (i.e. bytes between positions)? - 0); // What is the offset in the VBO to the position data? -#endif - - if (crtModel->texCoords) { - // Create a VBO to store texcoords - glGenBuffers(1, &texcoordBufferName); - glBindBuffer(GL_ARRAY_BUFFER, texcoordBufferName); - - // Allocate and load texcoord data into the VBO - glBufferData(GL_ARRAY_BUFFER, crtModel->texcoordArraySize, crtModel->texCoords, GL_STATIC_DRAW); - -#if USE_VAO - // Enable the texcoord attribute for this VAO - glEnableVertexAttribArray(TEXCOORD_ATTRIB_IDX); - - // Get the size of the texcoord type so we can set the stride properly - GLsizei texcoordTypeSize = getGLTypeSize(crtModel->texcoordType); - - // Set up parmeters for texcoord attribute in the VAO including, - // size, type, stride, and offset in the currenly bound VAO - // This also attaches the texcoord VBO to VAO - glVertexAttribPointer(TEXCOORD_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram) - crtModel->texcoordSize, // How many elements are there per texture coord? - crtModel->texcoordType, // What is the type of this data in the array? - GL_TRUE, // Do we want to normalize this data (0-1 range for fixed-point types) - crtModel->texcoordSize*texcoordTypeSize, // What is the stride (i.e. bytes between texcoords)? - 0); // What is the offset in the VBO to the texcoord data? -#endif - } - - // Create a VBO to vertex array elements - // This also attaches the element array buffer to the VAO - glGenBuffers(1, &elementBufferName); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName); - - // Allocate and load vertex array element data into VBO - glBufferData(GL_ELEMENT_ARRAY_BUFFER, crtModel->elementArraySize, crtModel->elements, GL_STATIC_DRAW); - - GL_ERRLOG("finished creating VAO/VBOs"); -} - -static void _destroy_VAO(GLuint vaoName) { - - // Bind the VAO so we can get data from it -#if USE_VAO - glBindVertexArray(vaoName); - - // For every possible attribute set in the VAO - for (GLuint index = 0; index < 16; index++) { - // Get the VBO set for that attibute - GLuint bufName = 0; - glGetVertexAttribiv(index , GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint*)&bufName); - - // If there was a VBO set... - if (bufName) { - //...delete the VBO - glDeleteBuffers(1, &bufName); - } - } - - // Get any element array VBO set in the VAO - { - GLuint bufName = 0; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint*)&bufName); - - // If there was a element array VBO set in the VAO - if (bufName) { - //...delete the VBO - glDeleteBuffers(1, &bufName); - } - } - - // Finally, delete the VAO - glDeleteVertexArrays(1, &vaoName); -#else - glDeleteBuffers(1, &posBufferName); - posBufferName = UNINITIALIZED_GL; - glDeleteBuffers(1, &texcoordBufferName); - texcoordBufferName = UNINITIALIZED_GL; - glDeleteBuffers(1, &elementBufferName); - elementBufferName = UNINITIALIZED_GL; -#endif - - GL_ERRLOG("destroying VAO/VBOs"); -} - -static GLuint _create_CRT_texture(void) { - GLuint texName; - - // Create a texture object to apply to model - glGenTextures(1, &texName); - glActiveTexture(TEXTURE_ACTIVE_FRAMEBUFFER); - glBindTexture(GL_TEXTURE_2D, texName); - - // Set up filter and wrap modes for this texture object - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - // Indicate that pixel rows are tightly packed (defaults to a stride of sizeof(PIXEL_TYPE) which is good for RGBA or - // FLOAT data types) - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - // Allocate and load image data into texture - glTexImage2D(GL_TEXTURE_2D, /*level*/0, TEX_FORMAT_INTERNAL, SCANWIDTH, SCANHEIGHT, /*border*/0, TEX_FORMAT, TEX_TYPE, NULL); - - GL_ERRLOG("finished creating CRT texture"); - - return texName; -} - -static GLuint _build_program(demoSource *vertexSource, demoSource *fragmentSource, bool hasNormal, bool hasTexcoord) { - GLuint prgName; - - GLint logLength, status; - - // String to pass to glShaderSource - GLchar *sourceString = NULL; - - // Determine if GLSL version 140 is supported by this context. - // We'll use this info to generate a GLSL shader source string - // with the proper version preprocessor string prepended - float glLanguageVersion = 0.f; - - char *shaderLangVersion = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION); - if (shaderLangVersion == NULL) { - ERRQUIT("shader toolchain unavailable"); - } -#if TARGET_OS_IPHONE - sscanf(shaderLangVersion, "OpenGL ES GLSL ES %f", &glLanguageVersion); -#else - sscanf(shaderLangVersion, "%f", &glLanguageVersion); -#endif - - // GL_SHADING_LANGUAGE_VERSION returns the version standard version form - // with decimals, but the GLSL version preprocessor directive simply - // uses integers (thus 1.10 should 110 and 1.40 should be 140, etc.) - // We multiply the floating point number by 100 to get a proper - // number for the GLSL preprocessor directive - GLuint version = 100 * glLanguageVersion; - - // Get the size of the version preprocessor string info so we know - // how much memory to allocate for our sourceString - const GLsizei versionStringSize = sizeof("#version 123\n"); - - // Create a program object - prgName = glCreateProgram(); - - // Indicate the attribute indicies on which vertex arrays will be - // set with glVertexAttribPointer - // See buildVAO to see where vertex arrays are actually set - glBindAttribLocation(prgName, POS_ATTRIB_IDX, "inPosition"); - - if (hasNormal) { - glBindAttribLocation(prgName, NORMAL_ATTRIB_IDX, "inNormal"); - } - - if (hasTexcoord) { - glBindAttribLocation(prgName, TEXCOORD_ATTRIB_IDX, "inTexcoord"); - } - - ////////////////////////////////////// - // Specify and compile VertexShader // - ////////////////////////////////////// - - // Allocate memory for the source string including the version preprocessor information - sourceString = malloc(vertexSource->byteSize + versionStringSize); - - // Prepend our vertex shader source string with the supported GLSL version so - // the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts - if (version) { - sprintf(sourceString, "#version %d\n%s", version, vertexSource->string); - } else { - RELEASE_LOG("No GLSL version specified ... so NOT adding a #version directive to shader sources =P"); - sprintf(sourceString, "%s", vertexSource->string); - } - - vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, (const GLchar **)&(sourceString), NULL); - glCompileShader(vertexShader); - glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &logLength); - - if (logLength > 0) { - GLchar *log = (GLchar *)malloc(logLength); - glGetShaderInfoLog(vertexShader, logLength, &logLength, log); - LOG("Vtx Shader compile log:%s\n", log); - free(log); - } - - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status); - if (status == 0) { - LOG("Failed to compile vtx shader:\n%s\n", sourceString); - return 0; - } - - free(sourceString); - sourceString = NULL; - - // Attach the vertex shader to our program - glAttachShader(prgName, vertexShader); - - ///////////////////////////////////////// - // Specify and compile Fragment Shader // - ///////////////////////////////////////// - - // Allocate memory for the source string including the version preprocessor information - sourceString = malloc(fragmentSource->byteSize + versionStringSize); - - // Prepend our fragment shader source string with the supported GLSL version so - // the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts - if (version) { - sprintf(sourceString, "#version %d\n%s", version, fragmentSource->string); - } else { - sprintf(sourceString, "%s", fragmentSource->string); - } - - fragShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragShader, 1, (const GLchar **)&(sourceString), NULL); - glCompileShader(fragShader); - glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &logLength); - if (logLength > 0) { - GLchar *log = (GLchar *)malloc(logLength); - glGetShaderInfoLog(fragShader, logLength, &logLength, log); - LOG("Frag Shader compile log:\n%s\n", log); - free(log); - } - - glGetShaderiv(fragShader, GL_COMPILE_STATUS, &status); - if (status == 0) { - LOG("Failed to compile frag shader:\n%s\n", sourceString); - return 0; - } - - free(sourceString); - sourceString = NULL; - - // Attach the fragment shader to our program - glAttachShader(prgName, fragShader); - - ////////////////////// - // Link the program // - ////////////////////// - - glLinkProgram(prgName); - glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength); - if (logLength > 0) { - GLchar *log = (GLchar*)malloc(logLength); - glGetProgramInfoLog(prgName, logLength, &logLength, log); - LOG("Program link log:\n%s\n", log); - free(log); - } - - glGetProgramiv(prgName, GL_LINK_STATUS, &status); - if (status == 0) { - LOG("Failed to link program"); - return 0; - } - - glValidateProgram(prgName); - glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength); - if (logLength > 0) { - GLchar *log = (GLchar*)malloc(logLength); - glGetProgramInfoLog(prgName, logLength, &logLength, log); - LOG("Program validate log:\n%s\n", log); - free(log); - } - - glGetProgramiv(prgName, GL_VALIDATE_STATUS, &status); - if (status == 0) { - LOG("Failed to validate program"); - return 0; - } - - glUseProgram(prgName); - - /////////////////////////////////////// - // Setup common program input points // - /////////////////////////////////////// - - texSamplerLoc = glGetUniformLocation(prgName, "aTexture"); - if (texSamplerLoc < 0) { - LOG("OOPS, no framebufferTexture shader : %d", texSamplerLoc); - } else { - glUniform1i(texSamplerLoc, TEXTURE_ID_FRAMEBUFFER); - } - - GLint maxTextureUnits = -1; - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); - - if (maxTextureUnits < TEXTURE_ID_MAX) { -#warning FIXME TODO ... gracefully handle devices with low max texture units? - ERRLOG("OOPS ... MAX TEXTURE UNITS : %d (<%d)", maxTextureUnits, TEXTURE_ID_MAX); - } else { - LOG("GL_MAX_TEXTURE_IMAGE_UNITS : %d", maxTextureUnits); - } - - uniformMVPIdx = glGetUniformLocation(prgName, "modelViewProjectionMatrix"); - if (uniformMVPIdx < 0) { - LOG("OOPS, no modelViewProjectionMatrix in shader : %d", uniformMVPIdx); - } - - alphaValue = glGetUniformLocation(prgName, "aValue"); - if (alphaValue < 0) { - LOG("OOPS, no texture selector in shader : %d", alphaValue); - } - - GL_ERRLOG("build program"); - - return prgName; -} - -static demoSource *_create_shader_source(const char *fileName) { - demoSource *src = NULL; -#if defined(__APPLE__) - CFBundleRef mainBundle = CFBundleGetMainBundle(); - CFStringRef fileString = CFStringCreateWithCString(/*allocator*/NULL, fileName, CFStringGetSystemEncoding()); - CFURLRef fileURL = CFBundleCopyResourceURL(mainBundle, fileString, NULL, NULL); - CFRELEASE(fileString); - CFStringRef filePath = CFURLCopyFileSystemPath(fileURL, kCFURLPOSIXPathStyle); - CFRELEASE(fileURL); - src = srcLoadSource(CFStringGetCStringPtr(filePath, CFStringGetSystemEncoding())); - CFRELEASE(filePath); -#else - char *filePath = NULL; - asprintf(&filePath, "%s/shaders/%s", data_dir, fileName); - if (filePath) { - src = srcLoadSource(filePath); - free(filePath); - } else { - ERRLOG("OOPS Could not load shader from %s (%s)", filePath, fileName); - } -#endif - return src; -} static void gldriver_render(void); @@ -580,6 +146,10 @@ static void gldriver_init_common(void) { _gldriver_setup_hackarounds(); +#if !PERSPECTIVE + mtxLoadIdentity(mvpIdentity); +#endif + GLint value = UNINITIALIZED_GL; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); LOG("GL_MAX_TEXTURE_SIZE:%d", value); @@ -594,41 +164,72 @@ static void gldriver_init_common(void) { } // ---------------------------- - // Create CRT model VAO/VBOs + // Create Cathode Ray Tube (CRT) model ... which currently is just a simple texture quad model ... - // create CRT model - _create_CRT_model(); - - // Build Vertex Buffer Objects (VBOs) and Vertex Array Object (VAOs) with our model data - _create_VAO_VBOs(); - - // Cache the number of element and primType to use later in our glDrawElements calls - crtNumElements = crtModel->numElements; - crtElementType = crtModel->elementType; - -#if USE_VAO - // We're using VAOs we can destroy certain buffers since they are already - // loaded into GL and we've saved anything else we need - FREE(crtModel->elements); - FREE(crtModel->positions); - FREE(crtModel->normals); - FREE(crtModel->texCoords); -#endif - - // Build a default texture object with our image data - a2TextureName = _create_CRT_texture(); + mdlDestroyModel(&crtModel); + glActiveTexture(TEXTURE_ACTIVE_FRAMEBUFFER); +#warning HACK FIXME TODO ^^^^^^^ is glActiveTexture() call needed here? + crtModel = mdlCreateQuad((GLModelParams_s){ + .skew_x = -1.0, // model space coords + .skew_y = -1.0, + .z = 0.0, + .obj_w = 2.0, // entire model space (-1.0 to 1.0) + .obj_h = 2.0, + .positionUsageHint = GL_STATIC_DRAW, // positions don't change + .tex_w = SCANWIDTH, + .tex_h = SCANHEIGHT, + .texcoordUsageHint = GL_DYNAMIC_DRAW, // but texture (Apple //e framebuffer) does + }, (GLCustom){ 0 }); // ---------------------------- // Load/setup shaders - demoSource *vtxSource = _create_shader_source("Basic.vsh"); - demoSource *frgSource = _create_shader_source("Basic.fsh"); + demoSource *vtxSource = glshader_createSource("Basic.vsh"); + demoSource *frgSource = glshader_createSource("Basic.fsh"); + + assert(vtxSource && "Catastrophic failure if vertex shader did not compile"); + assert(frgSource && "Catastrophic failure if fragment shader did not compile"); // Build/use Program - mainShaderProgram = _build_program(vtxSource, frgSource, /*withNormal:*/false, /*withTexcoord:*/true); + mainShaderProgram = glshader_buildProgram(vtxSource, frgSource, /*withTexcoord:*/true, &vertexShader, &fragShader); - srcDestroySource(vtxSource); - srcDestroySource(frgSource); + glshader_destroySource(vtxSource); + glshader_destroySource(frgSource); + + /////////////////////////////////////// + // Setup common program input points // + /////////////////////////////////////// + + glUseProgram(mainShaderProgram); + + texSamplerLoc = glGetUniformLocation(mainShaderProgram, "aTexture"); + if (texSamplerLoc < 0) { + LOG("OOPS, no framebufferTexture shader : %d", texSamplerLoc); + } else { + glUniform1i(texSamplerLoc, TEXTURE_ID_FRAMEBUFFER); + } + + GLint maxTextureUnits = -1; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + + if (maxTextureUnits < TEXTURE_ID_MAX) { +#warning FIXME TODO ... gracefully handle devices with low max texture units? + ERRLOG("OOPS ... MAX TEXTURE UNITS : %d (<%d)", maxTextureUnits, TEXTURE_ID_MAX); + } else { + LOG("GL_MAX_TEXTURE_IMAGE_UNITS : %d", maxTextureUnits); + } + + uniformMVPIdx = glGetUniformLocation(mainShaderProgram, "modelViewProjectionMatrix"); + if (uniformMVPIdx < 0) { + LOG("OOPS, no modelViewProjectionMatrix in shader : %d", uniformMVPIdx); + } + + alphaValue = glGetUniformLocation(mainShaderProgram, "aValue"); + if (alphaValue < 0) { + LOG("OOPS, no texture selector in shader : %d", alphaValue); + } + + GL_ERRLOG("build program"); // ---------------------------- // setup static OpenGL state @@ -652,9 +253,6 @@ static void gldriver_init_common(void) { // Check for errors to make sure all of our setup went ok GL_ERRLOG("finished initialization"); -#if !defined(__APPLE__) - //glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); -#endif GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { ERRQUIT("framebuffer status: %04X", status); @@ -665,15 +263,6 @@ static void _gldriver_shutdown(void) { LOG("Beginning GLDriver shutdown ..."); // Cleanup all OpenGL objects - if (a2TextureName != UNINITIALIZED_GL) { - glDeleteTextures(1, &a2TextureName); - a2TextureName = UNINITIALIZED_GL; - } - - if (crtVAOName != UNINITIALIZED_GL) { - _destroy_VAO(crtVAOName); - crtVAOName = UNINITIALIZED_GL; - } mdlDestroyModel(&crtModel); @@ -715,7 +304,7 @@ static void gldriver_shutdown(void) { // #if USE_GLUT static void gldriver_update(int unused) { -#if DEBUG_GL +#if FPS_LOG static uint32_t prevCount = 0; static uint32_t idleCount = 0; @@ -764,25 +353,25 @@ static void gldriver_render(void) { // Calculate the modelview matrix to render our character // at the proper position and rotation - GLfloat mvp[16]; #if PERSPECTIVE + GLfloat mvp[16]; // Create model-view-projection matrix //mtxLoadTranslate(modelView, 0, 150, -450); //mtxRotateXApply(modelView, -90.0f); //mtxRotateApply(modelView, -45.0f, 0.7, 0.3, 1); mtxMultiply(mvp, projection, modelView); -#else - // Just load an identity matrix for a pure orthographic/non-perspective viewing - mtxLoadIdentity(mvp); -#endif // Have our shader use the modelview projection matrix // that we calculated above glUniformMatrix4fv(uniformMVPIdx, 1, GL_FALSE, mvp); +#else + // Just load an identity matrix for a pure orthographic/non-perspective viewing + glUniformMatrix4fv(uniformMVPIdx, 1, GL_FALSE, mvpIdentity); +#endif unsigned long wasDirty = video_clearDirty(); - char pixels[SCANWIDTH * SCANHEIGHT * sizeof(PIXEL_TYPE)]; // HACK FIXME TODO ... are we sure this does not overflow max stack buffer size? + char *pixels = (char *)crtModel->texPixels; if (wasDirty) { SCOPE_TRACE_VIDEO("pixel convert"); // Update texture from indexed-color Apple //e internal framebuffer @@ -799,19 +388,19 @@ static void gldriver_render(void) { } glActiveTexture(TEXTURE_ACTIVE_FRAMEBUFFER); - glBindTexture(GL_TEXTURE_2D, a2TextureName); + glBindTexture(GL_TEXTURE_2D, crtModel->textureName); glUniform1i(texSamplerLoc, TEXTURE_ID_FRAMEBUFFER); if (wasDirty) { SCOPE_TRACE_VIDEO("glvideo texImage2D"); - _HACKAROUND_GLTEXIMAGE2D_PRE(TEXTURE_ACTIVE_FRAMEBUFFER, a2TextureName); + _HACKAROUND_GLTEXIMAGE2D_PRE(TEXTURE_ACTIVE_FRAMEBUFFER, crtModel->textureName); glTexImage2D(GL_TEXTURE_2D, /*level*/0, TEX_FORMAT_INTERNAL, SCANWIDTH, SCANHEIGHT, /*border*/0, TEX_FORMAT, TEX_TYPE, (GLvoid *)&pixels[0]); } // Bind our vertex array object #if USE_VAO - glBindVertexArray(crtVAOName); + glBindVertexArray(crtModel->vaoName); #else - glBindBuffer(GL_ARRAY_BUFFER, posBufferName); + glBindBuffer(GL_ARRAY_BUFFER, crtModel->posBufferName); GLsizei posTypeSize = getGLTypeSize(crtModel->positionType); GLsizei texcoordTypeSize = getGLTypeSize(crtModel->texcoordType); @@ -828,7 +417,7 @@ static void gldriver_render(void) { // Set up parmeters for texcoord attribute in the VAO including, size, type, stride, and offset in the currenly // bound VAO This also attaches the texcoord VBO to VAO - glBindBuffer(GL_ARRAY_BUFFER, texcoordBufferName); + glBindBuffer(GL_ARRAY_BUFFER, crtModel->texcoordBufferName); glVertexAttribPointer(TEXCOORD_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram) crtModel->texcoordSize, // How many elements are there per texture coord? crtModel->texcoordType, // What is the type of this data in the array? @@ -837,7 +426,7 @@ static void gldriver_render(void) { 0); // What is the offset in the VBO to the texcoord data? glEnableVertexAttribArray(TEXCOORD_ATTRIB_IDX); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, crtModel->elementBufferName); #endif glUniform1f(alphaValue, 1.0); @@ -848,7 +437,7 @@ static void gldriver_render(void) { // Draw the CRT object and others _HACKAROUND_GLDRAW_PRE(); - glDrawElements(GL_TRIANGLES, crtNumElements, crtElementType, 0); + glDrawElements(GL_TRIANGLES, crtModel->numElements, crtModel->elementType, 0); // Render HUD nodes glnode_renderNodes(); @@ -902,7 +491,7 @@ static void gldriver_reshape(int w, int h) { } #if USE_GLUT -static void gldriver_init_glut(GLuint fbo) { +static void gldriver_init_glut(void) { glutInit(&argc, argv); glutInitDisplayMode(/*GLUT_DOUBLE|*/GLUT_RGBA); glutInitWindowSize(windowWidth, windowHeight); @@ -936,16 +525,12 @@ static void gldriver_init_glut(GLuint fbo) { //---------------------------------------------------------------------------- // backend renderer API -static void gldriver_init(void *fbo) { +static void gldriver_init(void *unused) { safe_to_do_opengl_logging = true; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" - defaultFBO = (GLuint)fbo; -#pragma GCC diagnostic pop #if defined(__APPLE__) || defined(ANDROID) gldriver_init_common(); #elif USE_GLUT - gldriver_init_glut(defaultFBO); + gldriver_init_glut(); #else #error no working codepaths #endif diff --git a/src/video/glvideo.h b/src/video/glvideo.h index 97ccbc74..20c34d2c 100644 --- a/src/video/glvideo.h +++ b/src/video/glvideo.h @@ -46,6 +46,7 @@ enum { extern GLint texSamplerLoc; extern GLint alphaValue; extern GLuint mainShaderProgram; +extern GLfloat mvpIdentity[16]; // Common Model View Projection matrix // http://stackoverflow.com/questions/13676070/how-to-properly-mix-drawing-calls-and-changes-of-a-sampler-value-with-a-single-s // https://developer.qualcomm.com/forum/qdevnet-forums/mobile-gaming-graphics-optimization-adreno/8896 diff --git a/src/video/video.h b/src/video/video.h index be21913d..642e0c8f 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -39,6 +39,7 @@ typedef struct video_backend_s { void (*animation_showCPUSpeed)(void); void (*animation_showDiskChosen)(int drive); void (*animation_showTrackSector)(int drive, int track, int sect); + void (*animation_setEnableShowTrackSector)(bool enabled); } video_backend_s; @@ -157,6 +158,9 @@ static inline unsigned long video_clearDirty(void) { return __sync_fetch_and_and(&_backend_vid_dirty, 0UL); } +extern bool video_saveState(StateHelper_s *helper); +extern bool video_loadState(StateHelper_s *helper); + // ---------------------------------------------------------------------------- /* @@ -186,8 +190,10 @@ uint8_t floating_bus_hibit(const bool hibit); #define FONT_GLYPH_X (7+/*unused*/1) // generated font.c uses a single byte (8bits) per font glyph line #define FONT_GLYPH_Y (FONT_HEIGHT_PIXELS>>1) // ... 8 bytes total for whole glyph +#define FONT_GLYPH_SCALE_Y (FONT_HEIGHT_PIXELS/FONT_GLYPH_Y) // FIXME NOTE : implicit 2x scaling in display.c ... #define MOUSETEXT_BEGIN 0x80 // offset + 0x20 length +#define MOUSETEXT_RETURN (MOUSETEXT_BEGIN+0x0d) #define MOUSETEXT_UP (MOUSETEXT_BEGIN+0x0b) #define MOUSETEXT_LEFT (MOUSETEXT_BEGIN+0x08) #define MOUSETEXT_RIGHT (MOUSETEXT_BEGIN+0x15) diff --git a/src/video_util/glUtil.h b/src/video_util/glUtil.h index ceb3c637..21e0d6d3 100644 --- a/src/video_util/glUtil.h +++ b/src/video_util/glUtil.h @@ -14,13 +14,15 @@ #ifndef __GL_UTIL_H__ #define __GL_UTIL_H__ +#define UNINITIALIZED_GL (-31337) // HACK FIXME TODO : is there an official OpenGL value we can use to signify an uninitialized state? (cannot depend on zero) + #if defined(__APPLE__) # define USE_VAO 1 # import # import # if TARGET_OS_IPHONE -# import -# import +# import +# import # else # import # import @@ -42,7 +44,7 @@ #endif #if !defined(USE_VAO) -#define USE_VAO 1 +# define USE_VAO 1 #endif // Global unified texture format constants ... @@ -112,3 +114,4 @@ static inline const char * GetGLErrorString(GLenum error) { } #endif // __GL_UTIL_H__ + diff --git a/src/video_util/imageUtil.m b/src/video_util/imageUtil.m index 9ac71f85..ca9ff58e 100644 --- a/src/video_util/imageUtil.m +++ b/src/video_util/imageUtil.m @@ -12,6 +12,7 @@ // Modified sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html #include "imageUtil.h" +#include "common.h" #if TARGET_OS_IPHONE #import @@ -38,11 +39,11 @@ demoImage *imgLoadImage(const char *filepathname, int flipVertical) { return NULL; } - demoImage *image = malloc(sizeof(demoImage)); + demoImage *image = MALLOC(sizeof(demoImage)); image->width = (GLuint)CGImageGetWidth(cgImage); image->height = (GLuint)CGImageGetHeight(cgImage); image->rowByteSize = image->width * 4; - image->data = malloc(image->height * image->rowByteSize); + image->data = MALLOC(image->height * image->rowByteSize); image->format = GL_RGBA; image->type = GL_UNSIGNED_BYTE; @@ -70,7 +71,7 @@ demoImage *imgLoadImage(const char *filepathname, int flipVertical) { } void imgDestroyImage(demoImage* image) { - free(image->data); - free(image); + FREE(image->data); + FREE(image); } diff --git a/src/video_util/modelUtil.c b/src/video_util/modelUtil.c index 014a8c9b..d3797b7b 100644 --- a/src/video_util/modelUtil.c +++ b/src/video_util/modelUtil.c @@ -44,7 +44,7 @@ GLModel *mdlLoadModel(const char *filepathname) { if (!filepathname) { return NULL; } - GLModel *model = (GLModel *)calloc(sizeof(GLModel), 1); + GLModel *model = (GLModel *)CALLOC(sizeof(GLModel), 1); if (!model) { return NULL; } @@ -116,9 +116,9 @@ GLModel *mdlLoadModel(const char *filepathname) { if (GL_UNSIGNED_INT == model->elementType) { // ...load the UI elements and convert to UNSIGNED_SHORT - GLubyte *uiElements = (GLubyte *)malloc(model->elementArraySize); + GLubyte *uiElements = (GLubyte *)MALLOC(model->elementArraySize); size_t ushortElementArraySize = model->numElements * sizeof(GLushort); - model->elements = (GLubyte *)malloc(ushortElementArraySize); + model->elements = (GLubyte *)MALLOC(ushortElementArraySize); sizeRead = fread(uiElements, 1, model->elementArraySize, curFile); if (sizeRead != model->elementArraySize) { @@ -138,12 +138,12 @@ GLModel *mdlLoadModel(const char *filepathname) { ((GLushort *)model->elements)[elemNum] = ((GLuint *)uiElements)[elemNum]; } - free(uiElements); + FREE(uiElements); model->elementType = GL_UNSIGNED_SHORT; model->elementArraySize = model->numElements * sizeof(GLushort); } else { - model->elements = (GLubyte*)malloc(model->elementArraySize); + model->elements = (GLubyte*)MALLOC(model->elementArraySize); sizeRead = fread(model->elements, 1, model->elementArraySize, curFile); @@ -166,7 +166,7 @@ GLModel *mdlLoadModel(const char *filepathname) { model->positionType = attrib.datatype; model->positionSize = attrib.sizePerElement; model->numVertices = attrib.numElements; - model->positions = (GLubyte*)malloc(model->positionArraySize); + model->positions = (GLubyte*)MALLOC(model->positionArraySize); sizeRead = fread(model->positions, 1, model->positionArraySize, curFile); if (sizeRead != model->positionArraySize) { @@ -200,7 +200,7 @@ GLModel *mdlLoadModel(const char *filepathname) { return NULL; } - model->texCoords = (GLubyte*)malloc(model->texcoordArraySize); + model->texCoords = (GLubyte*)MALLOC(model->texcoordArraySize); sizeRead = fread(model->texCoords, 1, model->texcoordArraySize, curFile); if (sizeRead != model->texcoordArraySize) { @@ -235,7 +235,7 @@ GLModel *mdlLoadModel(const char *filepathname) { return NULL; } - model->normals = (GLubyte*)malloc(model->normalArraySize ); + model->normals = (GLubyte*)MALLOC(model->normalArraySize ); sizeRead = fread(model->normals, 1, model->normalArraySize , curFile); if (sizeRead != model->normalArraySize) { @@ -276,7 +276,7 @@ GLModel *mdlLoadQuadModel(void) { 0, 3, 2 }; - GLModel *model = (GLModel *)calloc(sizeof(GLModel), 1); + GLModel *model = (GLModel *)CALLOC(sizeof(GLModel), 1); if (!model) { return NULL; @@ -285,23 +285,23 @@ GLModel *mdlLoadQuadModel(void) { model->positionType = GL_FLOAT; model->positionSize = 3; model->positionArraySize = sizeof(posArray); - model->positions = (GLubyte*)malloc(model->positionArraySize); + model->positions = (GLubyte*)MALLOC(model->positionArraySize); memcpy(model->positions, posArray, model->positionArraySize); model->texcoordType = GL_FLOAT; model->texcoordSize = 2; model->texcoordArraySize = sizeof(texcoordArray); - model->texCoords = (GLubyte*)malloc(model->texcoordArraySize); + model->texCoords = (GLubyte*)MALLOC(model->texcoordArraySize); memcpy(model->texCoords, texcoordArray, model->texcoordArraySize ); model->normalType = GL_FLOAT; model->normalSize = 3; model->normalArraySize = sizeof(normalArray); - model->normals = (GLubyte*)malloc(model->normalArraySize); + model->normals = (GLubyte*)MALLOC(model->normalArraySize); memcpy(model->normals, normalArray, model->normalArraySize); model->elementArraySize = sizeof(elementArray); - model->elements = (GLubyte*)malloc(model->elementArraySize); + model->elements = (GLubyte*)MALLOC(model->elementArraySize); memcpy(model->elements, elementArray, model->elementArraySize); model->primType = GL_TRIANGLES; @@ -312,7 +312,7 @@ GLModel *mdlLoadQuadModel(void) { return model; } -#endif +#endif // 0 static void _quadCreateVAOAndVBOs(GLModel *model) { @@ -325,7 +325,7 @@ static void _quadCreateVAOAndVBOs(GLModel *model) { // Create a vertex buffer object (VBO) to store positions and load data glGenBuffers(1, &(model->posBufferName)); glBindBuffer(GL_ARRAY_BUFFER, model->posBufferName); - glBufferData(GL_ARRAY_BUFFER, model->positionArraySize, model->positions, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, model->positionArraySize, model->positions, model->positionUsageHint); #if USE_VAO // Enable the position attribute for this VAO @@ -351,7 +351,7 @@ static void _quadCreateVAOAndVBOs(GLModel *model) { glBindBuffer(GL_ARRAY_BUFFER, model->texcoordBufferName); // Allocate and load texcoord data into the VBO - glBufferData(GL_ARRAY_BUFFER, model->texcoordArraySize, model->texCoords, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, model->texcoordArraySize, model->texCoords, model->texcoordUsageHint); #if USE_VAO // Enable the texcoord attribute for this VAO @@ -378,7 +378,15 @@ static void _quadCreateVAOAndVBOs(GLModel *model) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->elementBufferName); // Allocate and load vertex array element data into VBO - glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->elementArraySize, model->elements, GL_DYNAMIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->elementArraySize, model->elements, GL_STATIC_DRAW/* HACK TODO FIXME: investigate*/); + +#if USE_VAO + // We're using VAOs we can destroy certain buffers since they are already + // loaded into GL and we've saved anything else we need + FREE(model->elements); + //FREE(model->normals); + FREE(model->texCoords); +#endif GL_ERRLOG("quad creation of VAO/VBOs"); } @@ -409,7 +417,15 @@ static GLuint _quadCreateTexture(GLModel *model) { return texName; } -GLModel *mdlCreateQuad(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat obj_h, GLfloat z, GLsizei tex_w, GLsizei tex_h, GLCustom clazz) { +GLModel *mdlCreateQuad(GLModelParams_s parms, GLCustom clazz) { + + const GLfloat skew_x = parms.skew_x; + const GLfloat skew_y = parms.skew_y; + const GLfloat obj_w = parms.obj_w; + const GLfloat obj_h = parms.obj_h; + const GLfloat z = parms.z; + const GLsizei tex_w = parms.tex_w; + const GLsizei tex_h = parms.tex_h; /* 2...3 * . @@ -437,15 +453,17 @@ GLModel *mdlCreateQuad(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat ob GLModel *model = NULL; do { - model = calloc(1, sizeof(GLModel)); + model = CALLOC(1, sizeof(GLModel)); if (!model) { break; } model->numVertices = 4; model->numElements = 6; model->primType = GL_TRIANGLES; + model->positionUsageHint = parms.positionUsageHint; + model->texcoordUsageHint = parms.texcoordUsageHint; - model->positions = malloc(sizeof(obj_positions)); + model->positions = MALLOC(sizeof(obj_positions)); if (!(model->positions)) { break; } @@ -454,8 +472,12 @@ GLModel *mdlCreateQuad(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat ob model->positionSize = 4; // x,y,z coordinates model->positionArraySize = sizeof(obj_positions); - if (tex_w > 0 && tex_h > 0) { - model->texCoords = malloc(sizeof(obj_texcoords)); + model->texcoordType = UNINITIALIZED_GL; + model->texcoordSize = 0; + model->texcoordArraySize = 0; + const bool useTexture = (tex_w > 0 && tex_h > 0); + if (useTexture) { + model->texCoords = MALLOC(sizeof(obj_texcoords)); if (!(model->texCoords)) { break; } @@ -465,6 +487,7 @@ GLModel *mdlCreateQuad(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat ob model->texcoordArraySize = sizeof(obj_texcoords); } +#if 0 { // NO NORMALS for now model->normals = NULL; @@ -472,8 +495,9 @@ GLModel *mdlCreateQuad(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat ob model->normalSize = GL_NONE; model->normalArraySize = 0; } +#endif - model->elements = malloc(sizeof(indices)); + model->elements = MALLOC(sizeof(indices)); if (!(model->elements)) { break; } @@ -487,9 +511,10 @@ GLModel *mdlCreateQuad(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat ob model->posBufferName = UNINITIALIZED_GL; model->texcoordBufferName = UNINITIALIZED_GL; model->elementBufferName = UNINITIALIZED_GL; + model->texFormat = UNINITIALIZED_GL; _quadCreateVAOAndVBOs(model); - if (model->posBufferName == UNINITIALIZED_GL || model->texcoordBufferName == UNINITIALIZED_GL || model->elementBufferName == UNINITIALIZED_GL) { + if (model->posBufferName == UNINITIALIZED_GL || (useTexture && model->texcoordBufferName == UNINITIALIZED_GL) || model->elementBufferName == UNINITIALIZED_GL) { LOG("Error creating model buffers!"); break; } @@ -497,28 +522,28 @@ GLModel *mdlCreateQuad(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat ob model->texDirty = true; model->texWidth = tex_w; model->texHeight = tex_h; - model->texFormat = TEX_FORMAT; - model->texPixels = (GLvoid *)calloc(tex_w * tex_h * sizeof(PIXEL_TYPE), 1); - if (model->texPixels == NULL) { - break; - } - model->textureName = _quadCreateTexture(model); - if (model->textureName == UNINITIALIZED_GL) { - LOG("Error creating model texture!"); - break; + if (useTexture) { + model->texFormat = TEX_FORMAT; + model->texPixels = (GLvoid *)MALLOC(tex_w * tex_h * sizeof(PIXEL_TYPE)); + if (model->texPixels == NULL) { + break; + } + model->textureName = _quadCreateTexture(model); + if (model->textureName == UNINITIALIZED_GL) { + LOG("Error creating model texture!"); + break; + } } model->custom = NULL; if (clazz.create) { - model->custom = clazz.create(); - if (model->custom) { - model->custom->create = NULL; - model->custom->setup = clazz.setup; - model->custom->destroy = clazz.destroy; - if (model->custom->setup) { - model->custom->setup(model); - } + model->custom = clazz.create(model); + if (!model->custom) { + LOG("Error creating custom model!"); + break; } + model->custom->create = NULL; + model->custom->destroy = clazz.destroy; } GL_ERRLOG("quad creation"); @@ -543,7 +568,7 @@ void mdlDestroyModel(INOUT GLModel **model) { FREE(m->elements); FREE(m->positions); - FREE(m->normals); + //FREE(m->normals); FREE(m->texCoords); FREE(m->texPixels); @@ -558,6 +583,7 @@ void mdlDestroyModel(INOUT GLModel **model) { // For every possible attribute set in the VAO for (GLuint index = 0; index < 16; index++) { +#warning FIXME TODO ... why magick hardcoded 16? ... // Get the VBO set for that attibute GLuint bufName = 0; glGetVertexAttribiv(index , GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint*)&bufName); @@ -603,8 +629,9 @@ void mdlDestroyModel(INOUT GLModel **model) { } #endif - if (m->custom) { + if (m->custom && m->custom->destroy) { m->custom->destroy(m); + m->custom = NULL; } FREE(*model); diff --git a/src/video_util/modelUtil.h b/src/video_util/modelUtil.h index 603173fa..2d745eea 100644 --- a/src/video_util/modelUtil.h +++ b/src/video_util/modelUtil.h @@ -16,21 +16,19 @@ #include "common.h" -#define UNINITIALIZED_GL (-31337) -#warning FIXME TODO : is there an official OpenGL value we can use to signify an uninitialized state? - enum { POS_ATTRIB_IDX, TEXCOORD_ATTRIB_IDX, +#if 0 NORMAL_ATTRIB_IDX, +#endif }; typedef struct GLModel; #define MODEL_CLASS(CLS, ...) \ typedef struct CLS { \ - void *(*create)(void); \ - void (*setup)(struct GLModel *parent); \ + void *(*create)(struct GLModel *parent); \ void (*destroy)(struct GLModel *parent); \ __VA_ARGS__ \ } CLS; @@ -45,16 +43,21 @@ typedef struct GLModel { GLenum positionType; GLuint positionSize; GLsizei positionArraySize; + GLenum positionUsageHint; GLvoid *texCoords; GLenum texcoordType; GLuint texcoordSize; GLsizei texcoordArraySize; + GLenum texcoordUsageHint; +#if 0 GLvoid *normals; GLenum normalType; GLuint normalSize; GLsizei normalArraySize; + GLenum normalUsageHint; +#endif GLvoid *elements; GLenum elementType; @@ -83,11 +86,29 @@ typedef struct GLModel { GLCustom *custom; } GLModel; +#if 0 GLModel *mdlLoadModel(const char *filepathname); GLModel *mdlLoadQuadModel(); +#endif -GLModel *mdlCreateQuad(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat obj_h, GLfloat z, GLsizei tex_w, GLsizei tex_h, GLCustom clazz); +typedef struct GLModelParams_s { + // positions + GLfloat skew_x; + GLfloat skew_y; + GLfloat z; + GLfloat obj_w; + GLfloat obj_h; + GLenum positionUsageHint; + + // texture + GLsizei tex_w; + GLsizei tex_h; + GLenum texcoordUsageHint; + +} GLModelParams_s; + +GLModel *mdlCreateQuad(GLModelParams_s parms, GLCustom clazz); void mdlDestroyModel(INOUT GLModel **model); diff --git a/src/video_util/sourceUtil.c b/src/video_util/sourceUtil.c index 0c533bd9..d0c10307 100644 --- a/src/video_util/sourceUtil.c +++ b/src/video_util/sourceUtil.c @@ -12,13 +12,10 @@ // Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html #include "sourceUtil.h" +#include "modelUtil.h" -#include -#include -#include - -demoSource *srcLoadSource(const char *filepathname) { - demoSource *source = (demoSource *)calloc(sizeof(demoSource), 1); +static demoSource *srcLoadSource(const char *filepathname) { + demoSource *source = (demoSource *)CALLOC(sizeof(demoSource), 1); // Check the file name suffix to determine what type of shader this is const char *suffixBegin = filepathname + strlen(filepathname) - 4; @@ -42,7 +39,7 @@ demoSource *srcLoadSource(const char *filepathname) { source->byteSize = fileSize + 1; // Alloc memory for the string - source->string = malloc(source->byteSize); + source->string = MALLOC(source->byteSize); // Read entire file into the string from beginning of the file fseek(curFile, 0, SEEK_SET); @@ -56,8 +53,198 @@ demoSource *srcLoadSource(const char *filepathname) { return source; } -void srcDestroySource(demoSource *source) { - free(source->string); - free(source); +demoSource *glshader_createSource(const char *fileName) { + demoSource *src = NULL; +#if defined(__APPLE__) + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFStringRef fileString = CFStringCreateWithCString(/*allocator*/NULL, fileName, CFStringGetSystemEncoding()); + CFURLRef fileURL = CFBundleCopyResourceURL(mainBundle, fileString, NULL, NULL); + CFRELEASE(fileString); + CFStringRef filePath = CFURLCopyFileSystemPath(fileURL, kCFURLPOSIXPathStyle); + CFRELEASE(fileURL); + src = srcLoadSource(CFStringGetCStringPtr(filePath, CFStringGetSystemEncoding())); + CFRELEASE(filePath); +#else + char *filePath = NULL; + asprintf(&filePath, "%s/shaders/%s", data_dir, fileName); + if (filePath) { + src = srcLoadSource(filePath); + ASPRINTF_FREE(filePath); + } else { + ERRLOG("OOPS Could not load shader from %s (%s)", filePath, fileName); + } +#endif + return src; +} + +void glshader_destroySource(demoSource *source) { + FREE(source->string); + FREE(source); +} + +GLuint glshader_buildProgram(demoSource *vertexSource, demoSource *fragmentSource, /*bool hasNormal, */bool hasTexcoord, OUTPARM GLuint *vertexShader, OUTPARM GLuint *fragShader) { + GLuint prgName = UNINITIALIZED_GL; + GLint logLength = UNINITIALIZED_GL; + GLint status = UNINITIALIZED_GL; + + // String to pass to glShaderSource + GLchar *sourceString = NULL; + + // Determine if GLSL version 140 is supported by this context. + // We'll use this info to generate a GLSL shader source string + // with the proper version preprocessor string prepended + float glLanguageVersion = 0.f; + + char *shaderLangVersion = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION); + if (shaderLangVersion == NULL) { + ERRQUIT("shader toolchain unavailable"); + } +#if TARGET_OS_IPHONE + sscanf(shaderLangVersion, "OpenGL ES GLSL ES %f", &glLanguageVersion); +#else + sscanf(shaderLangVersion, "%f", &glLanguageVersion); +#endif + + // GL_SHADING_LANGUAGE_VERSION returns the version standard version form + // with decimals, but the GLSL version preprocessor directive simply + // uses integers (thus 1.10 should 110 and 1.40 should be 140, etc.) + // We multiply the floating point number by 100 to get a proper + // number for the GLSL preprocessor directive + GLuint version = 100 * glLanguageVersion; + + // Get the size of the version preprocessor string info so we know + // how much memory to allocate for our sourceString + const GLsizei versionStringSize = sizeof("#version 123\n"); + + // Create a program object + prgName = glCreateProgram(); + + // Indicate the attribute indicies on which vertex arrays will be + // set with glVertexAttribPointer + // See buildVAO to see where vertex arrays are actually set + glBindAttribLocation(prgName, POS_ATTRIB_IDX, "inPosition"); + +#if 0 + if (hasNormal) { + glBindAttribLocation(prgName, NORMAL_ATTRIB_IDX, "inNormal"); + } +#endif + + if (hasTexcoord) { + glBindAttribLocation(prgName, TEXCOORD_ATTRIB_IDX, "inTexcoord"); + } + + ////////////////////////////////////// + // Specify and compile VertexShader // + ////////////////////////////////////// + + // Allocate memory for the source string including the version preprocessor information + sourceString = MALLOC(vertexSource->byteSize + versionStringSize); + + // Prepend our vertex shader source string with the supported GLSL version so + // the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts + if (version) { + sprintf(sourceString, "#version %d\n%s", version, vertexSource->string); + } else { + RELEASE_LOG("No GLSL version specified ... so NOT adding a #version directive to shader sources =P"); + sprintf(sourceString, "%s", vertexSource->string); + } + + *vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(*vertexShader, 1, (const GLchar **)&(sourceString), NULL); + glCompileShader(*vertexShader); + glGetShaderiv(*vertexShader, GL_INFO_LOG_LENGTH, &logLength); + + if (logLength > 0) { + GLchar *log = (GLchar *)MALLOC(logLength); + glGetShaderInfoLog(*vertexShader, logLength, &logLength, log); + LOG("Vtx Shader compile log:%s\n", log); + FREE(log); + } + + glGetShaderiv(*vertexShader, GL_COMPILE_STATUS, &status); + if (status == 0) { + LOG("Failed to compile vtx shader:\n%s\n", sourceString); + return 0; + } + + FREE(sourceString); + + // Attach the vertex shader to our program + glAttachShader(prgName, *vertexShader); + + ///////////////////////////////////////// + // Specify and compile Fragment Shader // + ///////////////////////////////////////// + + // Allocate memory for the source string including the version preprocessor information + sourceString = MALLOC(fragmentSource->byteSize + versionStringSize); + + // Prepend our fragment shader source string with the supported GLSL version so + // the shader will work on ES, Legacy, and OpenGL 3.2 Core Profile contexts + if (version) { + sprintf(sourceString, "#version %d\n%s", version, fragmentSource->string); + } else { + sprintf(sourceString, "%s", fragmentSource->string); + } + + *fragShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(*fragShader, 1, (const GLchar **)&(sourceString), NULL); + glCompileShader(*fragShader); + glGetShaderiv(*fragShader, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + GLchar *log = (GLchar *)MALLOC(logLength); + glGetShaderInfoLog(*fragShader, logLength, &logLength, log); + LOG("Frag Shader compile log:\n%s\n", log); + FREE(log); + } + + glGetShaderiv(*fragShader, GL_COMPILE_STATUS, &status); + if (status == 0) { + LOG("Failed to compile frag shader:\n%s\n", sourceString); + return 0; + } + + FREE(sourceString); + + // Attach the fragment shader to our program + glAttachShader(prgName, *fragShader); + + ////////////////////// + // Link the program // + ////////////////////// + + glLinkProgram(prgName); + glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + GLchar *log = (GLchar*)MALLOC(logLength); + glGetProgramInfoLog(prgName, logLength, &logLength, log); + LOG("Program link log:\n%s\n", log); + FREE(log); + } + + glGetProgramiv(prgName, GL_LINK_STATUS, &status); + if (status == 0) { + LOG("Failed to link program"); + return 0; + } + + glValidateProgram(prgName); + glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength); + if (logLength > 0) { + GLchar *log = (GLchar*)MALLOC(logLength); + glGetProgramInfoLog(prgName, logLength, &logLength, log); + LOG("Program validate log:\n%s\n", log); + FREE(log); + } + + glGetProgramiv(prgName, GL_VALIDATE_STATUS, &status); + if (status == 0) { + LOG("Failed to validate program"); + return 0; + } + + GL_ERRLOG("build program"); + return prgName; } diff --git a/src/video_util/sourceUtil.h b/src/video_util/sourceUtil.h index fce53497..7b589890 100644 --- a/src/video_util/sourceUtil.h +++ b/src/video_util/sourceUtil.h @@ -14,7 +14,7 @@ #ifndef __SOURCE_UTIL_H__ #define __SOURCE_UTIL_H__ -#include "glUtil.h" +#include "common.h" typedef struct demoSourceRec { GLchar *string; @@ -22,8 +22,13 @@ typedef struct demoSourceRec { GLenum shaderType; // Vertex or Fragment } demoSource; -demoSource *srcLoadSource(const char *filepathname); +// Create a shader source object from a shader source file +extern demoSource *glshader_createSource(const char *filepathname); -void srcDestroySource(demoSource *source); +// Destroy a shader source object +extern void glshader_destroySource(demoSource *source); + +// Builds a GL program from shader sources +extern GLuint glshader_buildProgram(demoSource *vertexSource, demoSource *fragmentSource, /*bool hasNormal, */bool hasTexcoord, OUTPARM GLuint *vertexShader, OUTPARM GLuint *fragShader); #endif // __SOURCE_UTIL_H__ diff --git a/src/vm.c b/src/vm.c index aa1e09ac..20a20439 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1224,6 +1224,387 @@ void vm_reinitializeAudio(void) { #warning TODO FIXME ... should unset MB/Phasor hooks if volume is zero ... } +bool vm_saveState(StateHelper_s *helper) { + bool saved = false; + int fd = helper->fd; + + do { + uint8_t serialized[8] = { 0 }; + + serialized[0] = (uint8_t)((softswitches & 0xFF000000) >> 24); + serialized[1] = (uint8_t)((softswitches & 0xFF0000 ) >> 16); + serialized[2] = (uint8_t)((softswitches & 0xFF00 ) >> 8); + serialized[3] = (uint8_t)((softswitches & 0xFF ) >> 0); + LOG("SAVE softswitches = %08x", softswitches); + if (!helper->save(fd, serialized, sizeof(softswitches))) { + break; + } + + // save main/aux memory state + if (!helper->save(fd, apple_ii_64k[0], sizeof(apple_ii_64k))) { + break; + } + + // save language card + if (!helper->save(fd, language_card[0], sizeof(language_card))) { + break; + } + + // save language banks + if (!helper->save(fd, language_banks[0], sizeof(language_banks))) { + break; + } + + // save offsets + serialized[0] = 0x0; + serialized[1] = 0x1; + serialized[2] = 0x2; + serialized[3] = 0x3; + serialized[4] = 0x4; + serialized[5] = 0x5; + LOG("SAVE base_ramrd = %d", (base_ramrd == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_ramrd == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + LOG("SAVE base_ramwrt = %d", (base_ramwrt == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_ramwrt == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + LOG("SAVE base_textrd = %d", (base_textrd == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_textrd == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + LOG("SAVE base_textwrt = %d", (base_textwrt == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_textwrt == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + LOG("SAVE base_hgrrd = %d", (base_hgrrd == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_hgrrd == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + LOG("SAVE base_hgrwrt = %d", (base_hgrwrt == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_hgrwrt == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + LOG("SAVE base_stackzp = %d", (base_stackzp == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_stackzp == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + LOG("SAVE base_c3rom = %d", (base_c3rom == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_c3rom == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + LOG("SAVE base_cxrom = %d", (base_cxrom == apple_ii_64k[0]) ? serialized[0] : serialized[1]); + if (!helper->save(fd, (base_cxrom == apple_ii_64k[0]) ? &serialized[0] : &serialized[1], 1)) { + break; + } + + if (base_d000_rd == apple_ii_64k[0]) { + LOG("SAVE base_d000_rd = %d", serialized[0]); + if (!helper->save(fd, &serialized[0], 1)) { // base_d000_rd --> //e ROM + break; + } + } else if (base_d000_rd == language_banks[0] - 0xD000) { + LOG("SAVE base_d000_rd = %d", serialized[2]); + if (!helper->save(fd, &serialized[2], 1)) { // base_d000_rd --> main LC mem + break; + } + } else if (base_d000_rd == language_banks[0] - 0xC000) { + LOG("SAVE base_d000_rd = %d", serialized[3]); + if (!helper->save(fd, &serialized[3], 1)) { // base_d000_rd --> main LC mem + break; + } + } else if (base_d000_rd == language_banks[1] - 0xD000) { + LOG("SAVE base_d000_rd = %d", serialized[4]); + if (!helper->save(fd, &serialized[4], 1)) { // base_d000_rd --> aux LC mem + break; + } + } else if (base_d000_rd == language_banks[1] - 0xC000) { + LOG("SAVE base_d000_rd = %d", serialized[5]); + if (!helper->save(fd, &serialized[5], 1)) { // base_d000_rd --> aux LC mem + break; + } + } else { + LOG("OOPS ... language_banks[0] == %p base_d000_rd == %p", language_banks[0], base_d000_rd); + RELEASE_BREAK(); + } + + if (base_d000_wrt == 0) { + LOG("SAVE base_d000_wrt = %d", serialized[0]); + if (!helper->save(fd, &serialized[0], 1)) { // base_d000_wrt --> no write + break; + } + } else if (base_d000_wrt == language_banks[0] - 0xD000) { + LOG("SAVE base_d000_wrt = %d", serialized[2]); + if (!helper->save(fd, &serialized[2], 1)) { // base_d000_wrt --> main LC mem + break; + } + } else if (base_d000_wrt == language_banks[0] - 0xC000) { + LOG("SAVE base_d000_wrt = %d", serialized[3]); + if (!helper->save(fd, &serialized[3], 1)) { // base_d000_wrt --> main LC mem + break; + } + } else if (base_d000_wrt == language_banks[1] - 0xD000) { + LOG("SAVE base_d000_wrt = %d", serialized[4]); + if (!helper->save(fd, &serialized[4], 1)) { // base_d000_wrt --> aux LC mem + break; + } + } else if (base_d000_wrt == language_banks[1] - 0xC000) { + LOG("SAVE base_d000_wrt = %d", serialized[5]); + if (!helper->save(fd, &serialized[5], 1)) { // base_d000_wrt --> aux LC mem + break; + } + } else { + LOG("OOPS ... language_banks[0] == %p base_d000_wrt == %p", language_banks[0], base_d000_wrt); + RELEASE_BREAK(); + } + + if (base_e000_rd == apple_ii_64k[0]) { + LOG("SAVE base_e000_rd = %d", serialized[0]); + if (!helper->save(fd, &serialized[0], 1)) { // base_e000_rd --> //e ROM + break; + } + } else if (base_e000_rd == language_card[0] - 0xE000) { + LOG("SAVE base_e000_rd = %d", serialized[2]); + if (!helper->save(fd, &serialized[2], 1)) { // base_e000_rd --> main LC mem + break; + } + } else if (base_e000_rd == language_card[0] - 0xC000) { + LOG("SAVE base_e000_rd = %d", serialized[3]); + if (!helper->save(fd, &serialized[3], 1)) { // base_e000_rd --> aux LC mem + break; + } + } else { + LOG("OOPS ... language_card[0] == %p base_e000_rd == %p", language_card[0], base_e000_rd); + RELEASE_BREAK(); + } + + if (base_e000_wrt == 0) { + LOG("SAVE base_e000_wrt = %d", serialized[0]); + if (!helper->save(fd, &serialized[0], 1)) { // base_e000_wrt --> no write + break; + } + } else if (base_e000_wrt == language_card[0] - 0xE000) { + LOG("SAVE base_e000_wrt = %d", serialized[2]); + if (!helper->save(fd, &serialized[2], 1)) { // base_e000_wrt --> main LC mem + break; + } + } else if (base_e000_wrt == language_card[0] - 0xC000) { + LOG("SAVE base_e000_wrt = %d", serialized[3]); + if (!helper->save(fd, &serialized[3], 1)) { // base_e000_wrt --> aux LC mem + break; + } + } else { + LOG("OOPS ... language_card[0] == %p base_e000_wrt == %p", language_card[0], base_e000_wrt); + RELEASE_BREAK(); + } + + saved = true; + } while (0); + + return saved; +} + +bool vm_loadState(StateHelper_s *helper) { + bool loaded = false; + int fd = helper->fd; + + do { + + uint8_t serialized[4] = { 0 }; + + if (!helper->load(fd, serialized, sizeof(uint32_t))) { + break; + } + softswitches = (uint32_t)(serialized[0] << 24); + softswitches |= (uint32_t)(serialized[1] << 16); + softswitches |= (uint32_t)(serialized[2] << 8); + softswitches |= (uint32_t)(serialized[3] << 0); + LOG("LOAD softswitches = %08x", softswitches); + + // load main/aux memory state + if (!helper->load(fd, apple_ii_64k[0], sizeof(apple_ii_64k))) { + break; + } + + // load language card + if (!helper->load(fd, language_card[0], sizeof(language_card))) { + break; + } + + // load language banks + if (!helper->load(fd, language_banks[0], sizeof(language_banks))) { + break; + } + + // load offsets + uint8_t state = 0x0; + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_ramrd = %d", state); + base_ramrd = state == 0x0 ? apple_ii_64k[0] : apple_ii_64k[1]; + + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_ramwrt = %d", state); + base_ramwrt = state == 0x0 ? apple_ii_64k[0] : apple_ii_64k[1]; + + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_textrd = %d", state); + base_textrd = state == 0x0 ? apple_ii_64k[0] : apple_ii_64k[1]; + + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_textwrt = %d", state); + base_textwrt = state == 0x0 ? apple_ii_64k[0] : apple_ii_64k[1]; + + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_hgrrd = %d", state); + base_hgrrd = state == 0x0 ? apple_ii_64k[0] : apple_ii_64k[1]; + + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_hgrwrt = %d", state); + base_hgrwrt = state == 0x0 ? apple_ii_64k[0] : apple_ii_64k[1]; + + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_stackzp = %d", state); + base_stackzp = state == 0x0 ? apple_ii_64k[0] : apple_ii_64k[1]; + + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_c3rom = %d", state); + base_c3rom = state == 0x0 ? apple_ii_64k[0] : apple_ii_64k[1]; + + if (!helper->load(fd, &state, 1)) { + break; + } + LOG("LOAD base_cxrom = %d", state); + if (state == 0) { + base_cxrom = apple_ii_64k[0]; +#ifdef AUDIO_ENABLED + extern VMFunc MB_Read; + base_c4rom = (void *)MB_Read; + base_c5rom = (void *)MB_Read; +#else + base_c4rom = (void *)ram_nop; + base_c5rom = (void *)ram_nop; +#endif + } else { + base_cxrom = apple_ii_64k[1]; + base_c4rom = apple_ii_64k[1]; + base_c5rom = apple_ii_64k[1]; + } + + if (!helper->load(fd, &state, 1)) { + break; + } + switch (state) { + case 0: + base_d000_rd = apple_ii_64k[0]; + break; + case 2: + base_d000_rd = language_banks[0] - 0xD000; + break; + case 3: + base_d000_rd = language_banks[0] - 0xC000; + break; + case 4: + base_d000_rd = language_banks[1] - 0xD000; + break; + case 5: + base_d000_rd = language_banks[1] - 0xC000; + break; + default: + LOG("Unknown state base_d000_rd %02x", state); + RELEASE_BREAK(); + break; + } + LOG("LOAD base_d000_rd = %d", state); + + if (!helper->load(fd, &state, 1)) { + break; + } + switch (state) { + case 0: + base_d000_wrt = 0; + break; + case 2: + base_d000_wrt = language_banks[0] - 0xD000; + break; + case 3: + base_d000_wrt = language_banks[0] - 0xC000; + break; + case 4: + base_d000_wrt = language_banks[1] - 0xD000; + break; + case 5: + base_d000_wrt = language_banks[1] - 0xC000; + break; + default: + LOG("Unknown state base_d000_wrt %02x", state); + RELEASE_BREAK(); + break; + } + LOG("LOAD base_d000_wrt = %d", state); + + if (!helper->load(fd, &state, 1)) { + break; + } + switch (state) { + case 0: + base_e000_rd = apple_ii_64k[0]; + break; + case 2: + base_e000_rd = language_card[0] - 0xE000; + break; + case 3: + base_e000_rd = language_card[0] - 0xC000; + break; + default: + LOG("Unknown state base_e000_rd %02x", state); + RELEASE_BREAK(); + break; + } + LOG("LOAD base_e000_rd = %d", state); + + if (!helper->load(fd, &state, 1)) { + break; + } + switch (state) { + case 0: + base_e000_wrt = 0; + break; + case 2: + base_e000_wrt = language_card[0] - 0xE000; + break; + case 3: + base_e000_wrt = language_card[0] - 0xC000; + break; + default: + LOG("Unknown state base_e000_wrt %02x", state); + RELEASE_BREAK(); + break; + } + LOG("LOAD base_e000_wrt = %d", state); + + loaded = true; + } while (0); + + return loaded; +} + void debug_print_softwitches(void) { // useful from GDB ... diff --git a/src/vm.h b/src/vm.h index e728a070..aafb83a8 100644 --- a/src/vm.h +++ b/src/vm.h @@ -147,6 +147,9 @@ void vm_initialize(void); void vm_reinitializeAudio(void); +extern bool vm_saveState(StateHelper_s *helper); +extern bool vm_loadState(StateHelper_s *helper); + #if VM_TRACING void vm_trace_begin(const char *vm_file); void vm_trace_end(void); diff --git a/src/x86/cpu-regs.h b/src/x86/cpu-regs.h index b5d3ea03..83d3440a 100644 --- a/src/x86/cpu-regs.h +++ b/src/x86/cpu-regs.h @@ -89,6 +89,7 @@ # define _XSI %esi # define _XAX %eax /* scratch */ # define _XBX %ebx /* scratch2 */ +# define _X8 %eax // WRONG!!! FIXMENOW // full-length Apple ][ registers # define XY_Reg_X %ebx /* 6502 X&Y flags */ # define AF_Reg_X %ecx /* 6502 F&A flags */ @@ -127,16 +128,18 @@ #define CALL(foo) foo #else /* !NO_UNDERSCORES */ #if defined(__APPLE__) -# warning "2014/06/22 -- Apple's clang appears to not like certain manipulations of %_h register values (for example %ah, %ch) that are valid on *nix ... and it creates bizarre bytecode -# define APPLE_ASSEMBLER_IS_BROKEN 1 -# define SYM(foo) _##foo(%rip) -# define SYMX(foo, INDEX, SCALE) (_X8,INDEX,SCALE) # ifdef __LP64__ +# warning "2014/06/22 -- Mac requires PIC indexing +# define APPLE_ASSEMBLER_IS_BROKEN 1 +# define SYM(foo) _##foo(%rip) +# define SYMX(foo, INDEX, SCALE) (_X8,INDEX,SCALE) # define SYMX_PROLOGUE(foo) leaLQ _##foo(%rip), _X8; # else -# error "Building 32bit Darwin/x86 is not supported (unless you're a go-getter and make it supported)" +# define SYM(foo) _##foo +# define SYMX(foo, INDEX, SCALE) _##foo(,INDEX,SCALE) +# define SYMX_PROLOGUE(foo) # endif -# define ENTRY(foo) .globl _##foo; .balign 4; _##foo##: +# define ENTRY(foo) .globl _##foo; .balign 16; _##foo##: #else # define SYM(foo) _##foo # define SYMX(foo, INDEX, SCALE) _##foo(,INDEX,SCALE) diff --git a/src/x86/cpu.S b/src/x86/cpu.S index 385e1d85..8de850bd 100644 --- a/src/x86/cpu.S +++ b/src/x86/cpu.S @@ -1713,7 +1713,8 @@ ENTRY(op_SBC_dec) incb SYM(cpu65_opcycles) // +1 cycle GetFromEA_B DebugBCDCheck - btc $C_Flag_Bit, AF_Reg_X + bt $C_Flag_Bit, AF_Reg_X + cmc xchgb A_Reg, %al #if !defined(__LP64__) sbbb A_Reg, %al @@ -1722,7 +1723,6 @@ ENTRY(op_SBC_dec) cmc FlagNVZC #else - cmc sbbb A_Reg, %al // DAS algorithm : http://www.ray.masmcode.com/BCDdas.html // CF_old = CF diff --git a/src/zlib-helpers.c b/src/zlib-helpers.c index 6f71b408..825e8a1a 100644 --- a/src/zlib-helpers.c +++ b/src/zlib-helpers.c @@ -51,11 +51,12 @@ static const char* const _gzerr(gzFile gzf) { } } -/* Compress from file source to file dest until EOF on source. - def() returns Z_OK on success, Z_MEM_ERROR if memory could not be allocated - for processing, Z_VERSION_ERROR if the version of zlib.h and the version of - the library linked do not match, or Z_ERRNO if there is an error reading or - writing the files. */ +/* Compress some_file to some_file.gz and unlink previous. + * + * If expected_bytecount > 0, check that byte count written matches expected. + * + * Return NULL on success, or error string (possibly from zlib) on failure. + */ const char *zlib_deflate(const char* const src, const int expected_bytecount) { unsigned char buf[CHUNK]; int fd = -1; @@ -76,7 +77,7 @@ const char *zlib_deflate(const char* const src, const int expected_bytecount) { break; } - snprintf(dst, PATH_MAX-1, "%s%s", src, ".gz"); + snprintf(dst, PATH_MAX-1, "%s%s", src, EXT_GZ); gzdest = gzopen(dst, "wb"); if (gzdest == NULL) { @@ -114,7 +115,7 @@ const char *zlib_deflate(const char* const src, const int expected_bytecount) { } while (0); - if (bytecount != expected_bytecount) { + if (expected_bytecount && bytecount != expected_bytecount) { ERRLOG("OOPS did not write expected_bytecount of %d ... apparently wrote %d", expected_bytecount, bytecount); if (gzdest) { err = (char *)_gzerr(gzdest); @@ -141,12 +142,12 @@ const char *zlib_deflate(const char* const src, const int expected_bytecount) { return err; } -/* Decompress from file source to file dest until stream ends or EOF. - inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be - allocated for processing, Z_DATA_ERROR if the deflate data is - invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and - the version of the library linked do not match, or Z_ERRNO if there - is an error reading or writing the files. */ +/* Decompress some_file.gz to some_file and unlink previous. + * + * If expected_bytecount > 0, check that byte count read matches expected. + * + * Return NULL on success, or error string (possibly from zlib) on failure. + */ const char *zlib_inflate(const char* const src, const int expected_bytecount) { gzFile gzsource = NULL; int fd = -1; @@ -167,8 +168,8 @@ const char *zlib_inflate(const char* const src, const int expected_bytecount) { size_t len = strlen(src); snprintf(dst, PATH_MAX-1, "%s", src); - if (! ( (dst[len-3] == '.') && (dst[len-2] == 'g') && (dst[len-1] == 'z') ) ) { - ERRLOG("Expected filename ending in .gz"); + if (!is_gz(dst)) { + ERRLOG("Expected filename ending in %s", EXT_GZ); break; } dst[len-3] = '\0'; @@ -214,7 +215,7 @@ const char *zlib_inflate(const char* const src, const int expected_bytecount) { } while (0); - if (bytecount != expected_bytecount) { + if (expected_bytecount && bytecount != expected_bytecount) { ERRLOG("OOPS did not write expected_bytecount of %d ... apparently wrote %d", expected_bytecount, bytecount); if (gzsource) { err = (char *)_gzerr(gzsource);