2018-09-28 17:05:11 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copyright 2018 faddenSoft
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2019-12-04 23:50:19 +00:00
|
|
|
|
using System.Collections.ObjectModel;
|
2018-09-28 17:05:11 +00:00
|
|
|
|
|
|
|
|
|
namespace PluginCommon {
|
|
|
|
|
/// <summary>
|
2019-10-06 02:51:34 +00:00
|
|
|
|
/// Extension script "plugins" must implement this interface.
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
public interface IPlugin {
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Identification string. Contents are arbitrary, but should briefly identify the
|
|
|
|
|
/// purpose of the plugin, e.g. "Apple II ProDOS 8 MLI call handler". It may
|
|
|
|
|
/// contain version information, but should not be expected to be machine-readable.
|
|
|
|
|
/// </summary>
|
|
|
|
|
string Identifier { get; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-12-03 22:34:45 +00:00
|
|
|
|
/// Prepares the plugin for action. Called at the start of every code analysis pass
|
|
|
|
|
/// and when generating visualization images.
|
|
|
|
|
///
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// In the current implementation, the file data will be the same every time,
|
2019-10-06 02:51:34 +00:00
|
|
|
|
/// because it doesn't change after the project is opened. However, this could
|
2019-12-03 22:34:45 +00:00
|
|
|
|
/// change if we add a descramble feature. The IApplication and AddressTranslate
|
|
|
|
|
/// references will likely change between invocations.
|
|
|
|
|
///
|
|
|
|
|
/// This may be called even when the plugin won't be asked to do anything. Avoid
|
|
|
|
|
/// performing expensive operations here.
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="appRef">Reference to application interface.</param>
|
|
|
|
|
/// <param name="fileData">65xx code and data.</param>
|
2019-12-03 22:34:45 +00:00
|
|
|
|
/// <param name="addrTrans">Mapping between offsets and addresses.</param>
|
2019-10-14 01:19:28 +00:00
|
|
|
|
void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans);
|
2019-12-01 01:52:33 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Tells the plugin that we're done talking to it for now.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void Unprepare();
|
2019-10-14 01:19:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extension scripts that want to receive the list of symbols must implement this interface.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public interface IPlugin_SymbolList {
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Receives a list of the currently defined platform, project, and user symbols.
|
|
|
|
|
/// The list does not include auto-generated labels or local variables.
|
|
|
|
|
///
|
|
|
|
|
/// This is called immediately after Prepare(), before any other interfaces are
|
|
|
|
|
/// invoked, at the start of every code analysis pass.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="plSyms">Symbols available to plugins, in no particular order.</param>
|
|
|
|
|
void UpdateSymbolList(List<PlSymbol> plSyms);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Handles a notification that a user symbol has been added, edited, or removed. If the
|
|
|
|
|
/// label is of interest to the plugin, e.g. it changes how the plugin formats code or
|
|
|
|
|
/// data, the app needs to know.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// The application does a full re-analysis when project properties change, but not
|
|
|
|
|
/// when labels are edited. The CheckJsr/Jsl/Brk methods are only called during code
|
|
|
|
|
/// analysis, so if their behavior changes based on the presence or absence of a user
|
|
|
|
|
/// label then we need to tell the application that a full re-analysis is needed.
|
|
|
|
|
///
|
|
|
|
|
/// Plugins that don't care about user symbols, e.g. that just use tagged platform
|
|
|
|
|
/// symbols, can simply return false. (Changes to user labels that overlap with
|
|
|
|
|
/// project/platform symbols are detected by the app.)
|
|
|
|
|
/// </remarks>
|
|
|
|
|
/// <param name="beforeLabel">The label before the change, or empty if this is a
|
|
|
|
|
/// newly-added label.</param>
|
|
|
|
|
/// <param name="afterLabel">The label after the change, or empty if the label was
|
|
|
|
|
/// removed.</param>
|
|
|
|
|
/// <returns>True if the label change could affect the plugin's actions.</returns>
|
|
|
|
|
bool IsLabelSignificant(string beforeLabel, string afterLabel);
|
2019-08-02 23:06:27 +00:00
|
|
|
|
}
|
2018-09-28 17:05:11 +00:00
|
|
|
|
|
2019-10-06 02:51:34 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extension scripts that want to handle inline JSRs must implement this interface.
|
|
|
|
|
/// </summary>
|
2019-08-02 23:06:27 +00:00
|
|
|
|
public interface IPlugin_InlineJsr {
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks to see if code/data near a JSR instruction should be formatted.
|
2019-08-02 23:06:27 +00:00
|
|
|
|
///
|
|
|
|
|
/// The file data is guaranteed to hold all bytes of the JSR (offset + 2).
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="offset">Offset of the JSR instruction.</param>
|
2019-10-17 20:15:25 +00:00
|
|
|
|
/// <param name="operand">16-bit JSR operand.</param>
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// <param name="noContinue">Set to true if the JSR doesn't actually return.</param>
|
2019-10-17 20:15:25 +00:00
|
|
|
|
void CheckJsr(int offset, int operand, out bool noContinue);
|
2019-08-02 23:06:27 +00:00
|
|
|
|
}
|
2018-09-28 17:05:11 +00:00
|
|
|
|
|
2019-10-06 02:51:34 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extension scripts that want to handle inline JSLs must implement this interface.
|
|
|
|
|
/// </summary>
|
2019-08-02 23:06:27 +00:00
|
|
|
|
public interface IPlugin_InlineJsl {
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks to see if code/data near a JSL instruction should be formatted.
|
2019-08-02 23:06:27 +00:00
|
|
|
|
///
|
|
|
|
|
/// The file data is guaranteed to hold all bytes of the JSL (offset + 3).
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="offset">Offset of the JSL instruction.</param>
|
2019-10-17 20:15:25 +00:00
|
|
|
|
/// <param name="operand">24-bit JSL operand.</param>
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// <param name="noContinue">Set to true if the JSL doesn't actually return.</param>
|
2019-10-17 20:15:25 +00:00
|
|
|
|
void CheckJsl(int offset, int operand, out bool noContinue);
|
2018-09-28 17:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-06 02:51:34 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extension scripts that want to handle inline BRKs must implement this interface.
|
|
|
|
|
/// </summary>
|
2019-08-02 23:06:27 +00:00
|
|
|
|
public interface IPlugin_InlineBrk {
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks to see if code/data near a BRK instruction should be formatted.
|
|
|
|
|
///
|
|
|
|
|
/// The file data is only guaranteed to hold the BRK opcode byte.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="offset">Offset of the BRK instruction.</param>
|
Optionally treat BRKs as two-byte instructions
Early data sheets listed BRK as one byte, but RTI after a BRK skips
the following byte, effectively making BRK a 2-byte instruction.
Sometimes, such as when diassembling Apple /// SOS code, it's handy
to treat it that way explicitly.
This change makes two-byte BRKs optional, controlled by a checkbox
in the project settings. In the system definitions it defaults to
true for Apple ///, false for all others.
ACME doesn't allow BRK to have an arg, and cc65 only allows it for
65816 code (?), so it's emitted as a hex blob for those assemblers.
Anyone wishing to target those assemblers should stick to 1-byte mode.
Extension scripts have to switch between formatting one byte of
inline data and formatting an instruction with a one-byte operand.
A helper function has been added to the plugin Util class.
To get some regression test coverage, 2022-extension-scripts has
been configured to use two-byte BRK.
Also, added/corrected some SOS constants.
See also issue #44.
2019-10-09 21:55:56 +00:00
|
|
|
|
/// <param name="isTwoBytes">True if the CPU is configured for two-byte BRKs.</param>
|
2019-08-02 23:06:27 +00:00
|
|
|
|
/// <param name="noContinue">Set to true if the BRK doesn't actually return.</param>
|
Optionally treat BRKs as two-byte instructions
Early data sheets listed BRK as one byte, but RTI after a BRK skips
the following byte, effectively making BRK a 2-byte instruction.
Sometimes, such as when diassembling Apple /// SOS code, it's handy
to treat it that way explicitly.
This change makes two-byte BRKs optional, controlled by a checkbox
in the project settings. In the system definitions it defaults to
true for Apple ///, false for all others.
ACME doesn't allow BRK to have an arg, and cc65 only allows it for
65816 code (?), so it's emitted as a hex blob for those assemblers.
Anyone wishing to target those assemblers should stick to 1-byte mode.
Extension scripts have to switch between formatting one byte of
inline data and formatting an instruction with a one-byte operand.
A helper function has been added to the plugin Util class.
To get some regression test coverage, 2022-extension-scripts has
been configured to use two-byte BRK.
Also, added/corrected some SOS constants.
See also issue #44.
2019-10-09 21:55:56 +00:00
|
|
|
|
void CheckBrk(int offset, bool isTwoBytes, out bool noContinue);
|
2019-08-02 23:06:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-25 22:27:38 +00:00
|
|
|
|
/// <summary>
|
2019-11-27 02:54:42 +00:00
|
|
|
|
/// Extension scripts that want to generate visualizations must implement this interface.
|
2019-11-25 22:27:38 +00:00
|
|
|
|
/// </summary>
|
2019-11-27 02:54:42 +00:00
|
|
|
|
public interface IPlugin_Visualizer {
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Retrieves a list of descriptors for visualization generators implemented by this
|
2019-12-05 18:21:07 +00:00
|
|
|
|
/// plugin. The items in the set may have values based on the file data.
|
|
|
|
|
///
|
|
|
|
|
/// The caller must not modify the contents.
|
2019-11-27 02:54:42 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
VisDescr[] GetVisGenDescrs();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Executes the specified visualization generator with the supplied parameters.
|
|
|
|
|
/// </summary>
|
2020-03-01 02:30:19 +00:00
|
|
|
|
/// <param name="descr">Visualization generator descriptor.</param>
|
2019-11-27 02:54:42 +00:00
|
|
|
|
/// <param name="parms">Parameter set.</param>
|
2019-12-01 01:52:33 +00:00
|
|
|
|
/// <returns>2D visualization object reference, or null if something went
|
2019-12-05 18:21:07 +00:00
|
|
|
|
/// wrong (unknown ident, bad parameters, etc). By convention, an error
|
|
|
|
|
/// message is reported through the IApplication ReportError interface.</returns>
|
2019-12-04 23:50:19 +00:00
|
|
|
|
IVisualization2d Generate2d(VisDescr descr, ReadOnlyDictionary<string, object> parms);
|
2019-11-27 02:54:42 +00:00
|
|
|
|
}
|
2019-11-25 22:27:38 +00:00
|
|
|
|
|
2020-03-01 02:30:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Version 2 of the visualizer interface. Adds wireframe objects.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public interface IPlugin_Visualizer_v2 : IPlugin_Visualizer {
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Executes the specified visualization generator with the supplied parameters.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="descr">Visualization generator descriptor.</param>
|
|
|
|
|
/// <param name="parms">Parameter set.</param>
|
|
|
|
|
/// <returns>Wireframe visualization object reference, or null if something went
|
|
|
|
|
/// wrong (unknown ident, bad parameters, etc). By convention, an error
|
|
|
|
|
/// message is reported through the IApplication ReportError interface.</returns>
|
|
|
|
|
IVisualizationWireframe GenerateWireframe(VisDescr descr,
|
|
|
|
|
ReadOnlyDictionary<string, object> parms);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-04 23:50:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Visualization generator descriptor. IPlugin_Visualizer instances publish a list of
|
|
|
|
|
/// these to tell the application about the generators it supports.
|
|
|
|
|
/// </summary>
|
2019-11-27 02:54:42 +00:00
|
|
|
|
[Serializable]
|
|
|
|
|
public class VisDescr {
|
|
|
|
|
/// <summary>
|
2019-12-04 23:50:19 +00:00
|
|
|
|
/// Unique identifier. This is stored in the project file. Names beginning with
|
2020-03-08 00:52:36 +00:00
|
|
|
|
/// underscores ('_') are reserved and must not be defined by plugins.
|
2019-11-27 02:54:42 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
public string Ident { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Human-readable string describing the visualizer. Used for combo boxes and
|
|
|
|
|
/// other UI elements.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string UiName { get; private set; }
|
2019-11-25 22:27:38 +00:00
|
|
|
|
|
2020-04-12 00:24:21 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Visualization type, used to distinguish between bitmaps and wireframes.
|
|
|
|
|
/// </summary>
|
2019-11-27 02:54:42 +00:00
|
|
|
|
public enum VisType {
|
|
|
|
|
Unknown = 0,
|
|
|
|
|
Bitmap, // 2D bitmap
|
2020-03-01 02:30:19 +00:00
|
|
|
|
Wireframe, // wireframe mesh
|
2019-11-27 02:54:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Visualization type.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public VisType VisualizationType { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Visualization parameter descriptors.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public VisParamDescr[] VisParamDescrs { get; private set; }
|
|
|
|
|
|
2019-12-04 23:50:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor.
|
|
|
|
|
/// </summary>
|
2019-11-27 02:54:42 +00:00
|
|
|
|
public VisDescr(string ident, string uiName, VisType type, VisParamDescr[] descrs) {
|
|
|
|
|
Ident = ident;
|
|
|
|
|
UiName = uiName;
|
|
|
|
|
VisualizationType = type;
|
|
|
|
|
VisParamDescrs = descrs;
|
|
|
|
|
}
|
2019-11-25 22:27:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Visualization parameter descriptor.
|
|
|
|
|
/// </summary>
|
2019-12-04 23:50:19 +00:00
|
|
|
|
/// <remarks>
|
|
|
|
|
/// We provide min/max for individual numeric fields, but there's no way to check other
|
|
|
|
|
/// fields to see if e.g. Stride >= Width. We'd need a "verify" function and a way to
|
|
|
|
|
/// report errors that the GUI could use to point out what was wrong.
|
|
|
|
|
/// </remarks>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
[Serializable]
|
|
|
|
|
public class VisParamDescr {
|
2019-12-04 23:50:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Special feature enumeration.
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public enum SpecialMode {
|
|
|
|
|
None = 0, Offset
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-04 23:50:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Label to show in the UI.
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public string UiLabel { get; private set; }
|
2019-12-04 23:50:19 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Name to use internally. Do not use names that start with an underscore ('_'), as
|
|
|
|
|
/// these are reserved for future internal use.
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public string Name { get; private set; }
|
2019-12-04 23:50:19 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parameter data type.
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public Type CsType { get; private set; }
|
2019-11-27 02:54:42 +00:00
|
|
|
|
|
2019-12-04 23:50:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Minimum allowable value for int/float (and perhaps string length).
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public object Min { get; private set; }
|
2019-12-04 23:50:19 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Maximum allowable value for int/float (and perhaps string length).
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public object Max { get; private set; }
|
2019-12-04 23:50:19 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set to a value if the field requires special treatment.
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public SpecialMode Special { get; private set; }
|
2019-12-04 23:50:19 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Default value for this field.
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public object DefaultValue { get; private set; }
|
|
|
|
|
|
2019-12-04 23:50:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor.
|
|
|
|
|
/// </summary>
|
2019-11-25 22:27:38 +00:00
|
|
|
|
public VisParamDescr(string uiLabel, string name, Type csType, object min, object max,
|
|
|
|
|
SpecialMode special, object defVal) {
|
2020-01-21 19:02:36 +00:00
|
|
|
|
if (defVal.GetType() != csType) {
|
|
|
|
|
throw new ArgumentException("Mismatch between type and default value in \"" +
|
|
|
|
|
name + "\"");
|
|
|
|
|
}
|
2019-11-25 22:27:38 +00:00
|
|
|
|
UiLabel = uiLabel;
|
|
|
|
|
Name = name;
|
|
|
|
|
CsType = csType;
|
|
|
|
|
Min = min;
|
|
|
|
|
Max = max;
|
|
|
|
|
Special = special;
|
|
|
|
|
DefaultValue = defVal;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-11-27 02:54:42 +00:00
|
|
|
|
/// Rendered 2D visualization. The object represents the "raw" form of the data,
|
|
|
|
|
/// without scaling or filtering.
|
2019-11-25 22:27:38 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
public interface IVisualization2d {
|
2019-12-05 02:05:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bitmap width, in pixels.
|
|
|
|
|
/// </summary>
|
2019-11-28 01:12:26 +00:00
|
|
|
|
int Width { get; }
|
2019-12-05 02:05:17 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bitmap height, in pixels.
|
|
|
|
|
/// </summary>
|
2019-11-28 01:12:26 +00:00
|
|
|
|
int Height { get; }
|
|
|
|
|
|
2019-12-05 02:05:17 +00:00
|
|
|
|
//void SetPixelIndex(int x, int y, byte colorIndex);
|
|
|
|
|
//int GetPixel(int x, int y); // returns ARGB value
|
2019-11-27 02:54:42 +00:00
|
|
|
|
|
2019-12-05 02:05:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns a densely-packed array of color indices or ARGB values.
|
|
|
|
|
/// Do not modify.
|
|
|
|
|
/// </summary>
|
|
|
|
|
byte[] GetPixels();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the color palette as a series of 32-bit ARGB values. Will be null for
|
|
|
|
|
/// direct-color images.
|
|
|
|
|
/// Do not modify.
|
|
|
|
|
/// </summary>
|
|
|
|
|
int[] GetPalette();
|
2019-11-28 01:12:26 +00:00
|
|
|
|
|
2019-12-05 02:05:17 +00:00
|
|
|
|
// TODO(maybe): report pixel aspect ratio?
|
2019-11-25 22:27:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-01 02:30:19 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Holds raw vertex/edge/normal data collected from a 2D or 3D wireframe mesh. We use
|
Switch to left-handed coordinate system
There's no "standard" coordinate system, so the choice is arbitrary.
However, an examination of the Transporter mesh in Elite revealed
that the mesh was designed for a left-handed coordinate system. We
can compensate for that trivially in the Elite visualizer, but we
might as well match what they're doing. (The only change required
in the code is a couple of sign changes on the Z coordinate, and an
update to the rotation matrix.)
This also downsizes Matrix44 to Matrix33, exposes the rotation mode
enum, and adds a left-handed ZYX rotation mode.
This does mean that meshes that put the front at +Z will show their
backsides initially, since we're now oriented as if we're flying
the ships rather than facing them. I considered adding a 180-degree
Y rotation (with a tweak to the rotation matrix handedness to correct
the first rotation axis) to have them facing by default, but figured
that might be confusing since +Z is supposed to be away.
Anybody who really wants it to be the other way can trivially flip
the coordinates in their visualizer (negate xc/zc).
The Z coordinates in the visualization test project were flipped so
that the design is still facing the viewer at rotation (0,0,0).
2020-03-14 17:25:17 +00:00
|
|
|
|
/// a left-handed coordinate system (+Z goes into the screen). If the project being
|
2020-04-11 18:23:16 +00:00
|
|
|
|
/// disassembled uses different definitions for the axes, it's probably best to convert
|
|
|
|
|
/// them in the visualizer. 2D data should use X/Y with Z=0.
|
2020-03-01 02:30:19 +00:00
|
|
|
|
///
|
2020-04-11 18:23:16 +00:00
|
|
|
|
/// All objects will have vertices. Most will have edges, some will have points. Face
|
|
|
|
|
/// normals are optional.
|
2020-03-01 02:30:19 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
2020-03-07 00:51:47 +00:00
|
|
|
|
/// The face-normal stuff is designed specifically for Elite. Besides being one of the
|
|
|
|
|
/// very few 6502-based games to use backface culling, it extended the concept to allow
|
|
|
|
|
/// convex shapes to have protrusions.
|
2020-03-01 02:30:19 +00:00
|
|
|
|
///
|
2020-04-11 18:23:16 +00:00
|
|
|
|
/// Points are included primarily for the benefit of AVG games like Battlezone.
|
|
|
|
|
///
|
2020-03-07 00:51:47 +00:00
|
|
|
|
/// We favor multiple arrays over compound objects for this interface to avoid making
|
|
|
|
|
/// such objects part of the plugin interface.
|
2020-03-01 02:30:19 +00:00
|
|
|
|
///
|
2020-04-11 18:23:16 +00:00
|
|
|
|
/// TODO(maybe): specify colors for points and edges. Not widely used? Could be handy for
|
|
|
|
|
/// color AVG games like Tempest.
|
2020-03-01 02:30:19 +00:00
|
|
|
|
/// </remarks>
|
|
|
|
|
public interface IVisualizationWireframe {
|
2020-03-04 03:29:15 +00:00
|
|
|
|
// Each function returns the specified data. Do not modify the returned arrays.
|
2020-03-01 02:30:19 +00:00
|
|
|
|
|
2020-04-12 00:24:21 +00:00
|
|
|
|
bool Is2d { get; }
|
|
|
|
|
|
2020-03-01 02:30:19 +00:00
|
|
|
|
float[] GetVerticesX();
|
|
|
|
|
float[] GetVerticesY();
|
|
|
|
|
float[] GetVerticesZ();
|
|
|
|
|
|
2020-04-11 18:23:16 +00:00
|
|
|
|
int[] GetPoints();
|
2020-03-01 02:30:19 +00:00
|
|
|
|
IntPair[] GetEdges();
|
|
|
|
|
|
|
|
|
|
float[] GetNormalsX();
|
|
|
|
|
float[] GetNormalsY();
|
|
|
|
|
float[] GetNormalsZ();
|
|
|
|
|
|
|
|
|
|
IntPair[] GetVertexFaces();
|
|
|
|
|
IntPair[] GetEdgeFaces();
|
2020-03-13 17:53:53 +00:00
|
|
|
|
int[] GetExcludedVertices();
|
|
|
|
|
int[] GetExcludedEdges();
|
2020-04-23 18:25:45 +00:00
|
|
|
|
|
|
|
|
|
bool Validate(out string msg);
|
2020-03-01 02:30:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Represents a pair of integers. Immutable.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Serializable]
|
|
|
|
|
public struct IntPair {
|
|
|
|
|
public int Val0 { get; private set; }
|
|
|
|
|
public int Val1 { get; private set; }
|
|
|
|
|
|
|
|
|
|
public IntPair(int val0, int val1) {
|
|
|
|
|
Val0 = val0;
|
|
|
|
|
Val1 = val1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// <summary>
|
2019-10-06 02:51:34 +00:00
|
|
|
|
/// Interfaces provided by the application for use by plugins. An IApplication instance
|
2019-12-03 22:34:45 +00:00
|
|
|
|
/// is passed to the plugin as an argument to Prepare().
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
public interface IApplication {
|
2019-12-05 18:21:07 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Reports an error message to the application. Used by visualizers.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="msg"></param>
|
|
|
|
|
void ReportError(string msg);
|
|
|
|
|
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a debug message to the application. This can be useful when debugging scripts.
|
2019-12-03 22:34:45 +00:00
|
|
|
|
/// (For example, DEBUG > Show Analyzer Output shows output generated while performing
|
|
|
|
|
/// code analysis.)
|
2018-09-28 17:05:11 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="msg">Message to send.</param>
|
|
|
|
|
void DebugLog(string msg);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Specifies operand formatting.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="offset">File offset of opcode.</param>
|
|
|
|
|
/// <param name="subType">Sub-type. Must be appropriate for NumericLE.</param>
|
|
|
|
|
/// <param name="label">Optional symbolic label.</param>
|
|
|
|
|
/// <returns>True if the change was made, false if it was rejected.</returns>
|
|
|
|
|
bool SetOperandFormat(int offset, DataSubType subType, string label);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Formats file data as inline data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="offset">File offset.</param>
|
|
|
|
|
/// <param name="length">Length of item.</param>
|
|
|
|
|
/// <param name="type">Type of item. Must be NumericLE, NumericBE, or Dense.</param>
|
|
|
|
|
/// <param name="subType">Sub-type. Must be appropriate for type.</param>
|
|
|
|
|
/// <param name="label">Optional symbolic label.</param>
|
2019-10-06 02:51:34 +00:00
|
|
|
|
/// <returns>True if the change was made, false if it was rejected (e.g. because
|
|
|
|
|
/// the area is already formatted, or contains code).</returns>
|
|
|
|
|
/// <exception cref="PluginException">If something is really wrong, e.g. data runs
|
|
|
|
|
/// off end of file.</exception>
|
2018-09-28 17:05:11 +00:00
|
|
|
|
bool SetInlineDataFormat(int offset, int length, DataType type,
|
|
|
|
|
DataSubType subType, string label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Data format type.
|
|
|
|
|
/// </summary>
|
2019-10-14 01:19:28 +00:00
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Essentially a clone of FormatDescriptor.Type.
|
|
|
|
|
/// </remarks>
|
2018-09-28 17:05:11 +00:00
|
|
|
|
public enum DataType {
|
|
|
|
|
Unknown = 0,
|
|
|
|
|
NumericLE,
|
|
|
|
|
NumericBE,
|
Change the way string formats are defined
We used to use type="String", with the sub-type indicating whether
the string was null-terminated, prefixed with a length, or whatever.
This didn't leave much room for specifying a character encoding,
which is orthogonal to the sub-type.
What we actually want is to have the type specify the string type,
and then have the sub-type determine the character encoding. These
sub-types can also be used with the Numeric type to specify the
encoding of character operands.
This change updates the enum definitions and the various bits of
code that use them, but does not add any code for working with
non-ASCII character encodings.
The project file version number was incremented to 2, since the new
FormatDescriptor serialization is mildly incompatible with the old.
(Won't explode, but it'll post a complaint and ignore the stuff
it doesn't recognize.)
While I was at it, I finished removing DciReverse. It's still part
of the 2005-string-types regression test, which currently fails
because the generated source doesn't match.
2019-08-07 22:23:23 +00:00
|
|
|
|
StringGeneric,
|
2019-10-06 02:51:34 +00:00
|
|
|
|
StringReverse,
|
|
|
|
|
StringNullTerm,
|
|
|
|
|
StringL8,
|
|
|
|
|
StringL16,
|
|
|
|
|
StringDci,
|
2018-09-28 17:05:11 +00:00
|
|
|
|
Dense,
|
|
|
|
|
Fill
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Data format sub-type.
|
|
|
|
|
/// </summary>
|
2019-10-14 01:19:28 +00:00
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Essentially a clone of FormatDescriptor.SubType.
|
|
|
|
|
/// </remarks>
|
2018-09-28 17:05:11 +00:00
|
|
|
|
public enum DataSubType {
|
|
|
|
|
// No sub-type specified.
|
|
|
|
|
None = 0,
|
|
|
|
|
|
|
|
|
|
// For NumericLE/BE
|
|
|
|
|
Hex,
|
|
|
|
|
Decimal,
|
|
|
|
|
Binary,
|
|
|
|
|
Address,
|
2019-10-06 02:51:34 +00:00
|
|
|
|
Symbol,
|
|
|
|
|
|
|
|
|
|
// Strings and NumericLE/BE (single character)
|
|
|
|
|
Ascii,
|
|
|
|
|
HighAscii,
|
|
|
|
|
C64Petscii,
|
|
|
|
|
C64Screen
|
2018-09-28 17:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|