OXYGENHUB
◆ main openmsx / src / Plotter.hh
5.0 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef PLOTTER_HH
2
#define PLOTTER_HH
3
4
#include "PlotterPaper.hh"
5
#include "PrinterCore.hh"
6
7
#include "BooleanSetting.hh"
8
#include "EnumSetting.hh"
9
10
#include "gl_vec.hh"
11
12
#include <array>
13
#include <cstdint>
14
#include <memory>
15
#include <string>
16
17
namespace openmsx {
18
19
class BooleanSetting;
20
class CliComm;
21
class IntegerSetting;
22
class MSXMotherBoard;
23
24
// MSXPlotter: emulates Sony PRN-C41 color plotter with 4 pens
25
class MSXPlotter final : public PrinterCore
26
{
27
public:
28
	// Character set options for the plotter
29
	enum class CharacterSet : uint8_t { International, DIN };
30
	enum class PenThickness : uint8_t { Standard, Thick };
31
32
public:
33
	explicit MSXPlotter(MSXMotherBoard& motherBoard);
34
	MSXPlotter(const MSXPlotter&) = delete;
35
	MSXPlotter(MSXPlotter&&) = delete;
36
	MSXPlotter& operator=(const MSXPlotter&) = delete;
37
	MSXPlotter& operator=(MSXPlotter&&) = delete;
38
	~MSXPlotter() override;
39
40
	// Pluggable
41
	[[nodiscard]] zstring_view getName() const override;
42
	[[nodiscard]] zstring_view getDescription() const override;
43
	void plugHelper(Connector& connector, EmuTime time) override;
44
45
	// PrinterCore
46
	void write(uint8_t data) override;
47
	void forceFormFeed() override;
48
49
	[[nodiscard]] PlotterPaper* getPaper() { return paper.get(); }
50
51
	// Configuration settings (accessible by ImGui)
52
	[[nodiscard]] CharacterSet getCharacterSet() const;
53
	void setCharacterSet(CharacterSet cs);
54
	[[nodiscard]] bool getDipSwitch4() const;
55
	void setDipSwitch4(bool enabled);
56
57
	// Manual controls (for ImGui)
58
	void cyclePen();
59
	void moveStep(gl::vec2 delta);
60
	void ejectPaper();
61
62
	// Access to settings for persistence
63
	[[nodiscard]] EnumSetting<CharacterSet>& getCharacterSetSetting() { return charSetSetting; }
64
	[[nodiscard]] BooleanSetting& getDipSwitch4Setting() { return dipSwitch4Setting; }
65
	[[nodiscard]] EnumSetting<PenThickness>& getPenThicknessSetting() { return penThicknessSetting; }
66
67
	[[nodiscard]] gl::vec2 getPlotterPos() const { return penPosition + origin; }
68
	[[nodiscard]] unsigned getSelectedPen() const { return selectedPen; }
69
	[[nodiscard]] bool isGraphicMode() const { return mode == Mode::GRAPHIC; }
70
71
	void resetSettings();
72
	void ensurePrintPage();
73
	void flushEmulatedPrinter();
74
75
	// (Optional) serialization
76
	template<typename Archive>
77
	void serialize(Archive&, unsigned)
78
	{
79
		// TODO
80
	}
81
82
private:
83
	void updateLineFeed();
84
	void processTextMode(uint8_t data);
85
	void processGraphicMode(uint8_t data);
86
	void executeGraphicCommand();
87
	void moveTo(gl::vec2 pos);
88
	void lineTo(gl::vec2 pos);
89
	void drawLine(gl::vec2 from, gl::vec2 to);
90
	void drawCharacter(uint8_t c);
91
	void drawDot(gl::vec2 pos);
92
	void setPenDown(bool newState);
93
	void liftPen();
94
	void drawDashedLine(gl::vec2 A, gl::vec2 B, float halfPeriod);
95
	void drawSolidLine(gl::vec2 A, gl::vec2 B);
96
	[[nodiscard]] gl::vec2 toPaperPos(gl::vec2 plotterPos) const;
97
	[[nodiscard]] float penRadius() const;
98
	[[nodiscard]] gl::vec3 penColor() const;
99
100
private:
101
	CliComm& cliComm;
102
	std::shared_ptr<IntegerSetting> dpiSetting;
103
	std::unique_ptr<PlotterPaper> paper;
104
105
	// Configuration settings (persistent)
106
	EnumSetting<CharacterSet> charSetSetting;
107
	BooleanSetting dipSwitch4Setting;
108
	EnumSetting<PenThickness> penThicknessSetting;
109
110
	float pixelSize = 0.0f;
111
112
	// Mode state
113
	enum class Mode : uint8_t { TEXT, GRAPHIC };
114
	Mode mode = Mode::TEXT;
115
116
	// ESC sequence parsing state
117
	enum class EscState : uint8_t { NONE, ESC, ESC_C, ESC_S, ESC_S_EXP_DIGIT };
118
	EscState escState = EscState::NONE;
119
	enum class TerminatorSkip : uint8_t { NONE, START, SEEN_CR };
120
	TerminatorSkip terminatorSkip = TerminatorSkip::NONE;
121
	bool printNext = false; // For 0x01 literal prefix
122
123
	// Pen/color state
124
	uint8_t selectedPen = 0; // 0=black, 1=blue, 2=green, 3=red
125
	bool penDown = false;
126
127
	// Plotter head position (logical steps, relative to origin)
128
	gl::vec2 penPosition{0.0f, 0.0f};
129
130
	// Origin offset (physical steps)
131
	gl::vec2 origin{0.0f, 0.0f};
132
133
	// Line style
134
	uint8_t lineType = 0; // 0=solid, 1-14=dashed
135
	float dashDistance  = 0.0f;
136
	float maxLineHeight = 0.0f;
137
	float lineFeed      = 18.0f;
138
139
	// Character rotation (0-3)
140
	unsigned rotation = 0;
141
142
	// Pending character gap (to be removed if Q command follows)
143
	float pendingCharGap        = 0.0f;
144
	unsigned pendingGapRotation = 0;
145
146
	// Character scale (0-15, 0 is smallest)
147
	unsigned charScale         = 0;
148
	unsigned pendingScaleDigit = 0;
149
150
	// Graphic mode command buffer
151
	std::string graphicCmdBuffer;
152
153
public:
154
	// X-axis is the short axis (carriage), Y-axis is the long axis (paper feed).
155
	static constexpr auto A4_SIZE = gl::vec2{210.0f, 297.0f}; // portrait A4 in mm
156
	static constexpr gl::vec2 FULL_AREA = A4_SIZE * 5; // 5 steps/mm  ->  1050 x 1485 steps
157
158
	// A4 Plotting Area: 192mm x 276.8mm => 960 x 1384 steps.
159
	static constexpr gl::vec2 PLOT_AREA = {960.0f, 1384.0f};
160
	static constexpr auto RIGHT_BORDER = PLOT_AREA.x;
161
162
	static constexpr gl::vec2 MARGIN = (FULL_AREA - PLOT_AREA) * 0.5f;
163
164
	// Pen colors: 0=no ink, 1=full ink for subtractive model
165
	static constexpr std::array<gl::vec3, 4> inkColors = {{
166
		{0.48f, 0.48f, 0.48f}, // black
167
		{0.48f, 0.48f, 0.00f}, // blue
168
		{0.39f, 0.192f, 0.312f}, // green
169
		{0.00f, 0.48f, 0.48f}, // red
170
	}};
171
};
172
173
} // namespace openmsx
174
175
#endif