Compare commits
5 Commits
4f4483da51
...
9afd8b9670
| Author | SHA1 | Date | |
|---|---|---|---|
| 9afd8b9670 | |||
| b7b3044b63 | |||
| 4b919ee68c | |||
| c42adfb074 | |||
| 54a328d75b |
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
img
|
||||||
|
Doku
|
||||||
|
Presentation/*.aux
|
||||||
|
Presentation/*.log
|
||||||
|
Presentation/*.out
|
||||||
|
Presentation/*.gz
|
||||||
|
*.o
|
||||||
|
*.swp
|
||||||
|
spedit
|
||||||
779
Client/Client.ino
Normal file
@@ -0,0 +1,779 @@
|
|||||||
|
/*
|
||||||
|
* SSUP (Super Spiker Ultra Plus)
|
||||||
|
* Copyright (C) 2024-2026 Gabriel Weingardt
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License,
|
||||||
|
* or any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For further information, see <https://weingardt.dev/ssup/>
|
||||||
|
* There you'll find documentation and how to update the device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
#include "assets.h"
|
||||||
|
|
||||||
|
/* Screen dimension defines */
|
||||||
|
#define IMAGEX 128
|
||||||
|
#define IMAGEY 32
|
||||||
|
#define TEXTX 21
|
||||||
|
#define TEXTY 4
|
||||||
|
|
||||||
|
Adafruit_SSD1306 display(IMAGEX, IMAGEY, &Wire, -1);
|
||||||
|
|
||||||
|
const char PROGMEM HELP[] = \
|
||||||
|
"--- SSUP Help---\n\
|
||||||
|
Please see https://weingardt.dev/ssup for more info\n\
|
||||||
|
There you'll also find a manual and instructions\n\n\
|
||||||
|
g = Print System Info\n\
|
||||||
|
r = Reload Standart Configuration\n\
|
||||||
|
s = Enter Data Transfer Mode\n\
|
||||||
|
x = Exit Data Transfer Mode\n\
|
||||||
|
f = TOC Clear\n\
|
||||||
|
c = Clear EEPROM\n\
|
||||||
|
p = Print Page Content\n\
|
||||||
|
t = Print TOC Content\n\
|
||||||
|
h = Help\n\
|
||||||
|
u = Unlock Device\n\
|
||||||
|
l = Lock Device";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Serial BAUD rate */
|
||||||
|
#define BAUD 9600
|
||||||
|
|
||||||
|
/* EEPROM addresses for settings */
|
||||||
|
#define E_PAGE 0
|
||||||
|
#define E_CONTRAST 1
|
||||||
|
#define E_LOCK 2
|
||||||
|
#define E_EEPROM_SIZE 3
|
||||||
|
#define E_TOC_SIZE 4
|
||||||
|
#define E_SCREEN_ADDR 5
|
||||||
|
#define E_EEPROM_ADDR 6
|
||||||
|
#define E_THRESHHOLD 7
|
||||||
|
|
||||||
|
/* Calculator button pins */
|
||||||
|
#define ROW 3
|
||||||
|
#define D1 A3
|
||||||
|
#define D2 A2
|
||||||
|
#define D3 A0
|
||||||
|
#define D4 A1
|
||||||
|
|
||||||
|
#define LEFT 0b1000
|
||||||
|
#define SUPER 0b0100
|
||||||
|
#define TOGGLE 0b0010
|
||||||
|
#define RIGHT 0b0001
|
||||||
|
|
||||||
|
/* Serial flow control values and device info */
|
||||||
|
#define WAIT 0xFA
|
||||||
|
#define RELEASE 0xFB
|
||||||
|
#define MODEL 1
|
||||||
|
#define FIRMWARE 4
|
||||||
|
|
||||||
|
/* Setting variables */
|
||||||
|
uint8_t S_EEPROM_Address;
|
||||||
|
uint8_t S_SCREEN_Address;
|
||||||
|
uint16_t S_EEPROM_Size;
|
||||||
|
uint16_t S_TOC_SIZE;
|
||||||
|
uint8_t S_THRESHHOLD;
|
||||||
|
|
||||||
|
/* Variables */
|
||||||
|
uint8_t currentIndex = 0;
|
||||||
|
uint8_t currentPress = 4;
|
||||||
|
uint8_t fetchTrack = 0;
|
||||||
|
bool contrast = true;
|
||||||
|
bool locked = false;
|
||||||
|
bool dataTransferMode = false;
|
||||||
|
bool displayOn = true;
|
||||||
|
bool nextPage = false;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
/* Begin serial and I2C wire for EEPROM */
|
||||||
|
Serial.begin(BAUD);
|
||||||
|
Wire.begin();
|
||||||
|
Wire.setClock(400000);
|
||||||
|
|
||||||
|
/* Init settings */
|
||||||
|
loadSettings();
|
||||||
|
|
||||||
|
/* Say hello and lock status */
|
||||||
|
Serial.println("#SSUP\nType 'h' for help");
|
||||||
|
if (locked) Serial.println("!SSUP LOCK\n#This device is locked! Send 'u' to unlock it");
|
||||||
|
|
||||||
|
/* Init calculator scan pins */
|
||||||
|
pinMode(D1, INPUT_PULLUP);
|
||||||
|
pinMode(D2, INPUT_PULLUP);
|
||||||
|
pinMode(D3, INPUT_PULLUP);
|
||||||
|
pinMode(D4, INPUT_PULLUP);
|
||||||
|
pinMode(ROW, OUTPUT);
|
||||||
|
|
||||||
|
/* Init display
|
||||||
|
* Note: If less than ~768 bytes of dynamic memory is avaiable,
|
||||||
|
* the display will fail to init. The screen library needs 1k
|
||||||
|
* of dynamic memory during runtime!
|
||||||
|
*/
|
||||||
|
if (!display.begin(SSD1306_SWITCHCAPVCC, S_SCREEN_Address)) {
|
||||||
|
Serial.print("!DISPLAYBAD: ");
|
||||||
|
Serial.println(display.getWriteError());
|
||||||
|
Serial.println("#See manual");
|
||||||
|
}
|
||||||
|
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setTextColor(SSD1306_WHITE);
|
||||||
|
display.cp437(true);
|
||||||
|
|
||||||
|
/* Print welcome screen */
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setCursor(38, 12);
|
||||||
|
display.write("@");
|
||||||
|
display.print(BAUD);
|
||||||
|
display.write(" Baud");
|
||||||
|
|
||||||
|
scanButtons();
|
||||||
|
if ((currentPress & RIGHT) != 0) {
|
||||||
|
//display.fillRect(102, 12, 16, 16, SSD1306_BLACK);
|
||||||
|
display.drawBitmap(0, 0, LOGO, 128, 32, 1);
|
||||||
|
//display.drawBitmap(102, 12, WHAT, 16, 16, 1);
|
||||||
|
display.display();
|
||||||
|
delay(4000);
|
||||||
|
if (currentPress == (RIGHT | LEFT))
|
||||||
|
for (;;);
|
||||||
|
} else if ((currentPress & LEFT) != 0) {
|
||||||
|
|
||||||
|
/* Restore settings on left press */
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
display.print("Loading Default Settings");
|
||||||
|
resetSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
Wire.begin();
|
||||||
|
|
||||||
|
delay(6000);
|
||||||
|
|
||||||
|
/* Display first page */
|
||||||
|
currentIndex = 0;
|
||||||
|
displayPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
scanButtons();
|
||||||
|
|
||||||
|
static float datCount = 0;
|
||||||
|
static uint8_t recieved = 0;
|
||||||
|
|
||||||
|
/* Look while data is in seral buffer */
|
||||||
|
while (Serial.available()) {
|
||||||
|
static bool indexMode = false;
|
||||||
|
static bool contentMode = false;
|
||||||
|
static bool image = false;
|
||||||
|
|
||||||
|
static uint8_t newIndex;
|
||||||
|
static uint16_t startAddress;
|
||||||
|
static uint16_t endAddress;
|
||||||
|
|
||||||
|
/* Get recieved data */
|
||||||
|
recieved = (uint8_t)Serial.read();
|
||||||
|
|
||||||
|
datCount += (recieved / 100.f);
|
||||||
|
|
||||||
|
if (contentMode) {
|
||||||
|
/* If in content mode (data upload mode) */
|
||||||
|
|
||||||
|
/* Stop on character ']' */
|
||||||
|
if (recieved == ']') {
|
||||||
|
Serial.println("!DONE");
|
||||||
|
contentMode = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Else, interpret the send data */
|
||||||
|
static int count = 0;
|
||||||
|
count++;
|
||||||
|
|
||||||
|
/* Send '.' every 8 counts for the master to flow control data */
|
||||||
|
if (count > 8) {
|
||||||
|
count = 0;
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image) {
|
||||||
|
/* For the image, decode 2 byte ASCII HEX into a byte */
|
||||||
|
static uint8_t num = 0;
|
||||||
|
/* Stop digging byte on ';' */
|
||||||
|
if (recieved == ';') {
|
||||||
|
writeEEPROM(startAddress++, num);
|
||||||
|
num = 0;
|
||||||
|
|
||||||
|
} else if (isalnum(recieved)) {
|
||||||
|
/* Fetch ASCII hex digit (0..F) into a nibble and construct the byte */
|
||||||
|
recieved = tolower(recieved);
|
||||||
|
uint8_t fetch = ((recieved - ((recieved >= '0' && recieved <= '9') ? '0' : 'a')) & 0xF);
|
||||||
|
|
||||||
|
/* First, shift previous fetch and then OR the new nibble */
|
||||||
|
num = num << 4;
|
||||||
|
num |= fetch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Else, just write the ASCII data */
|
||||||
|
} else if (recieved >= 0x20) writeEEPROM(startAddress++, recieved);
|
||||||
|
|
||||||
|
/* On overflow, request temporary pause from master */
|
||||||
|
if (startAddress > endAddress) Serial.println("!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else if (indexMode) {
|
||||||
|
/* Index mode fetches the allocation mode for the next entry */
|
||||||
|
if (recieved == ';') {
|
||||||
|
/* If ';' was recieved, alloc entry and reset index mode, now comes the data */
|
||||||
|
indexMode = false;
|
||||||
|
contentMode = true;
|
||||||
|
newIndex = allocPage(image);
|
||||||
|
startAddress = (getPageAddress(newIndex) & 0x7FFF);
|
||||||
|
endAddress = (startAddress + getPageSize(newIndex));
|
||||||
|
|
||||||
|
} else image = (recieved != 't'); // Determine image or text
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Interpret the recieved serial characters */
|
||||||
|
|
||||||
|
switch (recieved) {
|
||||||
|
case 'g':
|
||||||
|
/* Print system info to serial */
|
||||||
|
printSystemInfo();
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
/* Load default values and reset */
|
||||||
|
Serial.println("!RESETTING");
|
||||||
|
resetSettings();
|
||||||
|
setup();
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
/* Set data transfer mode */
|
||||||
|
dataTransferMode = true;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
/* Exit data transfer mode */
|
||||||
|
dataTransferMode = false;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
/* Clear fast, only TOC */
|
||||||
|
clearTOC();
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
/* Clear entire EEPROM */
|
||||||
|
clearEEPROM();
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
/* Print all page content to serial */
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
uint16_t addr = getPageAddress(i);
|
||||||
|
if (addr != 0) printPageData(i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
/* Print TOC entries (addresses and size) */
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
printTOC(i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
/* Print help dialog */
|
||||||
|
Serial.println(HELP);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
/* Unlock device */
|
||||||
|
EEPROM.write(E_LOCK, 0);
|
||||||
|
Serial.println("!UNLOCKED");
|
||||||
|
setup();
|
||||||
|
case 'l':
|
||||||
|
/* Lock device */
|
||||||
|
EEPROM.write(E_LOCK, 1);
|
||||||
|
Serial.println("!LOCKED");
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
/* Start index mode (new page entry) */
|
||||||
|
indexMode = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.println("?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataTransferMode) {
|
||||||
|
/* If in data transfer mode, show data transfer screen animation */
|
||||||
|
static float rotCount = 0;
|
||||||
|
|
||||||
|
display.clearDisplay();
|
||||||
|
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
display.print("Transfer mode\nHold D2+D3 to \nforcefully abort");
|
||||||
|
|
||||||
|
/* Nice little animation */
|
||||||
|
display.drawLine(108, 16, 108 + (cosf(rotCount) * 10), 16 + (sinf(rotCount) * 10), SSD1306_WHITE);
|
||||||
|
display.drawLine(108, 16, 108 + (sinf(datCount + rotCount) * 10), 16 + (cosf(datCount + rotCount) * 10), SSD1306_WHITE);
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
//delay(3);
|
||||||
|
|
||||||
|
rotCount += 0.125;
|
||||||
|
|
||||||
|
scanButtons();
|
||||||
|
if (currentPress == (SUPER | TOGGLE)) dataTransferMode = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* If not in data transfer mode, we are in display/normal mode */
|
||||||
|
|
||||||
|
bool wait = true;
|
||||||
|
/* Test the current key press */
|
||||||
|
switch (currentPress) {
|
||||||
|
case TOGGLE:
|
||||||
|
/* Toggle, toggles the display on/off state */
|
||||||
|
displayOn = !displayOn;
|
||||||
|
display.ssd1306_command(displayOn ? SSD1306_DISPLAYON : SSD1306_DISPLAYOFF);
|
||||||
|
delay(200);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LEFT:
|
||||||
|
/* Left, decrements the page */
|
||||||
|
incrementPage(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RIGHT:
|
||||||
|
/* Right, increments the page */
|
||||||
|
incrementPage(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUPER | TOGGLE:
|
||||||
|
/* Super+Toggle toggles the display contrast */
|
||||||
|
contrast = !contrast;
|
||||||
|
display.ssd1306_command(SSD1306_SETCONTRAST);
|
||||||
|
display.ssd1306_command(contrast ? 255 : 0);
|
||||||
|
delay(200);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUPER | RIGHT:
|
||||||
|
/* Super+Right will lock the calculator */
|
||||||
|
bool abort = false;
|
||||||
|
for (int i = 5; i >= 0; i--) {
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
display.print("Device will be locked\nHold D1 to abort!\nHold D4 to lock NOW\n -> Locking in: ");
|
||||||
|
display.print(i);
|
||||||
|
display.display();
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
/* On left press abort, on right press skip counter */
|
||||||
|
scanButtons();
|
||||||
|
if (currentPress == LEFT) {
|
||||||
|
abort = true;
|
||||||
|
break;
|
||||||
|
} else if (currentPress == RIGHT) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write lock and reset */
|
||||||
|
if (!abort) {
|
||||||
|
EEPROM.write(E_LOCK, 1);
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
case SUPER | LEFT:
|
||||||
|
/* Super+Left resets the index to 0 */
|
||||||
|
currentIndex = 0;
|
||||||
|
displayPage();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wait = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (wait && currentPress != 0) delay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeEEPROM(uint16_t address, char writebyte) {
|
||||||
|
/* Write the given value to EEPROM from desired address */
|
||||||
|
|
||||||
|
Wire.beginTransmission(S_EEPROM_Address);
|
||||||
|
Wire.write((byte)(address >> 8));
|
||||||
|
Wire.write((byte)(address & 0xFF));
|
||||||
|
Wire.write(writebyte);
|
||||||
|
|
||||||
|
Wire.endTransmission();
|
||||||
|
delay(2); // wait to complete the write cycle
|
||||||
|
}
|
||||||
|
|
||||||
|
int readEEPROM(uint16_t address) {
|
||||||
|
/* Read one byte from EEPROM from desired address */
|
||||||
|
|
||||||
|
Wire.beginTransmission(S_EEPROM_Address);
|
||||||
|
Wire.write((byte)(address >> 8));
|
||||||
|
Wire.write((byte)(address & 0xFF));
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.requestFrom(S_EEPROM_Address, (uint8_t)1);
|
||||||
|
return Wire.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearEEPROM() {
|
||||||
|
/* Clearing the entire EEPROM (fill with zeros) */
|
||||||
|
|
||||||
|
Serial.print("!EEPROM CLEAR ");
|
||||||
|
Serial.print((S_EEPROM_Size / 1024) + 1);
|
||||||
|
Serial.println("k\n# '.' = 1k");
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < S_EEPROM_Size; i++) {
|
||||||
|
writeEEPROM(i, 0);
|
||||||
|
|
||||||
|
/* For every 256 bytes, refresh display */
|
||||||
|
if ((i & 0xFF) == 0) {
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
|
||||||
|
display.print("Clearing EEPROM ");
|
||||||
|
display.print((S_EEPROM_Size / 1024) + 1);
|
||||||
|
display.println('k');
|
||||||
|
display.print(String(i / 1024));
|
||||||
|
display.println("KB cleared");
|
||||||
|
display.print((uint8_t)(((float)i / S_EEPROM_Size) * 100));
|
||||||
|
display.print("% done ");
|
||||||
|
display.println(i < S_TOC_SIZE ? "(TOC)" : "(Data)");
|
||||||
|
display.println("Hold D4 to abort");
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
|
||||||
|
/* If RIGHT was pressed, abort */
|
||||||
|
scanButtons();
|
||||||
|
if (currentPress == RIGHT) break;
|
||||||
|
|
||||||
|
/* Print status */
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("\n!EEPROM CLEAR DONE");
|
||||||
|
displayPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayPage() {
|
||||||
|
/* Display page at current index */
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
|
||||||
|
/* Get TOC address and size */
|
||||||
|
uint16_t start = (getPageAddress(currentIndex) & 0x7FFF);
|
||||||
|
uint16_t end = start + getPageSize(currentIndex);
|
||||||
|
|
||||||
|
/* If text mode, just print the characters */
|
||||||
|
if ((getPageAddress(currentIndex) & 0x8000) == 0) {
|
||||||
|
for (int16_t i = start; i < end; i++) {
|
||||||
|
display.print((char)readEEPROM(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* If it is an image, read bytes and put them into a line buffer and print them out */
|
||||||
|
uint8_t buffer[(IMAGEX / 8)];
|
||||||
|
uint8_t y = 0;
|
||||||
|
uint8_t c = 0;
|
||||||
|
|
||||||
|
for (uint16_t i = start; i < end; i++) {
|
||||||
|
/* Fill buffer with values */
|
||||||
|
buffer[c++] = readEEPROM(i);
|
||||||
|
|
||||||
|
if (c >= (IMAGEX / 8)) {
|
||||||
|
/* Draw a 1 line bitmap from the buffer to the S_SCREEN_Address
|
||||||
|
* This draws the image line by line, without needing a big buffer
|
||||||
|
*/
|
||||||
|
display.drawBitmap(0, y++, buffer, IMAGEX - 1, 1, 1);
|
||||||
|
c = 0;
|
||||||
|
|
||||||
|
scanButtons();
|
||||||
|
if ((currentPress & (LEFT | RIGHT)) != 0) {
|
||||||
|
nextPage = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For every 8 lines, print the page */
|
||||||
|
if ((y % 8) == 0) display.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void scanButtons() {
|
||||||
|
/* Performs a scan on the calculator button matrix */
|
||||||
|
|
||||||
|
/* Set the ROW pin to OUTPUT and set it LOW */
|
||||||
|
pinMode(ROW, OUTPUT);
|
||||||
|
digitalWrite(ROW, LOW);
|
||||||
|
|
||||||
|
/* Wait a bit */
|
||||||
|
delay(3);
|
||||||
|
|
||||||
|
currentPress = 0;
|
||||||
|
|
||||||
|
/* Read inputs, if analog read exceeds the threshhold,
|
||||||
|
* OR the pressed button to currentPress
|
||||||
|
*/
|
||||||
|
if (analogRead(D1) < S_THRESHHOLD) currentPress |= LEFT;
|
||||||
|
if (analogRead(D2) < S_THRESHHOLD) currentPress |= SUPER;
|
||||||
|
if (analogRead(D3) < S_THRESHHOLD) currentPress |= TOGGLE;
|
||||||
|
if (analogRead(D4) < S_THRESHHOLD) currentPress |= RIGHT;
|
||||||
|
|
||||||
|
/* Set ROW to INPUT, this set's the pin in tri state mode */
|
||||||
|
pinMode(ROW, INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void incrementPage(bool increment) {
|
||||||
|
/* Increments or decrements the page */
|
||||||
|
|
||||||
|
/* Dont't modify, if index is 0 or 255 or if next TOC entry is empty */
|
||||||
|
if (increment && currentIndex == 255) return;
|
||||||
|
else if (!increment && currentIndex == 0) return;
|
||||||
|
else if (increment && (getPageAddress((currentIndex + 1)) & 0x7FFF) == 0) return;
|
||||||
|
|
||||||
|
currentIndex += (increment ? 1 : -1);
|
||||||
|
|
||||||
|
nextPage = false;
|
||||||
|
displayPage();
|
||||||
|
if (nextPage) incrementPage(increment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printPageData(uint8_t pageIndex) {
|
||||||
|
/* Print the page data at the requested index to serial */
|
||||||
|
|
||||||
|
int i = getPageAddress(pageIndex) & 0x7FFF;
|
||||||
|
int to = i + getPageSize(pageIndex);
|
||||||
|
|
||||||
|
bool graphicsMode = ((getPageAddress(pageIndex) & 0x8000) != 0);
|
||||||
|
|
||||||
|
Serial.print("!DATA ");
|
||||||
|
Serial.println(graphicsMode ? "IMAGE:" : "TEXT:");
|
||||||
|
|
||||||
|
for (; i < to; i++) {
|
||||||
|
uint8_t val = readEEPROM(i);
|
||||||
|
|
||||||
|
if (graphicsMode) {
|
||||||
|
Serial.print(numToHex(val));
|
||||||
|
Serial.print(numToHex(val >> 4));
|
||||||
|
Serial.print(';');
|
||||||
|
} else {
|
||||||
|
Serial.print((char)val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("\n!DONE");
|
||||||
|
}
|
||||||
|
|
||||||
|
void printTOC(int index) {
|
||||||
|
/* Print TOC index information to serial */
|
||||||
|
|
||||||
|
uint16_t addr = getPageAddress(index);
|
||||||
|
uint16_t size = getPageSize(index);
|
||||||
|
|
||||||
|
/* Don't print if address is empty */
|
||||||
|
if (addr != 0) {
|
||||||
|
Serial.print("!TOC INFO: ");
|
||||||
|
Serial.print(index);
|
||||||
|
Serial.print("\tADDR: ");
|
||||||
|
Serial.print((addr & 0x7FFF));
|
||||||
|
Serial.print("\tSIZE: ");
|
||||||
|
Serial.print(size);
|
||||||
|
Serial.print((addr & 0x8000) ? "\tIMAGE" : "\tTEXT");
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char numToHex(uint8_t val) {
|
||||||
|
/* Convert the lower section of a byte to a hex char */
|
||||||
|
|
||||||
|
val &= 0xF;
|
||||||
|
return (val < 0xA) ? ('0' + val) : ('A' + (val - 0xA));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t allocPage(bool image) {
|
||||||
|
/* Allocate new Memory Block returning the allocated Index
|
||||||
|
* Input specifies the allocation size. A Text Entry (image = false)
|
||||||
|
* will allocate 84 bytes, while a Image (image = true) will use 512 bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Get free index */
|
||||||
|
uint8_t newIndex = findNewTOCIndex();
|
||||||
|
uint16_t resultAddress = 0xFFFF;
|
||||||
|
|
||||||
|
/* If the index was 0 (first TOC entry), use the address, after the TOC size
|
||||||
|
* Addresses after the TOC size is the usable data
|
||||||
|
*/
|
||||||
|
|
||||||
|
Serial.println("!TOC ALLOC");
|
||||||
|
if (newIndex == 0) resultAddress = S_TOC_SIZE;
|
||||||
|
else {
|
||||||
|
/* If not, search for a suitable address based of TOC Entries */
|
||||||
|
uint16_t lastAddress = 0;
|
||||||
|
uint16_t end = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < S_TOC_SIZE / 2; i++) {
|
||||||
|
lastAddress = end;
|
||||||
|
uint16_t addrs = getPageAddress(i);
|
||||||
|
end = (addrs & 0x7FFF) + getPageSize(i);
|
||||||
|
|
||||||
|
if (i != 0 && (addrs & 0x7FFF) == 0) {
|
||||||
|
|
||||||
|
/* If we reached end of TOC, break */
|
||||||
|
resultAddress = lastAddress;
|
||||||
|
Serial.println("!TOC FULL");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update TOC index to found address and set the image/text bit */
|
||||||
|
setPageAddress(newIndex, (resultAddress | (image ? 0x8000 : 0)));
|
||||||
|
|
||||||
|
/* Randomizing of new allocated space (optional) */
|
||||||
|
/*
|
||||||
|
uint16_t end = (getPageSize(newIndex) + resultAddress);
|
||||||
|
for (int i = resultAddress; i < end; i++) {
|
||||||
|
if (image) writeEEPROM(i, random(255));
|
||||||
|
else writeEEPROM(i, random(20, 127));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Serial.print("!TOC INDEX ");
|
||||||
|
Serial.print(newIndex);
|
||||||
|
Serial.print(" IS ADDR ");
|
||||||
|
Serial.println(resultAddress);
|
||||||
|
|
||||||
|
return newIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t findNewTOCIndex() {
|
||||||
|
/* Get next free TOC Index */
|
||||||
|
|
||||||
|
Serial.println("!TOC SCAN");
|
||||||
|
|
||||||
|
int foundIndex = 0;
|
||||||
|
for (; foundIndex < S_TOC_SIZE / 2; foundIndex++) {
|
||||||
|
uint16_t addrs = getPageAddress(foundIndex);
|
||||||
|
if (addrs == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("!TOC FOUND INDEX" + String(foundIndex));
|
||||||
|
setPageAddress(foundIndex, 0);
|
||||||
|
|
||||||
|
return foundIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getPageSize(uint8_t pageIndex) {
|
||||||
|
/* Get the TOC page size from TOC index
|
||||||
|
* Here, the most significant bit of the address byte
|
||||||
|
* is used to determine the allocated space.
|
||||||
|
* For text, it's just TEXTX * TEXTY (for 21x4 Text = 84 bytes),
|
||||||
|
* for an image it's (IMAGEX / 8) * IMAGEY, because 1 byte can hold 8
|
||||||
|
* horizontal pixels (for 128x32 Image = 512 bytes)
|
||||||
|
*/
|
||||||
|
|
||||||
|
return ((getPageAddress(pageIndex) & 0x8000) == 0 ? (TEXTX * TEXTY) : ((IMAGEX / 8) * IMAGEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getPageAddress(uint8_t pageIndex) {
|
||||||
|
/* Get the page address from the TOC index */
|
||||||
|
|
||||||
|
uint16_t retAddrs = readEEPROM(pageIndex * 2);
|
||||||
|
retAddrs |= (readEEPROM((pageIndex * 2) + 1) << 8);
|
||||||
|
return retAddrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPageAddress(uint8_t pageIndex, uint16_t address) {
|
||||||
|
/* Write the given Address to the desired TOC Location */
|
||||||
|
|
||||||
|
writeEEPROM(pageIndex * 2, (byte)(address & 0xFF));
|
||||||
|
writeEEPROM((pageIndex * 2) + 1, (byte)(address >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearTOC() {
|
||||||
|
/* Clear table of contents (TOC)
|
||||||
|
* This is a quick erase, deleting just the address entries
|
||||||
|
*/
|
||||||
|
|
||||||
|
Serial.println("!TOC CLEAR");
|
||||||
|
for (int i = 0; i < S_TOC_SIZE; i++) {
|
||||||
|
writeEEPROM(i, 0);
|
||||||
|
}
|
||||||
|
Serial.println("!TOC CLEAR DONE");
|
||||||
|
}
|
||||||
|
|
||||||
|
void printSystemInfo() {
|
||||||
|
/* Print system info as JSON to serial */
|
||||||
|
|
||||||
|
Serial.print("!SYSINFO:{");
|
||||||
|
Serial.print("\"FIRMWARE\":" + String(FIRMWARE));
|
||||||
|
Serial.print(",\"MODEL\":" + String(MODEL));
|
||||||
|
Serial.print(",\"TEXTX\":" + String(TEXTX));
|
||||||
|
Serial.print(",\"TEXTY\":" + String(TEXTY));
|
||||||
|
Serial.print(",\"IMAGEX\":" + String(IMAGEX));
|
||||||
|
Serial.print(",\"IMAGEY\":" + String(IMAGEY));
|
||||||
|
|
||||||
|
Serial.println("}");
|
||||||
|
getSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadSettings() {
|
||||||
|
/* Loads configuration from EEPROM */
|
||||||
|
|
||||||
|
S_EEPROM_Address = EEPROM.read(E_EEPROM_ADDR);
|
||||||
|
S_SCREEN_Address = EEPROM.read(E_SCREEN_ADDR);
|
||||||
|
S_EEPROM_Size = (((uint16_t)EEPROM.read(E_EEPROM_SIZE)) * 1024) - 1;
|
||||||
|
S_TOC_SIZE = ((uint16_t)EEPROM.read(E_TOC_SIZE)) * 64;
|
||||||
|
S_THRESHHOLD = EEPROM.read(E_THRESHHOLD);
|
||||||
|
currentIndex = EEPROM.read(E_PAGE);
|
||||||
|
contrast = (bool)EEPROM.read(E_CONTRAST);
|
||||||
|
locked = (bool)EEPROM.read(E_LOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getSettings() {
|
||||||
|
/* Print settings in JSON format to serial */
|
||||||
|
|
||||||
|
Serial.print("!SETTINGS:{");
|
||||||
|
Serial.print("\"EEPROM_ADDR\":" + String(EEPROM.read(E_EEPROM_ADDR)));
|
||||||
|
Serial.print(",\"SCREEN_ADDR\":" + String(EEPROM.read(E_SCREEN_ADDR)));
|
||||||
|
Serial.print(",\"EEPROM_SIZE\":" + String(EEPROM.read(E_EEPROM_SIZE)));
|
||||||
|
Serial.print(",\"TOC_SIZE\":" + String(EEPROM.read(E_TOC_SIZE)));
|
||||||
|
Serial.print(",\"THRESHHOLD\":" + String(EEPROM.read(E_THRESHHOLD)));
|
||||||
|
Serial.print(",\"PAGE\":" + String(EEPROM.read(E_PAGE)));
|
||||||
|
Serial.print(",\"CONTRAST\":" + String(EEPROM.read(E_CONTRAST)));
|
||||||
|
Serial.print(",\"LOCKED\":" + String(EEPROM.read(E_LOCK)));
|
||||||
|
Serial.println("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetSettings() {
|
||||||
|
/* Restore settings to default values */
|
||||||
|
|
||||||
|
EEPROM.write(E_PAGE, 0);
|
||||||
|
EEPROM.write(E_CONTRAST, 255);
|
||||||
|
EEPROM.write(E_LOCK, 0);
|
||||||
|
EEPROM.write(E_EEPROM_SIZE, 64); // x * 1024 = EEPROM SIZE
|
||||||
|
EEPROM.write(E_TOC_SIZE, 8); // x * 64 = TOCSIZE
|
||||||
|
EEPROM.write(E_EEPROM_ADDR, 0x50);
|
||||||
|
EEPROM.write(E_SCREEN_ADDR, 0x3C);
|
||||||
|
EEPROM.write(E_THRESHHOLD, 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Ein geschlossener Regenschirm ist ebenso elegant wie ein offener hässlich ist */
|
||||||
232
Client/LICENSE
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
“This License” refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
|
||||||
|
|
||||||
|
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
|
||||||
|
|
||||||
|
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
|
||||||
|
|
||||||
|
A “covered work” means either the unmodified Program or a work based on the Program.
|
||||||
|
|
||||||
|
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
|
||||||
|
|
||||||
|
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
|
||||||
|
|
||||||
|
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
|
||||||
|
|
||||||
|
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.
|
||||||
|
|
||||||
|
A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
|
||||||
|
|
||||||
|
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
LS7-Emulator
|
||||||
|
Copyright (C) 2024 0xmac
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
LS7-Emulator Copyright (C) 2024 0xmac
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <https://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
3
Client/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# SSUP
|
||||||
|
|
||||||
|
SSUP is a hardware modified calculator to cheat in math and physics lol
|
||||||
40
Client/assets.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
static const unsigned char PROGMEM LOGO[] = {
|
||||||
|
0x67, 0x74, 0xa5, 0xc1, 0x8c, 0xf0, 0x4c, 0x0f, 0x18, 0xc6, 0x31, 0x9e, 0x21, 0x09, 0x08, 0x08,
|
||||||
|
0x92, 0x24, 0xa5, 0x22, 0x52, 0xa8, 0x52, 0x0a, 0xa5, 0x29, 0x4a, 0x50, 0x21, 0x0a, 0x04, 0x08,
|
||||||
|
0x82, 0x24, 0xa5, 0x22, 0x12, 0xa8, 0x92, 0xaa, 0xa5, 0x09, 0x0a, 0x5c, 0x22, 0xea, 0x72, 0x08,
|
||||||
|
0x82, 0x27, 0xa5, 0xc2, 0x12, 0xa8, 0x92, 0xaa, 0xbd, 0x06, 0x12, 0x42, 0x23, 0x16, 0x8a, 0x08,
|
||||||
|
0xb2, 0x24, 0xa5, 0x22, 0x12, 0xa9, 0x12, 0x4a, 0xa5, 0x09, 0x22, 0x42, 0x21, 0x60, 0x36, 0x04,
|
||||||
|
0x92, 0x24, 0xa5, 0x22, 0x52, 0xa9, 0x12, 0xaa, 0xa5, 0x29, 0x42, 0x52, 0x11, 0x90, 0x42, 0x04,
|
||||||
|
0x67, 0x24, 0x99, 0xc9, 0x8c, 0xaa, 0x0c, 0xaa, 0xa4, 0xc6, 0x79, 0x8c, 0x11, 0x00, 0x02, 0x04,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x84, 0x04, 0x04,
|
||||||
|
0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x04, 0x04,
|
||||||
|
0x00, 0x0e, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0x08, 0x04,
|
||||||
|
0x00, 0xf0, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x23, 0x14, 0x04,
|
||||||
|
0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x26, 0x04,
|
||||||
|
0x0c, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c, 0xc5, 0xc4,
|
||||||
|
0x10, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1b, 0x0c, 0x74,
|
||||||
|
0x30, 0x46, 0x03, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe8, 0x14, 0x8c,
|
||||||
|
0x79, 0x98, 0x20, 0xcc, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x4c, 0x65, 0x02,
|
||||||
|
0x7e, 0x80, 0x00, 0x0b, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x8b, 0x89, 0x01,
|
||||||
|
0x00, 0x80, 0x70, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x88, 0x09, 0x01,
|
||||||
|
0x01, 0x30, 0xf8, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x08, 0x11, 0x01,
|
||||||
|
0x01, 0x78, 0x88, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x08, 0x11, 0x81,
|
||||||
|
0x01, 0x78, 0x88, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x08, 0x21, 0x81,
|
||||||
|
0x01, 0x30, 0x8e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x41, 0x01,
|
||||||
|
0x01, 0x00, 0x79, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x04, 0x81, 0x02,
|
||||||
|
0x00, 0x80, 0x08, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x03, 0x02, 0x02,
|
||||||
|
0x00, 0x80, 0x04, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x02,
|
||||||
|
0x00, 0xc0, 0x02, 0x38, 0x00, 0x19, 0xcc, 0xa2, 0xaa, 0xee, 0xe7, 0x00, 0x14, 0x00, 0x02, 0x04,
|
||||||
|
0x00, 0x80, 0xfa, 0x28, 0x00, 0x24, 0x92, 0xa2, 0xaa, 0x84, 0x94, 0x80, 0x14, 0x00, 0x04, 0x04,
|
||||||
|
0x00, 0x80, 0x71, 0x08, 0x00, 0x20, 0x92, 0xa2, 0xaa, 0x84, 0x94, 0x80, 0x14, 0x00, 0x04, 0x04,
|
||||||
|
0x00, 0x80, 0x01, 0x08, 0x00, 0x18, 0x9e, 0x42, 0xae, 0xe4, 0xe4, 0x80, 0x14, 0x00, 0x04, 0x08,
|
||||||
|
0x01, 0x00, 0x00, 0x04, 0x00, 0x04, 0x92, 0x42, 0xaa, 0x84, 0xa4, 0x80, 0x22, 0x00, 0x04, 0x08,
|
||||||
|
0x01, 0x00, 0x00, 0x04, 0x00, 0x24, 0x92, 0x41, 0x4a, 0x84, 0x94, 0x80, 0x22, 0x00, 0x08, 0x10,
|
||||||
|
0x01, 0x00, 0x00, 0x04, 0x00, 0x18, 0x92, 0x41, 0x4a, 0xee, 0x97, 0x00, 0x21, 0x00, 0x08, 0x10
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char PROGMEM WHAT[] = {
|
||||||
|
0x83, 0x30, 0x86, 0xc0, 0x78, 0x00, 0x90, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00,
|
||||||
|
0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x80, 0x12, 0x90, 0x02, 0x81, 0x84, 0x43, 0x78, 0x3d
|
||||||
|
};
|
||||||
91
Editor/Makefile
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
.ONESHELL:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Cross Platform Makefile
|
||||||
|
# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X
|
||||||
|
#
|
||||||
|
# You will need SDL2 (http://www.libsdl.org):
|
||||||
|
# Linux:
|
||||||
|
# apt-get install libsdl2-dev
|
||||||
|
# Mac OS X:
|
||||||
|
# brew install sdl2
|
||||||
|
# MSYS2:
|
||||||
|
# pacman -S mingw-w64-i686-SDL2
|
||||||
|
#
|
||||||
|
|
||||||
|
#CXX = g++
|
||||||
|
#CXX = clang++
|
||||||
|
|
||||||
|
EXE = spedit
|
||||||
|
IMGUI_DIR = imgui
|
||||||
|
SOURCES = main.cpp serialib.cpp
|
||||||
|
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
|
||||||
|
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_sdlrenderer2.cpp
|
||||||
|
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
|
||||||
|
CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -ljson11
|
||||||
|
CXXFLAGS += -g -Wall -Wformat
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
##---------------------------------------------------------------------
|
||||||
|
## BUILD FLAGS PER PLATFORM
|
||||||
|
##---------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(UNAME_S), Linux) #LINUX
|
||||||
|
ECHO_MESSAGE = "Linux"
|
||||||
|
LIBS += -lGL -ldl `sdl2-config --libs`
|
||||||
|
|
||||||
|
CXXFLAGS += `sdl2-config --cflags`
|
||||||
|
CFLAGS = $(CXXFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME_S), Darwin) #APPLE
|
||||||
|
ECHO_MESSAGE = "Mac OS X"
|
||||||
|
LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl2-config --libs`
|
||||||
|
LIBS += -L/usr/local/lib -L/opt/local/lib
|
||||||
|
|
||||||
|
CXXFLAGS += `sdl2-config --cflags`
|
||||||
|
CXXFLAGS += -I/usr/local/include -I/opt/local/include
|
||||||
|
CFLAGS = $(CXXFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OS), Windows_NT)
|
||||||
|
ECHO_MESSAGE = "MinGW"
|
||||||
|
LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl2`
|
||||||
|
|
||||||
|
CXXFLAGS += `pkg-config --cflags sdl2`
|
||||||
|
CFLAGS = $(CXXFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
##---------------------------------------------------------------------
|
||||||
|
## BUILD RULES
|
||||||
|
##---------------------------------------------------------------------
|
||||||
|
|
||||||
|
%.o:%.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o:$(IMGUI_DIR)/%.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o:$(IMGUI_DIR)/backends/%.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
all: $(EXE)
|
||||||
|
@echo Build complete for $(ECHO_MESSAGE)
|
||||||
|
rm bin -rf
|
||||||
|
mkdir bin
|
||||||
|
mv $(EXE) bin
|
||||||
|
strip bin/$(EXE)
|
||||||
|
|
||||||
|
$(EXE): $(OBJS)
|
||||||
|
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(EXE) $(OBJS)
|
||||||
|
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p $(PREFIX)/bin
|
||||||
|
install bin/$(EXE) $(PREFIX)/bin/$(EXE)
|
||||||
|
cp bin/$(EXE) /usr/bin/$(EXE)
|
||||||
70
Editor/actions.cpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
|
#include "serialib.h"
|
||||||
|
#include "ssup.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void renderActions(){
|
||||||
|
|
||||||
|
static string deleteString;
|
||||||
|
ImVec2 parentWidth = ImVec2(ImGui::GetWindowWidth() - 16, 0);
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(!connected);
|
||||||
|
|
||||||
|
ImGui::SeparatorText(appLang == LANG::ENGLISH ? "Erasing" : "Löschen");
|
||||||
|
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Erase TOC (fastest)" : "TOC löschen (schnell)", parentWidth)) {
|
||||||
|
deleteString = "f";
|
||||||
|
ImGui::OpenPopup("Erase?");
|
||||||
|
}
|
||||||
|
ImGui::SetItemTooltip("Erase Filesystem structure -> fast -> could lead to \"ghost content\"");
|
||||||
|
|
||||||
|
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Erase everything (slowest)" : "Alles löschen (langsam)", parentWidth)) {
|
||||||
|
deleteString = "c";
|
||||||
|
ImGui::OpenPopup("Erase?");
|
||||||
|
}
|
||||||
|
ImGui::SetItemTooltip("Overwrite the storage -> slower -> safer");
|
||||||
|
|
||||||
|
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||||
|
ImGui::SetNextWindowPos(center, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||||
|
if (ImGui::BeginPopupModal("Erase?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Erasing will result in permanent data loss!" : "Löschen kann nicht rückgängig gemacht werden!");
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
if (ImGui::Button("OK", ImVec2(120, 0))) {
|
||||||
|
serial.writeString(deleteString.c_str());
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Cancel" : "Abbrechen", ImVec2(120, 0))) ImGui::CloseCurrentPopup();
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SeparatorText("");
|
||||||
|
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Restore Settings" : "Einstellungen wiederherstellen", parentWidth)) serial.writeString("rg");
|
||||||
|
ImGui::SetItemTooltip("Set all the settings back to their original value.\nThis operation does not erase content.");
|
||||||
|
|
||||||
|
ImGui::SeparatorText("");
|
||||||
|
|
||||||
|
ImGui::Button("Download SSUP Content", parentWidth);
|
||||||
|
ImGui::SetItemTooltip("Download the content from SSUP to a JSON file.\nOne can reproduce and edit it's content after.");
|
||||||
|
|
||||||
|
ImGui::Button("Upload to SSUP", parentWidth);
|
||||||
|
ImGui::SetItemTooltip("Upload the content in this program to SSUP. This could take a couple of minutes");
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
280
Editor/connector.cpp
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
#include <SDL2/SDL_mouse.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <ctime>
|
||||||
|
#include <string>
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
#include <json11.hpp>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "serialib.h"
|
||||||
|
|
||||||
|
#include "ssup.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace json11;
|
||||||
|
|
||||||
|
string cutJSON(string input){
|
||||||
|
int start = input.find_first_of('{');
|
||||||
|
int end = input.find_last_of('}');
|
||||||
|
|
||||||
|
return input.substr(start, (end - start) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void restartDevice(serialib &serial){
|
||||||
|
serial.clearDTR();
|
||||||
|
SDL_Delay(10);
|
||||||
|
serial.setDTR();
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderConnectModule(){
|
||||||
|
|
||||||
|
if (ImGui::BeginTabItem(appLang == LANG::ENGLISH ? "Connect" : "Verbindung", NULL)){
|
||||||
|
|
||||||
|
static bool firstScan = true;
|
||||||
|
static bool scan = true;
|
||||||
|
|
||||||
|
static bool wait = false;
|
||||||
|
static vector<string> device;
|
||||||
|
static int selectedDevice;
|
||||||
|
static char error = 1;
|
||||||
|
|
||||||
|
static string gotBuffer = "";
|
||||||
|
static string fetchLine = "";
|
||||||
|
static string currentLine = "";
|
||||||
|
|
||||||
|
bool newContent = false;
|
||||||
|
bool newLine = false;
|
||||||
|
|
||||||
|
const string combo_preview_value = (device.size() == 0 ? (appLang == LANG::ENGLISH ? "-- No ports found --" : "-- Keine Ports gefunden --") : device[selectedDevice]);
|
||||||
|
if (device.size() == 0) ImGui::PushStyleColor(ImGuiCol_Text, 0xFF555555);
|
||||||
|
|
||||||
|
if (ImGui::BeginCombo("COM Port", combo_preview_value.c_str())) {
|
||||||
|
for (int i = 0; i < (int)device.size(); i++) {
|
||||||
|
const bool is_selected = selectedDevice == i;
|
||||||
|
|
||||||
|
if (ImGui::Selectable(device[i].c_str(), is_selected)) selectedDevice = i;
|
||||||
|
if (is_selected) ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
static char mbuffer[64] = {0};
|
||||||
|
bool mtrue = ImGui::InputText("Manually specify port###MANPORT", mbuffer, sizeof(mbuffer), ImGuiInputTextFlags_EnterReturnsTrue);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Ok###MANPORTBTN") || mtrue){
|
||||||
|
if (strlen(mbuffer) > 0) {
|
||||||
|
device.clear();
|
||||||
|
device.push_back(mbuffer);
|
||||||
|
scan = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device.size() == 0) ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Rescan Ports") || ((time(NULL) % 32 == 0 || firstScan) && scan)) {
|
||||||
|
device.clear();
|
||||||
|
device.push_back("/dev/ttyUSB0");
|
||||||
|
}
|
||||||
|
|
||||||
|
firstScan = false;
|
||||||
|
|
||||||
|
if (!connected && ImGui::Button(appLang == LANG::ENGLISH ? "Connect" : "Verbinden")){
|
||||||
|
serial.closeDevice();
|
||||||
|
error = serial.openDevice(device[selectedDevice].c_str(), 9600);
|
||||||
|
restartDevice(serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected && ImGui::Button(appLang == LANG::ENGLISH ? "Disconnect" : "Trennen")){
|
||||||
|
serial.closeDevice();
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::BeginDisabled(!connected);
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Restart SSUP" : "SSUP neustarten")){
|
||||||
|
restartDevice(serial);
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (error == 1){
|
||||||
|
if (serial.isDeviceOpen()){
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, 0xFF00AA00);
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Connected" : "Verbunden");
|
||||||
|
connected = true;
|
||||||
|
|
||||||
|
config.eeprom_size = 16;
|
||||||
|
config.toc_size = 512;
|
||||||
|
} else {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, 0xFF0000FF);
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Not connected" : "Nicht verbunden");
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, 0xFF0000FF);
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Error opening %s" : "Fehler beim öffnen von %s", device[selectedDevice].c_str());
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (serial.available()){
|
||||||
|
|
||||||
|
while (serial.available()){
|
||||||
|
static uint8_t got;
|
||||||
|
serial.readBytes(&got, 1);
|
||||||
|
|
||||||
|
if (got == 0xFA) wait = true;
|
||||||
|
else if (got == 0xFB) wait = false;
|
||||||
|
else {
|
||||||
|
gotBuffer.push_back((char)got);
|
||||||
|
newContent = true;
|
||||||
|
|
||||||
|
newLine = false;
|
||||||
|
if ((char)got == '\n' || (char)got == 0){
|
||||||
|
currentLine = fetchLine;
|
||||||
|
fetchLine = "";
|
||||||
|
newLine = true;
|
||||||
|
break;
|
||||||
|
} else fetchLine.push_back((char)got);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jsonError = false;
|
||||||
|
static int fetchedSettings = 0;
|
||||||
|
static string jsonErrorString;
|
||||||
|
|
||||||
|
if (newLine){
|
||||||
|
if (currentLine == "SSUP") serial.writeString("g");
|
||||||
|
else if (currentLine.find("!SYSINFO:") != string::npos){
|
||||||
|
string jsonRawData = cutJSON(currentLine);
|
||||||
|
|
||||||
|
jsonErrorString.clear();
|
||||||
|
Json jsonData = Json::parse(jsonRawData, jsonErrorString);
|
||||||
|
|
||||||
|
if (jsonErrorString.length() > 0) jsonError = true;
|
||||||
|
else {
|
||||||
|
config.firmware = jsonData["FIRMWARE"].int_value();
|
||||||
|
config.model = jsonData["MODEL"].int_value();
|
||||||
|
config.textx = jsonData["TEXTX"].int_value();
|
||||||
|
config.texty = jsonData["TEXTY"].int_value();
|
||||||
|
config.imagex = jsonData["IMAGEX"].int_value();
|
||||||
|
config.imagey = jsonData["IMAGEY"].int_value();
|
||||||
|
|
||||||
|
jsonError = false;
|
||||||
|
fetchedSettings++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (currentLine.find("!SETTINGS:") != string::npos){
|
||||||
|
string jsonRawData = cutJSON(currentLine);
|
||||||
|
|
||||||
|
jsonErrorString.clear();
|
||||||
|
Json jsonData = Json::parse(jsonRawData, jsonErrorString);
|
||||||
|
|
||||||
|
if (jsonErrorString.length() > 0) jsonError = true;
|
||||||
|
else {
|
||||||
|
config.eeprom_address = jsonData["EEPROM_ADDR"].int_value();
|
||||||
|
config.eeprom_size = jsonData["EEPROM_SIZE"].int_value();
|
||||||
|
config.screen_address = jsonData["SCREEN_ADDR"].int_value();
|
||||||
|
config.toc_size = jsonData["TOC_SIZE"].int_value();
|
||||||
|
config.threshhold = jsonData["THRESHHOLD"].int_value();
|
||||||
|
//config.= jsonData["PAGE"].int_value();
|
||||||
|
config.contrast = jsonData["CONTRAST"].int_value();
|
||||||
|
config.locked = (jsonData["LOCKED"].int_value() == 1);
|
||||||
|
|
||||||
|
jsonError = false;
|
||||||
|
fetchedSettings++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected){
|
||||||
|
if (ImGui::CollapsingHeader("SSUP Info:", ImGuiTreeNodeFlags_DefaultOpen)){
|
||||||
|
if (jsonError){
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, 0xFFAAAAAA);
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Error while parsing device JSON!\n%s" : "Fehler beim interpretieren des JSON!\n%s", jsonErrorString.c_str());
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SmallButton("?###LOCKED"); ImGui::SameLine();
|
||||||
|
ImGui::SetItemTooltip(appLang == LANG::ENGLISH ?
|
||||||
|
"SSUP locked state. In case of emergency one can lock the device.\nThat means it won't show anything until it is unlocked right here.\nThe calculator stays functional troughout.\nHow you lock SSUP is model specific. Please refer to the manual or to the help tab" :
|
||||||
|
"SSUP Sperrstatus. Im Notfall kann man den Spicker sperren.\nDas bedeutet, dass der Spicker nichts anzeigen wird und nicht bedienbar ist, solange er hier nicht ensperrt wurde.\nDer Taschenrechner bleibt dabei funktionstüchtig.\nWie man den Spicker sperrt ist modellspezifisch und steht im Handbuch und im 'Hilfe' Tab.");
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Locked:" : "Gesperrt:"); ImGui::SameLine();
|
||||||
|
if (config.locked){
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, 0xFF0000FF);
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Yes" : "Ja");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::SmallButton(appLang == LANG::ENGLISH ? "Unlock" : "Entsperren")) {
|
||||||
|
serial.writeString("ug");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, 0xFF00AA00);
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "No" : "Nein");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fetchedSettings < 1) ImGui::Text(appLang == LANG::ENGLISH ? "Fetching..." : "Verarbeiten...");
|
||||||
|
else {
|
||||||
|
ImGui::Text("Firmware: %d", config.firmware);
|
||||||
|
ImGui::Text("Model: %d > %s", config.model, modelLookup[config.model - 1].c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::CollapsingHeader("Nerd Info:")){
|
||||||
|
if (fetchedSettings < 2) ImGui::Text("Fetching...");
|
||||||
|
else {
|
||||||
|
ImGui::Text("Text Size: %dx%d", config.textx, config.texty);
|
||||||
|
ImGui::Text("Image Size: %dx%d", config.imagex, config.imagey);
|
||||||
|
ImGui::Text("EEPROM Size: %d Kilobytes", config.eeprom_size);
|
||||||
|
ImGui::Text("EEPROM Address: %d", config.eeprom_address);
|
||||||
|
ImGui::Text("Screen Address: %d", config.screen_address);
|
||||||
|
ImGui::Text("TOC Size: %d Bytes", config.toc_size);
|
||||||
|
ImGui::Text("Threshhold: %d", config.threshhold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, 0xFFAAAAAA);
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Please connect SSUP" : "Bitte SSUP verbinden");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::CollapsingHeader("Log:", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
ImGui::PushItemWidth(ImGui::GetWindowWidth()-20);
|
||||||
|
|
||||||
|
ImGui::BeginChild(ImGui::GetID("###LOGFRAME"), ImVec2(0, 150), ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Borders);
|
||||||
|
ImGui::Text(gotBuffer.c_str());
|
||||||
|
if (newContent) ImGui::SetScrollHereY(0.999f);
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(!connected);
|
||||||
|
static char commandBuffer[512];
|
||||||
|
bool sendCommand = ImGui::InputText(appLang == LANG::ENGLISH ? "Send###commandText" : "Senden###commandText", commandBuffer, sizeof(commandBuffer),
|
||||||
|
ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_ElideLeft);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(">>") || sendCommand) {
|
||||||
|
serial.writeString(commandBuffer);
|
||||||
|
commandBuffer[0] = 0;
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Clear Log" : "Log löschen")) gotBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
//ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
125
Editor/editor.cpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "ssup.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
void renderPageEditor(){
|
||||||
|
//static char buffer[4][22];
|
||||||
|
static uint8_t drawBuffer[32][16];
|
||||||
|
|
||||||
|
static char label[64];
|
||||||
|
static bool drawMode = false;
|
||||||
|
|
||||||
|
//::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||||
|
|
||||||
|
//ImGui::Begin("Page Editor", NULL,
|
||||||
|
// ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | (drawMode ? ImGuiWindowFlags_NoMove : 0));
|
||||||
|
|
||||||
|
if (ImGui::BeginTabItem(appLang == LANG::ENGLISH ? "Page Editor" : "Seiten Editor")){
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(currentPage <= 0);
|
||||||
|
if (ImGui::ArrowButton("###PREVPAGE", ImGuiDir_Left)) currentPage--;
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Page %d" : "Seite %d", currentPage);
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(currentPage >= (int)pages.size() - 1);
|
||||||
|
if (ImGui::ArrowButton("###NEXTPAGE", ImGuiDir_Right)) currentPage++;
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
if (pages.size() == 0){
|
||||||
|
ImGui::SeparatorText("###emptyText");
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, 0xFF2222FF);
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ?
|
||||||
|
"Empty page table!\nPlease add a text or image page to edit it here.\nIf you're stuck, read the guide:" :
|
||||||
|
"Keine Seiten!\nBitte füge Text oder Bild hinzu um diese hier zu bearbeiten\nWenn du bilfe brauchst, ließ die Anleitung:");
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::TextLinkOpenURL(appLang == LANG::ENGLISH ? "here" : "hier", "https://weingardt.dev/ssup");
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (pages[currentPage]->type == PAGETYPE::TEXT){
|
||||||
|
char** buffer = (char**)pages[currentPage]->data;
|
||||||
|
bool focus = false;
|
||||||
|
|
||||||
|
sprintf(label, "%dx%d Text", config.textx, config.texty);
|
||||||
|
ImGui::SeparatorText(label);
|
||||||
|
|
||||||
|
ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 1);
|
||||||
|
for (int i = 0; i < config.texty; i++){
|
||||||
|
int length = config.textx - (int)strlen(buffer[i]);
|
||||||
|
sprintf(label, "###TEXTEDIT%d", i);
|
||||||
|
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
for (int j = 0; j < (int)strlen(buffer[i]); j++) if (!isascii(buffer[i][j])) error = true;
|
||||||
|
|
||||||
|
if (error) ImGui::PushStyleColor(ImGuiCol_FrameBg, 0xFF0000FF);
|
||||||
|
ImGui::PushItemFlag(ImGuiTabItemFlags_Leading, focus);
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(ImGui::CalcTextSize("a").x * (config.textx + 1));
|
||||||
|
if (ImGui::InputText(label, buffer[i], config.textx + 1, ImGuiInputTextFlags_EnterReturnsTrue)) focus = true;
|
||||||
|
|
||||||
|
ImGui::PopItemFlag();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Illegal Character!" : "Ungültiger Buchstabe!");
|
||||||
|
} else ImGui::Text(appLang == LANG::ENGLISH ? "%d char%s left" : "%d Buchstabe%s übrig", length, length == 1 ? "" : (appLang == LANG::ENGLISH ? "s" : "n"));
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
drawMode = false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// REWORK!
|
||||||
|
sprintf(label, "%dx%d %s", config.imagex, config.imagey, appLang == LANG::ENGLISH ? "Image" : "Bild");
|
||||||
|
ImGui::SeparatorText(label);
|
||||||
|
const int SIZE = 4;
|
||||||
|
|
||||||
|
ImVec2 cursor = ImGui::GetCursorScreenPos();
|
||||||
|
ImVec2 size = ImVec2(128*SIZE, 32*SIZE);
|
||||||
|
ImVec2 mouse = ImGui::GetMousePos();
|
||||||
|
|
||||||
|
ImGui::Dummy(size);
|
||||||
|
ImDrawList* list = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
|
list->AddRectFilled(cursor, ImVec2(size.x + cursor.x, size.y + cursor.y), 0xFFFFFFFF);
|
||||||
|
list->AddRect(cursor, ImVec2(size.x + cursor.x, size.y + cursor.y), ImGui::GetColorU32(ImGui::GetStyleColorVec4(ImGuiCol_Border)));
|
||||||
|
|
||||||
|
for (int y = 0; y < 32; y++){
|
||||||
|
for (int x = 0; x < 128; x++){
|
||||||
|
|
||||||
|
if (((drawBuffer[y][x / 16] >> (x & 0b111)) & 1) == 1){
|
||||||
|
list->AddRectFilled(ImVec2(cursor.x + (x * SIZE), cursor.y + (y * SIZE)),
|
||||||
|
ImVec2(cursor.x + (x * SIZE) + SIZE, cursor.y + (y * SIZE) + SIZE), 0xFF000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 mousePreview = ImVec2((int)((((int)mouse.x) / SIZE) * SIZE), (int)((((int)mouse.y) / 4) * 4));
|
||||||
|
if (mousePreview.x > cursor.x && mousePreview.x < size.x + cursor.x &&
|
||||||
|
mousePreview.y > cursor.y && mousePreview.y < size.y + cursor.y){
|
||||||
|
|
||||||
|
list->AddRectFilled(mousePreview, ImVec2(mousePreview.x + SIZE, mousePreview.y + SIZE) , 0x55000000);
|
||||||
|
//SDL_ShowCursor(false);
|
||||||
|
drawMode = true;
|
||||||
|
} else {
|
||||||
|
//SDL_ShowCursor(true);
|
||||||
|
drawMode = false;
|
||||||
|
}
|
||||||
|
//list->PushClipRect(cursor, ImVec2(size.x + cursor.x, size.y + cursor.y), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
//ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
17
Editor/help.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "ssup.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void renderHelpMenu(){
|
||||||
|
if (ImGui::BeginTabItem(appLang == LANG::ENGLISH ? "Help" : "Hilfe")){
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Editor/imconfig.h
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
imgui/imconfig.h
|
||||||
1
Editor/imgui.h
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
imgui/imgui.h
|
||||||
860
Editor/imgui/backends/imgui_impl_sdl2.cpp
Normal file
@@ -0,0 +1,860 @@
|
|||||||
|
// dear imgui: Platform Backend for SDL2
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||||
|
// (Prefer SDL 2.0.5+ for full feature support.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
|
||||||
|
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||||
|
// [X] Platform: Gamepad support.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561)
|
||||||
|
// 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set.
|
||||||
|
// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468)
|
||||||
|
// 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650)
|
||||||
|
// 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode.
|
||||||
|
// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
|
||||||
|
// 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler.
|
||||||
|
// 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array.
|
||||||
|
// 2024-10-24: Emscripten: from SDL 2.30.9, SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f.
|
||||||
|
// 2024-09-09: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190)
|
||||||
|
// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
|
||||||
|
// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
|
||||||
|
// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
|
||||||
|
// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn
|
||||||
|
// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn
|
||||||
|
// 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*.
|
||||||
|
// 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853)
|
||||||
|
// 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions.
|
||||||
|
// 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library.
|
||||||
|
// 2024-02-14: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadMode().
|
||||||
|
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
|
||||||
|
// 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306)
|
||||||
|
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702)
|
||||||
|
// 2023-02-23: Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. (#6189, #6114, #3644)
|
||||||
|
// 2023-02-07: Implement IME handler (io.SetPlatformImeDataFn will call SDL_SetTextInputRect()/SDL_StartTextInput()).
|
||||||
|
// 2023-02-07: *BREAKING CHANGE* Renamed this backend file from imgui_impl_sdl.cpp/.h to imgui_impl_sdl2.cpp/.h in prevision for the future release of SDL3.
|
||||||
|
// 2023-02-02: Avoid calling SDL_SetCursor() when cursor has not changed, as the function is surprisingly costly on Mac with latest SDL (may be fixed in next SDL version).
|
||||||
|
// 2023-02-02: Added support for SDL 2.0.18+ preciseX/preciseY mouse wheel data for smooth scrolling + Scaling X value on Emscripten (bug?). (#4019, #6096)
|
||||||
|
// 2023-02-02: Removed SDL_MOUSEWHEEL value clamping, as values seem correct in latest Emscripten. (#4019)
|
||||||
|
// 2023-02-01: Flipping SDL_MOUSEWHEEL 'wheel.x' value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463)
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2022-09-26: Inputs: Disable SDL 2.0.22 new "auto capture" (SDL_HINT_MOUSE_AUTO_CAPTURE) which prevents drag and drop across windows for multi-viewport support + don't capture when drag and dropping. (#5710)
|
||||||
|
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
|
||||||
|
// 2022-03-22: Inputs: Fix mouse position issues when dragging outside of boundaries. SDL_CaptureMouse() erroneously still gives out LEAVE events when hovering OS decorations.
|
||||||
|
// 2022-03-22: Inputs: Added support for extra mouse buttons (SDL_BUTTON_X1/SDL_BUTTON_X2).
|
||||||
|
// 2022-02-04: Added SDL_Renderer* parameter to ImGui_ImplSDL2_InitForSDLRenderer(), so we can use SDL_GetRendererOutputSize() instead of SDL_GL_GetDrawableSize() when bound to a SDL_Renderer.
|
||||||
|
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
|
||||||
|
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
|
||||||
|
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
|
||||||
|
// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
|
||||||
|
// 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
|
||||||
|
// 2022-01-12: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
|
||||||
|
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||||
|
// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
|
||||||
|
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
|
||||||
|
// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
|
||||||
|
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
|
||||||
|
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
|
||||||
|
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
|
||||||
|
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||||
|
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||||
|
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||||
|
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||||
|
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
|
||||||
|
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||||
|
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
|
||||||
|
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||||
|
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||||
|
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
|
||||||
|
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
|
||||||
|
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
|
||||||
|
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||||
|
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
|
||||||
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||||
|
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
|
||||||
|
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
|
||||||
|
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||||
|
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
|
||||||
|
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||||
|
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||||
|
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui_impl_sdl2.h"
|
||||||
|
|
||||||
|
// Clang warnings with -Weverything
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SDL
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_syswm.h>
|
||||||
|
#include <stdio.h> // for snprintf()
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten/em_js.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
|
||||||
|
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
|
||||||
|
#else
|
||||||
|
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
|
||||||
|
#endif
|
||||||
|
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
|
||||||
|
#define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14)
|
||||||
|
#if SDL_HAS_VULKAN
|
||||||
|
#include <SDL_vulkan.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SDL Data
|
||||||
|
struct ImGui_ImplSDL2_Data
|
||||||
|
{
|
||||||
|
SDL_Window* Window;
|
||||||
|
Uint32 WindowID;
|
||||||
|
SDL_Renderer* Renderer;
|
||||||
|
Uint64 Time;
|
||||||
|
char* ClipboardTextData;
|
||||||
|
char BackendPlatformName[48];
|
||||||
|
|
||||||
|
// Mouse handling
|
||||||
|
Uint32 MouseWindowID;
|
||||||
|
int MouseButtonsDown;
|
||||||
|
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||||
|
SDL_Cursor* MouseLastCursor;
|
||||||
|
int MouseLastLeaveFrame;
|
||||||
|
bool MouseCanUseGlobalState;
|
||||||
|
bool MouseCanUseCapture;
|
||||||
|
|
||||||
|
// Gamepad handling
|
||||||
|
ImVector<SDL_GameController*> Gamepads;
|
||||||
|
ImGui_ImplSDL2_GamepadMode GamepadMode;
|
||||||
|
bool WantUpdateGamepadsList;
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||||
|
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
||||||
|
static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*)
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
if (bd->ClipboardTextData)
|
||||||
|
SDL_free(bd->ClipboardTextData);
|
||||||
|
bd->ClipboardTextData = SDL_GetClipboardText();
|
||||||
|
return bd->ClipboardTextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_SetClipboardText(ImGuiContext*, const char* text)
|
||||||
|
{
|
||||||
|
SDL_SetClipboardText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow().
|
||||||
|
static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData* data)
|
||||||
|
{
|
||||||
|
if (data->WantVisible)
|
||||||
|
{
|
||||||
|
SDL_Rect r;
|
||||||
|
r.x = (int)data->InputPos.x;
|
||||||
|
r.y = (int)data->InputPos.y;
|
||||||
|
r.w = 1;
|
||||||
|
r.h = (int)data->InputLineHeight;
|
||||||
|
SDL_SetTextInputRect(&r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not static to allow third-party code to use that if they want to (but undocumented)
|
||||||
|
ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode);
|
||||||
|
ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode)
|
||||||
|
{
|
||||||
|
switch (keycode)
|
||||||
|
{
|
||||||
|
case SDLK_TAB: return ImGuiKey_Tab;
|
||||||
|
case SDLK_LEFT: return ImGuiKey_LeftArrow;
|
||||||
|
case SDLK_RIGHT: return ImGuiKey_RightArrow;
|
||||||
|
case SDLK_UP: return ImGuiKey_UpArrow;
|
||||||
|
case SDLK_DOWN: return ImGuiKey_DownArrow;
|
||||||
|
case SDLK_PAGEUP: return ImGuiKey_PageUp;
|
||||||
|
case SDLK_PAGEDOWN: return ImGuiKey_PageDown;
|
||||||
|
case SDLK_HOME: return ImGuiKey_Home;
|
||||||
|
case SDLK_END: return ImGuiKey_End;
|
||||||
|
case SDLK_INSERT: return ImGuiKey_Insert;
|
||||||
|
case SDLK_DELETE: return ImGuiKey_Delete;
|
||||||
|
case SDLK_BACKSPACE: return ImGuiKey_Backspace;
|
||||||
|
case SDLK_SPACE: return ImGuiKey_Space;
|
||||||
|
case SDLK_RETURN: return ImGuiKey_Enter;
|
||||||
|
case SDLK_ESCAPE: return ImGuiKey_Escape;
|
||||||
|
//case SDLK_QUOTE: return ImGuiKey_Apostrophe;
|
||||||
|
case SDLK_COMMA: return ImGuiKey_Comma;
|
||||||
|
//case SDLK_MINUS: return ImGuiKey_Minus;
|
||||||
|
case SDLK_PERIOD: return ImGuiKey_Period;
|
||||||
|
//case SDLK_SLASH: return ImGuiKey_Slash;
|
||||||
|
case SDLK_SEMICOLON: return ImGuiKey_Semicolon;
|
||||||
|
//case SDLK_EQUALS: return ImGuiKey_Equal;
|
||||||
|
//case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket;
|
||||||
|
//case SDLK_BACKSLASH: return ImGuiKey_Backslash;
|
||||||
|
//case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket;
|
||||||
|
//case SDLK_BACKQUOTE: return ImGuiKey_GraveAccent;
|
||||||
|
case SDLK_CAPSLOCK: return ImGuiKey_CapsLock;
|
||||||
|
case SDLK_SCROLLLOCK: return ImGuiKey_ScrollLock;
|
||||||
|
case SDLK_NUMLOCKCLEAR: return ImGuiKey_NumLock;
|
||||||
|
case SDLK_PRINTSCREEN: return ImGuiKey_PrintScreen;
|
||||||
|
case SDLK_PAUSE: return ImGuiKey_Pause;
|
||||||
|
case SDLK_KP_0: return ImGuiKey_Keypad0;
|
||||||
|
case SDLK_KP_1: return ImGuiKey_Keypad1;
|
||||||
|
case SDLK_KP_2: return ImGuiKey_Keypad2;
|
||||||
|
case SDLK_KP_3: return ImGuiKey_Keypad3;
|
||||||
|
case SDLK_KP_4: return ImGuiKey_Keypad4;
|
||||||
|
case SDLK_KP_5: return ImGuiKey_Keypad5;
|
||||||
|
case SDLK_KP_6: return ImGuiKey_Keypad6;
|
||||||
|
case SDLK_KP_7: return ImGuiKey_Keypad7;
|
||||||
|
case SDLK_KP_8: return ImGuiKey_Keypad8;
|
||||||
|
case SDLK_KP_9: return ImGuiKey_Keypad9;
|
||||||
|
case SDLK_KP_PERIOD: return ImGuiKey_KeypadDecimal;
|
||||||
|
case SDLK_KP_DIVIDE: return ImGuiKey_KeypadDivide;
|
||||||
|
case SDLK_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
|
||||||
|
case SDLK_KP_MINUS: return ImGuiKey_KeypadSubtract;
|
||||||
|
case SDLK_KP_PLUS: return ImGuiKey_KeypadAdd;
|
||||||
|
case SDLK_KP_ENTER: return ImGuiKey_KeypadEnter;
|
||||||
|
case SDLK_KP_EQUALS: return ImGuiKey_KeypadEqual;
|
||||||
|
case SDLK_LCTRL: return ImGuiKey_LeftCtrl;
|
||||||
|
case SDLK_LSHIFT: return ImGuiKey_LeftShift;
|
||||||
|
case SDLK_LALT: return ImGuiKey_LeftAlt;
|
||||||
|
case SDLK_LGUI: return ImGuiKey_LeftSuper;
|
||||||
|
case SDLK_RCTRL: return ImGuiKey_RightCtrl;
|
||||||
|
case SDLK_RSHIFT: return ImGuiKey_RightShift;
|
||||||
|
case SDLK_RALT: return ImGuiKey_RightAlt;
|
||||||
|
case SDLK_RGUI: return ImGuiKey_RightSuper;
|
||||||
|
case SDLK_APPLICATION: return ImGuiKey_Menu;
|
||||||
|
case SDLK_0: return ImGuiKey_0;
|
||||||
|
case SDLK_1: return ImGuiKey_1;
|
||||||
|
case SDLK_2: return ImGuiKey_2;
|
||||||
|
case SDLK_3: return ImGuiKey_3;
|
||||||
|
case SDLK_4: return ImGuiKey_4;
|
||||||
|
case SDLK_5: return ImGuiKey_5;
|
||||||
|
case SDLK_6: return ImGuiKey_6;
|
||||||
|
case SDLK_7: return ImGuiKey_7;
|
||||||
|
case SDLK_8: return ImGuiKey_8;
|
||||||
|
case SDLK_9: return ImGuiKey_9;
|
||||||
|
case SDLK_a: return ImGuiKey_A;
|
||||||
|
case SDLK_b: return ImGuiKey_B;
|
||||||
|
case SDLK_c: return ImGuiKey_C;
|
||||||
|
case SDLK_d: return ImGuiKey_D;
|
||||||
|
case SDLK_e: return ImGuiKey_E;
|
||||||
|
case SDLK_f: return ImGuiKey_F;
|
||||||
|
case SDLK_g: return ImGuiKey_G;
|
||||||
|
case SDLK_h: return ImGuiKey_H;
|
||||||
|
case SDLK_i: return ImGuiKey_I;
|
||||||
|
case SDLK_j: return ImGuiKey_J;
|
||||||
|
case SDLK_k: return ImGuiKey_K;
|
||||||
|
case SDLK_l: return ImGuiKey_L;
|
||||||
|
case SDLK_m: return ImGuiKey_M;
|
||||||
|
case SDLK_n: return ImGuiKey_N;
|
||||||
|
case SDLK_o: return ImGuiKey_O;
|
||||||
|
case SDLK_p: return ImGuiKey_P;
|
||||||
|
case SDLK_q: return ImGuiKey_Q;
|
||||||
|
case SDLK_r: return ImGuiKey_R;
|
||||||
|
case SDLK_s: return ImGuiKey_S;
|
||||||
|
case SDLK_t: return ImGuiKey_T;
|
||||||
|
case SDLK_u: return ImGuiKey_U;
|
||||||
|
case SDLK_v: return ImGuiKey_V;
|
||||||
|
case SDLK_w: return ImGuiKey_W;
|
||||||
|
case SDLK_x: return ImGuiKey_X;
|
||||||
|
case SDLK_y: return ImGuiKey_Y;
|
||||||
|
case SDLK_z: return ImGuiKey_Z;
|
||||||
|
case SDLK_F1: return ImGuiKey_F1;
|
||||||
|
case SDLK_F2: return ImGuiKey_F2;
|
||||||
|
case SDLK_F3: return ImGuiKey_F3;
|
||||||
|
case SDLK_F4: return ImGuiKey_F4;
|
||||||
|
case SDLK_F5: return ImGuiKey_F5;
|
||||||
|
case SDLK_F6: return ImGuiKey_F6;
|
||||||
|
case SDLK_F7: return ImGuiKey_F7;
|
||||||
|
case SDLK_F8: return ImGuiKey_F8;
|
||||||
|
case SDLK_F9: return ImGuiKey_F9;
|
||||||
|
case SDLK_F10: return ImGuiKey_F10;
|
||||||
|
case SDLK_F11: return ImGuiKey_F11;
|
||||||
|
case SDLK_F12: return ImGuiKey_F12;
|
||||||
|
case SDLK_F13: return ImGuiKey_F13;
|
||||||
|
case SDLK_F14: return ImGuiKey_F14;
|
||||||
|
case SDLK_F15: return ImGuiKey_F15;
|
||||||
|
case SDLK_F16: return ImGuiKey_F16;
|
||||||
|
case SDLK_F17: return ImGuiKey_F17;
|
||||||
|
case SDLK_F18: return ImGuiKey_F18;
|
||||||
|
case SDLK_F19: return ImGuiKey_F19;
|
||||||
|
case SDLK_F20: return ImGuiKey_F20;
|
||||||
|
case SDLK_F21: return ImGuiKey_F21;
|
||||||
|
case SDLK_F22: return ImGuiKey_F22;
|
||||||
|
case SDLK_F23: return ImGuiKey_F23;
|
||||||
|
case SDLK_F24: return ImGuiKey_F24;
|
||||||
|
case SDLK_AC_BACK: return ImGuiKey_AppBack;
|
||||||
|
case SDLK_AC_FORWARD: return ImGuiKey_AppForward;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to scancode
|
||||||
|
switch (scancode)
|
||||||
|
{
|
||||||
|
case SDL_SCANCODE_GRAVE: return ImGuiKey_GraveAccent;
|
||||||
|
case SDL_SCANCODE_MINUS: return ImGuiKey_Minus;
|
||||||
|
case SDL_SCANCODE_EQUALS: return ImGuiKey_Equal;
|
||||||
|
case SDL_SCANCODE_LEFTBRACKET: return ImGuiKey_LeftBracket;
|
||||||
|
case SDL_SCANCODE_RIGHTBRACKET: return ImGuiKey_RightBracket;
|
||||||
|
case SDL_SCANCODE_NONUSBACKSLASH: return ImGuiKey_Oem102;
|
||||||
|
case SDL_SCANCODE_BACKSLASH: return ImGuiKey_Backslash;
|
||||||
|
case SDL_SCANCODE_SEMICOLON: return ImGuiKey_Semicolon;
|
||||||
|
case SDL_SCANCODE_APOSTROPHE: return ImGuiKey_Apostrophe;
|
||||||
|
case SDL_SCANCODE_COMMA: return ImGuiKey_Comma;
|
||||||
|
case SDL_SCANCODE_PERIOD: return ImGuiKey_Period;
|
||||||
|
case SDL_SCANCODE_SLASH: return ImGuiKey_Slash;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return ImGuiKey_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.AddKeyEvent(ImGuiMod_Ctrl, (sdl_key_mods & KMOD_CTRL) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiMod_Shift, (sdl_key_mods & KMOD_SHIFT) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiMod_Alt, (sdl_key_mods & KMOD_ALT) != 0);
|
||||||
|
io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & KMOD_GUI) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id)
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||||
|
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
|
||||||
|
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||||
|
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||||
|
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
||||||
|
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL2_Init()?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case SDL_MOUSEMOTION:
|
||||||
|
{
|
||||||
|
if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == nullptr)
|
||||||
|
return false;
|
||||||
|
ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
|
||||||
|
io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
|
||||||
|
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_MOUSEWHEEL:
|
||||||
|
{
|
||||||
|
if (ImGui_ImplSDL2_GetViewportForWindowID(event->wheel.windowID) == nullptr)
|
||||||
|
return false;
|
||||||
|
//IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY);
|
||||||
|
#if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten!
|
||||||
|
float wheel_x = -event->wheel.preciseX;
|
||||||
|
float wheel_y = event->wheel.preciseY;
|
||||||
|
#else
|
||||||
|
float wheel_x = -(float)event->wheel.x;
|
||||||
|
float wheel_y = (float)event->wheel.y;
|
||||||
|
#endif
|
||||||
|
#if defined(__EMSCRIPTEN__) && !SDL_VERSION_ATLEAST(2,31,0)
|
||||||
|
wheel_x /= 100.0f;
|
||||||
|
#endif
|
||||||
|
io.AddMouseSourceEvent(event->wheel.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
|
||||||
|
io.AddMouseWheelEvent(wheel_x, wheel_y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
case SDL_MOUSEBUTTONUP:
|
||||||
|
{
|
||||||
|
if (ImGui_ImplSDL2_GetViewportForWindowID(event->button.windowID) == nullptr)
|
||||||
|
return false;
|
||||||
|
int mouse_button = -1;
|
||||||
|
if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; }
|
||||||
|
if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; }
|
||||||
|
if (event->button.button == SDL_BUTTON_MIDDLE) { mouse_button = 2; }
|
||||||
|
if (event->button.button == SDL_BUTTON_X1) { mouse_button = 3; }
|
||||||
|
if (event->button.button == SDL_BUTTON_X2) { mouse_button = 4; }
|
||||||
|
if (mouse_button == -1)
|
||||||
|
break;
|
||||||
|
io.AddMouseSourceEvent(event->button.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
|
||||||
|
io.AddMouseButtonEvent(mouse_button, (event->type == SDL_MOUSEBUTTONDOWN));
|
||||||
|
bd->MouseButtonsDown = (event->type == SDL_MOUSEBUTTONDOWN) ? (bd->MouseButtonsDown | (1 << mouse_button)) : (bd->MouseButtonsDown & ~(1 << mouse_button));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
{
|
||||||
|
if (ImGui_ImplSDL2_GetViewportForWindowID(event->text.windowID) == nullptr)
|
||||||
|
return false;
|
||||||
|
io.AddInputCharactersUTF8(event->text.text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
case SDL_KEYUP:
|
||||||
|
{
|
||||||
|
if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == nullptr)
|
||||||
|
return false;
|
||||||
|
ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod);
|
||||||
|
//IMGUI_DEBUG_LOG("SDL_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n",
|
||||||
|
// (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod);
|
||||||
|
ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode);
|
||||||
|
io.AddKeyEvent(key, (event->type == SDL_KEYDOWN));
|
||||||
|
io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
{
|
||||||
|
if (ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID) == nullptr)
|
||||||
|
return false;
|
||||||
|
// - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right.
|
||||||
|
// - However we won't get a correct LEAVE event for a captured window.
|
||||||
|
// - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
|
||||||
|
// causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why
|
||||||
|
// we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details.
|
||||||
|
Uint8 window_event = event->window.event;
|
||||||
|
if (window_event == SDL_WINDOWEVENT_ENTER)
|
||||||
|
{
|
||||||
|
bd->MouseWindowID = event->window.windowID;
|
||||||
|
bd->MouseLastLeaveFrame = 0;
|
||||||
|
}
|
||||||
|
if (window_event == SDL_WINDOWEVENT_LEAVE)
|
||||||
|
bd->MouseLastLeaveFrame = ImGui::GetFrameCount() + 1;
|
||||||
|
if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||||
|
io.AddFocusEvent(true);
|
||||||
|
else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||||
|
io.AddFocusEvent(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SDL_CONTROLLERDEVICEADDED:
|
||||||
|
case SDL_CONTROLLERDEVICEREMOVED:
|
||||||
|
{
|
||||||
|
bd->WantUpdateGamepadsList = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
EM_JS(void, ImGui_ImplSDL2_EmscriptenOpenURL, (char const* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); });
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void* sdl_gl_context)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
|
||||||
|
|
||||||
|
// Obtain compiled and runtime versions
|
||||||
|
SDL_version ver_compiled;
|
||||||
|
SDL_version ver_runtime;
|
||||||
|
SDL_VERSION(&ver_compiled);
|
||||||
|
SDL_GetVersion(&ver_runtime);
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)();
|
||||||
|
snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl2 (%u.%u.%u, %u.%u.%u)",
|
||||||
|
ver_compiled.major, ver_compiled.minor, ver_compiled.patch, ver_runtime.major, ver_runtime.minor, ver_runtime.patch);
|
||||||
|
io.BackendPlatformUserData = (void*)bd;
|
||||||
|
io.BackendPlatformName = bd->BackendPlatformName;
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||||
|
|
||||||
|
bd->Window = window;
|
||||||
|
bd->WindowID = SDL_GetWindowID(window);
|
||||||
|
bd->Renderer = renderer;
|
||||||
|
|
||||||
|
// Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse()
|
||||||
|
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
|
||||||
|
bd->MouseCanUseGlobalState = false;
|
||||||
|
bd->MouseCanUseCapture = false;
|
||||||
|
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||||
|
const char* sdl_backend = SDL_GetCurrentVideoDriver();
|
||||||
|
const char* capture_and_global_state_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
|
||||||
|
for (const char* item : capture_and_global_state_whitelist)
|
||||||
|
if (strncmp(sdl_backend, item, strlen(item)) == 0)
|
||||||
|
bd->MouseCanUseGlobalState = bd->MouseCanUseCapture = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
|
||||||
|
platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
|
||||||
|
platform_io.Platform_ClipboardUserData = nullptr;
|
||||||
|
platform_io.Platform_SetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData;
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; };
|
||||||
|
#elif SDL_HAS_OPEN_URL
|
||||||
|
platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url) == 0; };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Gamepad handling
|
||||||
|
bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst;
|
||||||
|
bd->WantUpdateGamepadsList = true;
|
||||||
|
|
||||||
|
// Load mouse cursors
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Wait] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_Progress] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAITARROW);
|
||||||
|
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||||
|
|
||||||
|
// Set platform dependent data in viewport
|
||||||
|
// Our mouse update function expect PlatformHandle to be filled for the main viewport
|
||||||
|
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||||
|
main_viewport->PlatformHandle = (void*)(intptr_t)bd->WindowID;
|
||||||
|
main_viewport->PlatformHandleRaw = nullptr;
|
||||||
|
SDL_SysWMinfo info;
|
||||||
|
SDL_VERSION(&info.version);
|
||||||
|
if (SDL_GetWindowWMInfo(window, &info))
|
||||||
|
{
|
||||||
|
#if defined(SDL_VIDEO_DRIVER_WINDOWS)
|
||||||
|
main_viewport->PlatformHandleRaw = (void*)info.info.win.window;
|
||||||
|
#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
|
||||||
|
main_viewport->PlatformHandleRaw = (void*)info.info.cocoa.window;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
|
||||||
|
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
|
||||||
|
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
|
||||||
|
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
|
||||||
|
// you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||||
|
#ifdef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// From 2.0.18: Enable native IME.
|
||||||
|
// IMPORTANT: This is used at the time of SDL_CreateWindow() so this will only affects secondary windows, if any.
|
||||||
|
// For the main window to be affected, your application needs to call this manually before calling SDL_CreateWindow().
|
||||||
|
#ifdef SDL_HINT_IME_SHOW_UI
|
||||||
|
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
|
||||||
|
#ifdef SDL_HINT_MOUSE_AUTO_CAPTURE
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void)sdl_gl_context; // Unused in 'master' branch.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDL2_Init(window, nullptr, sdl_gl_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
|
||||||
|
{
|
||||||
|
#if !SDL_HAS_VULKAN
|
||||||
|
IM_ASSERT(0 && "Unsupported");
|
||||||
|
#endif
|
||||||
|
return ImGui_ImplSDL2_Init(window, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
|
||||||
|
{
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
IM_ASSERT(0 && "Unsupported");
|
||||||
|
#endif
|
||||||
|
return ImGui_ImplSDL2_Init(window, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDL2_Init(window, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDL2_Init(window, renderer, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDL2_InitForOther(SDL_Window* window)
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDL2_Init(window, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_CloseGamepads();
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
if (bd->ClipboardTextData)
|
||||||
|
SDL_free(bd->ClipboardTextData);
|
||||||
|
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||||
|
SDL_FreeCursor(bd->MouseCursors[cursor_n]);
|
||||||
|
ImGui_ImplSDL2_CloseGamepads();
|
||||||
|
|
||||||
|
io.BackendPlatformName = nullptr;
|
||||||
|
io.BackendPlatformUserData = nullptr;
|
||||||
|
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateMouseData()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below)
|
||||||
|
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||||
|
// - SDL_CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside.
|
||||||
|
// - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to mitigate the issue we wait until mouse has moved to begin capture.
|
||||||
|
if (bd->MouseCanUseCapture)
|
||||||
|
{
|
||||||
|
bool want_capture = false;
|
||||||
|
for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++)
|
||||||
|
if (ImGui::IsMouseDragging(button_n, 1.0f))
|
||||||
|
want_capture = true;
|
||||||
|
SDL_CaptureMouse(want_capture ? SDL_TRUE : SDL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||||
|
const bool is_app_focused = (bd->Window == focused_window);
|
||||||
|
#else
|
||||||
|
const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
|
||||||
|
#endif
|
||||||
|
if (is_app_focused)
|
||||||
|
{
|
||||||
|
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
|
||||||
|
if (io.WantSetMousePos)
|
||||||
|
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
|
||||||
|
|
||||||
|
// (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
|
||||||
|
const bool is_relative_mouse_mode = SDL_GetRelativeMouseMode() != 0;
|
||||||
|
if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode)
|
||||||
|
{
|
||||||
|
// Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
|
||||||
|
int window_x, window_y, mouse_x_global, mouse_y_global;
|
||||||
|
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
||||||
|
SDL_GetWindowPosition(bd->Window, &window_x, &window_y);
|
||||||
|
io.AddMousePosEvent((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateMouseCursor()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||||
|
return;
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
|
||||||
|
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||||
|
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||||
|
{
|
||||||
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||||
|
SDL_ShowCursor(SDL_FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show OS mouse cursor
|
||||||
|
SDL_Cursor* expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow];
|
||||||
|
if (bd->MouseLastCursor != expected_cursor)
|
||||||
|
{
|
||||||
|
SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113)
|
||||||
|
bd->MouseLastCursor = expected_cursor;
|
||||||
|
}
|
||||||
|
SDL_ShowCursor(SDL_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_CloseGamepads()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
if (bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual)
|
||||||
|
for (SDL_GameController* gamepad : bd->Gamepads)
|
||||||
|
SDL_GameControllerClose(gamepad);
|
||||||
|
bd->Gamepads.resize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array, int manual_gamepads_count)
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
ImGui_ImplSDL2_CloseGamepads();
|
||||||
|
if (mode == ImGui_ImplSDL2_GamepadMode_Manual)
|
||||||
|
{
|
||||||
|
IM_ASSERT(manual_gamepads_array != nullptr || manual_gamepads_count <= 0);
|
||||||
|
for (int n = 0; n < manual_gamepads_count; n++)
|
||||||
|
bd->Gamepads.push_back(manual_gamepads_array[n]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IM_ASSERT(manual_gamepads_array == nullptr && manual_gamepads_count <= 0);
|
||||||
|
bd->WantUpdateGamepadsList = true;
|
||||||
|
}
|
||||||
|
bd->GamepadMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateGamepadButton(ImGui_ImplSDL2_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GameControllerButton button_no)
|
||||||
|
{
|
||||||
|
bool merged_value = false;
|
||||||
|
for (SDL_GameController* gamepad : bd->Gamepads)
|
||||||
|
merged_value |= SDL_GameControllerGetButton(gamepad, button_no) != 0;
|
||||||
|
io.AddKeyEvent(key, merged_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
|
||||||
|
static void ImGui_ImplSDL2_UpdateGamepadAnalog(ImGui_ImplSDL2_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GameControllerAxis axis_no, float v0, float v1)
|
||||||
|
{
|
||||||
|
float merged_value = 0.0f;
|
||||||
|
for (SDL_GameController* gamepad : bd->Gamepads)
|
||||||
|
{
|
||||||
|
float vn = Saturate((float)(SDL_GameControllerGetAxis(gamepad, axis_no) - v0) / (float)(v1 - v0));
|
||||||
|
if (merged_value < vn)
|
||||||
|
merged_value = vn;
|
||||||
|
}
|
||||||
|
io.AddKeyAnalogEvent(key, merged_value > 0.1f, merged_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDL2_UpdateGamepads()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Update list of controller(s) to use
|
||||||
|
if (bd->WantUpdateGamepadsList && bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual)
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_CloseGamepads();
|
||||||
|
int joystick_count = SDL_NumJoysticks();
|
||||||
|
for (int n = 0; n < joystick_count; n++)
|
||||||
|
if (SDL_IsGameController(n))
|
||||||
|
if (SDL_GameController* gamepad = SDL_GameControllerOpen(n))
|
||||||
|
{
|
||||||
|
bd->Gamepads.push_back(gamepad);
|
||||||
|
if (bd->GamepadMode == ImGui_ImplSDL2_GamepadMode_AutoFirst)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bd->WantUpdateGamepadsList = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||||
|
if (bd->Gamepads.Size == 0)
|
||||||
|
return;
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||||
|
|
||||||
|
// Update gamepad inputs
|
||||||
|
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768);
|
||||||
|
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDL2_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL2_Init()?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
SDL_GetWindowSize(bd->Window, &w, &h);
|
||||||
|
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
|
||||||
|
w = h = 0;
|
||||||
|
if (bd->Renderer != nullptr)
|
||||||
|
SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h);
|
||||||
|
#if SDL_HAS_VULKAN
|
||||||
|
else if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_VULKAN)
|
||||||
|
SDL_Vulkan_GetDrawableSize(bd->Window, &display_w, &display_h);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
if (w > 0 && h > 0)
|
||||||
|
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||||
|
|
||||||
|
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||||
|
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
|
||||||
|
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||||
|
Uint64 current_time = SDL_GetPerformanceCounter();
|
||||||
|
if (current_time <= bd->Time)
|
||||||
|
current_time = bd->Time + 1;
|
||||||
|
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
|
||||||
|
bd->Time = current_time;
|
||||||
|
|
||||||
|
if (bd->MouseLastLeaveFrame && bd->MouseLastLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0)
|
||||||
|
{
|
||||||
|
bd->MouseWindowID = 0;
|
||||||
|
bd->MouseLastLeaveFrame = 0;
|
||||||
|
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_UpdateMouseData();
|
||||||
|
ImGui_ImplSDL2_UpdateMouseCursor();
|
||||||
|
|
||||||
|
// Update game controllers (if enabled and available)
|
||||||
|
ImGui_ImplSDL2_UpdateGamepads();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
46
Editor/imgui/backends/imgui_impl_sdl2.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// dear imgui: Platform Backend for SDL2
|
||||||
|
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||||
|
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Platform: Clipboard support.
|
||||||
|
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
|
||||||
|
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||||
|
// [X] Platform: Gamepad support.
|
||||||
|
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||||
|
// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
|
||||||
|
struct SDL_Window;
|
||||||
|
struct SDL_Renderer;
|
||||||
|
struct _SDL_GameController;
|
||||||
|
typedef union SDL_Event SDL_Event;
|
||||||
|
|
||||||
|
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
||||||
|
|
||||||
|
// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this.
|
||||||
|
// When using manual mode, caller is responsible for opening/closing gamepad.
|
||||||
|
enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual };
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = nullptr, int manual_gamepads_count = -1);
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
278
Editor/imgui/backends/imgui_impl_sdlrenderer2.cpp
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
// dear imgui: Renderer Backend for SDL_Renderer for SDL2
|
||||||
|
// (Requires: SDL 2.0.17+)
|
||||||
|
|
||||||
|
// Note that SDL_Renderer is an _optional_ component of SDL2, which IMHO is now largely obsolete.
|
||||||
|
// For a multi-platform app consider using other technologies:
|
||||||
|
// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. You will need to update to SDL3.
|
||||||
|
// - SDL2+DirectX, SDL2+OpenGL, SDL2+Vulkan: combine SDL with dedicated renderers.
|
||||||
|
// If your application wants to render any non trivial amount of graphics other than UI,
|
||||||
|
// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user
|
||||||
|
// and it might be difficult to step out of those boundaries.
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
|
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color.
|
||||||
|
// 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer2_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
|
||||||
|
// 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter.
|
||||||
|
// 2023-05-30: Renamed imgui_impl_sdlrenderer.h/.cpp to imgui_impl_sdlrenderer2.h/.cpp to accommodate for upcoming SDL3.
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19.
|
||||||
|
// 2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
|
// 2021-10-06: Backup and restore modified ClipRect/Viewport.
|
||||||
|
// 2021-09-21: Initial version.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui_impl_sdlrenderer2.h"
|
||||||
|
#include <stdint.h> // intptr_t
|
||||||
|
|
||||||
|
// Clang warnings with -Weverything
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SDL
|
||||||
|
#include <SDL.h>
|
||||||
|
#if !SDL_VERSION_ATLEAST(2,0,17)
|
||||||
|
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// SDL_Renderer data
|
||||||
|
struct ImGui_ImplSDLRenderer2_Data
|
||||||
|
{
|
||||||
|
SDL_Renderer* Renderer; // Main viewport's renderer
|
||||||
|
SDL_Texture* FontTexture;
|
||||||
|
ImGui_ImplSDLRenderer2_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
|
static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||||
|
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
|
io.BackendRendererName = "imgui_impl_sdlrenderer2";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
|
||||||
|
bd->Renderer = renderer;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer2_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
|
||||||
|
|
||||||
|
io.BackendRendererName = nullptr;
|
||||||
|
io.BackendRendererUserData = nullptr;
|
||||||
|
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
// Clear out any viewports and cliprect set by the user
|
||||||
|
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
|
||||||
|
SDL_RenderSetViewport(renderer, nullptr);
|
||||||
|
SDL_RenderSetClipRect(renderer, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer2_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLRenderer2_Init()?");
|
||||||
|
|
||||||
|
if (!bd->FontTexture)
|
||||||
|
ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
|
||||||
|
{
|
||||||
|
// If there's a scale factor set by the user, use that instead
|
||||||
|
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
|
||||||
|
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
|
||||||
|
float rsx = 1.0f;
|
||||||
|
float rsy = 1.0f;
|
||||||
|
SDL_RenderGetScale(renderer, &rsx, &rsy);
|
||||||
|
ImVec2 render_scale;
|
||||||
|
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
|
||||||
|
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
|
||||||
|
|
||||||
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
|
||||||
|
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
|
||||||
|
if (fb_width == 0 || fb_height == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
||||||
|
struct BackupSDLRendererState
|
||||||
|
{
|
||||||
|
SDL_Rect Viewport;
|
||||||
|
bool ClipEnabled;
|
||||||
|
SDL_Rect ClipRect;
|
||||||
|
};
|
||||||
|
BackupSDLRendererState old = {};
|
||||||
|
old.ClipEnabled = SDL_RenderIsClipEnabled(renderer) == SDL_TRUE;
|
||||||
|
SDL_RenderGetViewport(renderer, &old.Viewport);
|
||||||
|
SDL_RenderGetClipRect(renderer, &old.ClipRect);
|
||||||
|
|
||||||
|
// Setup desired state
|
||||||
|
ImGui_ImplSDLRenderer2_SetupRenderState(renderer);
|
||||||
|
|
||||||
|
// Setup render state structure (for callbacks and custom texture bindings)
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
ImGui_ImplSDLRenderer2_RenderState render_state;
|
||||||
|
render_state.Renderer = renderer;
|
||||||
|
platform_io.Renderer_RenderState = &render_state;
|
||||||
|
|
||||||
|
// Will project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||||
|
ImVec2 clip_scale = render_scale;
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* draw_list = draw_data->CmdLists[n];
|
||||||
|
const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data;
|
||||||
|
const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data;
|
||||||
|
|
||||||
|
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
|
||||||
|
{
|
||||||
|
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
|
||||||
|
if (pcmd->UserCallback)
|
||||||
|
{
|
||||||
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
|
ImGui_ImplSDLRenderer2_SetupRenderState(renderer);
|
||||||
|
else
|
||||||
|
pcmd->UserCallback(draw_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||||
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||||
|
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||||
|
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||||
|
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
|
||||||
|
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
|
||||||
|
SDL_RenderSetClipRect(renderer, &r);
|
||||||
|
|
||||||
|
const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos));
|
||||||
|
const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv));
|
||||||
|
#if SDL_VERSION_ATLEAST(2,0,19)
|
||||||
|
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+
|
||||||
|
#else
|
||||||
|
const int* color = (const int*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
|
||||||
|
SDL_RenderGeometryRaw(renderer, tex,
|
||||||
|
xy, (int)sizeof(ImDrawVert),
|
||||||
|
color, (int)sizeof(ImDrawVert),
|
||||||
|
uv, (int)sizeof(ImDrawVert),
|
||||||
|
draw_list->VtxBuffer.Size - pcmd->VtxOffset,
|
||||||
|
idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
platform_io.Renderer_RenderState = nullptr;
|
||||||
|
|
||||||
|
// Restore modified SDL_Renderer state
|
||||||
|
SDL_RenderSetViewport(renderer, &old.Viewport);
|
||||||
|
SDL_RenderSetClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by Init/NewFrame/Shutdown
|
||||||
|
bool ImGui_ImplSDLRenderer2_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||||
|
|
||||||
|
// Build texture atlas
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
|
bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height);
|
||||||
|
if (bd->FontTexture == nullptr)
|
||||||
|
{
|
||||||
|
SDL_Log("error creating texture");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width);
|
||||||
|
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear);
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer2_DestroyFontsTexture()
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||||
|
if (bd->FontTexture)
|
||||||
|
{
|
||||||
|
io.Fonts->SetTexID(0);
|
||||||
|
SDL_DestroyTexture(bd->FontTexture);
|
||||||
|
bd->FontTexture = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplSDLRenderer2_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
return ImGui_ImplSDLRenderer2_CreateFontsTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplSDLRenderer2_DestroyDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplSDLRenderer2_DestroyFontsTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
51
Editor/imgui/backends/imgui_impl_sdlrenderer2.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// dear imgui: Renderer Backend for SDL_Renderer for SDL2
|
||||||
|
// (Requires: SDL 2.0.17+)
|
||||||
|
|
||||||
|
// Note that SDL_Renderer is an _optional_ component of SDL2, which IMHO is now largely obsolete.
|
||||||
|
// For a multi-platform app consider using other technologies:
|
||||||
|
// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. You will need to update to SDL3.
|
||||||
|
// - SDL2+DirectX, SDL2+OpenGL, SDL2+Vulkan: combine SDL with dedicated renderers.
|
||||||
|
// If your application wants to render any non trivial amount of graphics other than UI,
|
||||||
|
// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user
|
||||||
|
// and it might be difficult to step out of those boundaries.
|
||||||
|
|
||||||
|
// Implemented features:
|
||||||
|
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||||
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
|
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||||
|
|
||||||
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
|
|
||||||
|
struct SDL_Renderer;
|
||||||
|
|
||||||
|
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer);
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_Shutdown();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer);
|
||||||
|
|
||||||
|
// Called by Init/NewFrame/Shutdown
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateFontsTexture();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyFontsTexture();
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
|
||||||
|
|
||||||
|
// [BETA] Selected render state data shared with callbacks.
|
||||||
|
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLRenderer2_RenderDrawData() call.
|
||||||
|
// (Please open an issue if you feel you need access to more data)
|
||||||
|
struct ImGui_ImplSDLRenderer2_RenderState
|
||||||
|
{
|
||||||
|
SDL_Renderer* Renderer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
141
Editor/imgui/imconfig.h
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||||
|
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||||
|
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||||
|
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||||
|
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||||
|
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||||
|
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//---- Define assertion handler. Defaults to calling assert().
|
||||||
|
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
|
||||||
|
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||||
|
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||||
|
|
||||||
|
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||||
|
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||||
|
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||||
|
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||||
|
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
|
||||||
|
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
|
||||||
|
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
|
||||||
|
|
||||||
|
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||||
|
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
|
||||||
|
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||||
|
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||||
|
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||||
|
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||||
|
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||||
|
|
||||||
|
//---- Don't implement some functions to reduce linkage requirements.
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||||
|
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||||
|
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||||
|
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||||
|
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert.
|
||||||
|
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||||
|
|
||||||
|
//---- Enable Test Engine / Automation features.
|
||||||
|
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
|
||||||
|
|
||||||
|
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||||
|
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||||
|
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
|
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||||
|
|
||||||
|
//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.
|
||||||
|
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
|
||||||
|
//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.
|
||||||
|
//#define IMGUI_USE_LEGACY_CRC32_ADLER
|
||||||
|
|
||||||
|
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||||
|
//#define IMGUI_USE_WCHAR32
|
||||||
|
|
||||||
|
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||||
|
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||||
|
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||||
|
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||||
|
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||||
|
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||||
|
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||||
|
|
||||||
|
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||||
|
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||||
|
//#define IMGUI_USE_STB_SPRINTF
|
||||||
|
|
||||||
|
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||||
|
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
|
||||||
|
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE
|
||||||
|
|
||||||
|
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
||||||
|
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||||
|
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
|
||||||
|
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
||||||
|
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
|
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||||
|
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||||
|
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||||
|
|
||||||
|
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
|
||||||
|
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||||
|
/*
|
||||||
|
#define IM_VEC2_CLASS_EXTRA \
|
||||||
|
constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
|
||||||
|
operator MyVec2() const { return MyVec2(x,y); }
|
||||||
|
|
||||||
|
#define IM_VEC4_CLASS_EXTRA \
|
||||||
|
constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
|
||||||
|
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||||
|
*/
|
||||||
|
//---- ...Or use Dear ImGui's own very basic math operators.
|
||||||
|
//#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
|
||||||
|
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
|
||||||
|
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||||
|
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||||
|
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||||
|
//#define ImDrawIdx unsigned int
|
||||||
|
|
||||||
|
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||||
|
//struct ImDrawList;
|
||||||
|
//struct ImDrawCmd;
|
||||||
|
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||||
|
//#define ImDrawCallback MyImDrawCallback
|
||||||
|
|
||||||
|
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||||
|
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||||
|
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||||
|
//#define IM_DEBUG_BREAK __debugbreak()
|
||||||
|
|
||||||
|
//---- Debug Tools: Enable slower asserts
|
||||||
|
//#define IMGUI_DEBUG_PARANOID
|
||||||
|
|
||||||
|
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||||
|
/*
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||||
|
}
|
||||||
|
*/
|
||||||
17140
Editor/imgui/imgui.cpp
Normal file
3797
Editor/imgui/imgui.h
Normal file
4858
Editor/imgui/imgui_draw.cpp
Normal file
3655
Editor/imgui/imgui_internal.h
Normal file
4559
Editor/imgui/imgui_tables.cpp
Normal file
10591
Editor/imgui/imgui_widgets.cpp
Normal file
627
Editor/imgui/imstb_rectpack.h
Normal file
@@ -0,0 +1,627 @@
|
|||||||
|
// [DEAR IMGUI]
|
||||||
|
// This is a slightly modified version of stb_rect_pack.h 1.01.
|
||||||
|
// Grep for [DEAR IMGUI] to find the changes.
|
||||||
|
//
|
||||||
|
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||||
|
// Sean Barrett 2014
|
||||||
|
//
|
||||||
|
// Useful for e.g. packing rectangular textures into an atlas.
|
||||||
|
// Does not do rotation.
|
||||||
|
//
|
||||||
|
// Before #including,
|
||||||
|
//
|
||||||
|
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
//
|
||||||
|
// in the file that you want to have the implementation.
|
||||||
|
//
|
||||||
|
// Not necessarily the awesomest packing method, but better than
|
||||||
|
// the totally naive one in stb_truetype (which is primarily what
|
||||||
|
// this is meant to replace).
|
||||||
|
//
|
||||||
|
// Has only had a few tests run, may have issues.
|
||||||
|
//
|
||||||
|
// More docs to come.
|
||||||
|
//
|
||||||
|
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||||
|
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||||
|
//
|
||||||
|
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||||
|
//
|
||||||
|
// Please note: better rectangle packers are welcome! Please
|
||||||
|
// implement them to the same API, but with a different init
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// Credits
|
||||||
|
//
|
||||||
|
// Library
|
||||||
|
// Sean Barrett
|
||||||
|
// Minor features
|
||||||
|
// Martins Mozeiko
|
||||||
|
// github:IntellectualKitty
|
||||||
|
//
|
||||||
|
// Bugfixes / warning fixes
|
||||||
|
// Jeremy Jaussaud
|
||||||
|
// Fabian Giesen
|
||||||
|
//
|
||||||
|
// Version history:
|
||||||
|
//
|
||||||
|
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||||
|
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||||
|
// 0.99 (2019-02-07) warning fixes
|
||||||
|
// 0.11 (2017-03-03) return packing success/fail result
|
||||||
|
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||||
|
// 0.09 (2016-08-27) fix compiler warnings
|
||||||
|
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||||
|
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||||
|
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||||
|
// 0.01: initial release
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
//
|
||||||
|
// See end of file for license information.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// INCLUDE SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
|
||||||
|
#define STB_RECT_PACK_VERSION 1
|
||||||
|
|
||||||
|
#ifdef STBRP_STATIC
|
||||||
|
#define STBRP_DEF static
|
||||||
|
#else
|
||||||
|
#define STBRP_DEF extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct stbrp_context stbrp_context;
|
||||||
|
typedef struct stbrp_node stbrp_node;
|
||||||
|
typedef struct stbrp_rect stbrp_rect;
|
||||||
|
|
||||||
|
typedef int stbrp_coord;
|
||||||
|
|
||||||
|
#define STBRP__MAXVAL 0x7fffffff
|
||||||
|
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||||
|
|
||||||
|
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||||
|
// Assign packed locations to rectangles. The rectangles are of type
|
||||||
|
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||||
|
// are 'num_rects' many of them.
|
||||||
|
//
|
||||||
|
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||||
|
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||||
|
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||||
|
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||||
|
// have the 'was_packed' flag set to 0.
|
||||||
|
//
|
||||||
|
// You should not try to access the 'rects' array from another thread
|
||||||
|
// while this function is running, as the function temporarily reorders
|
||||||
|
// the array while it executes.
|
||||||
|
//
|
||||||
|
// To pack into another rectangle, you need to call stbrp_init_target
|
||||||
|
// again. To continue packing into the same rectangle, you can call
|
||||||
|
// this function again. Calling this multiple times with multiple rect
|
||||||
|
// arrays will probably produce worse packing results than calling it
|
||||||
|
// a single time with the full rectangle array, but the option is
|
||||||
|
// available.
|
||||||
|
//
|
||||||
|
// The function returns 1 if all of the rectangles were successfully
|
||||||
|
// packed and 0 otherwise.
|
||||||
|
|
||||||
|
struct stbrp_rect
|
||||||
|
{
|
||||||
|
// reserved for your use:
|
||||||
|
int id;
|
||||||
|
|
||||||
|
// input:
|
||||||
|
stbrp_coord w, h;
|
||||||
|
|
||||||
|
// output:
|
||||||
|
stbrp_coord x, y;
|
||||||
|
int was_packed; // non-zero if valid packing
|
||||||
|
|
||||||
|
}; // 16 bytes, nominally
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||||
|
// Initialize a rectangle packer to:
|
||||||
|
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||||
|
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||||
|
//
|
||||||
|
// You must call this function every time you start packing into a new target.
|
||||||
|
//
|
||||||
|
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||||
|
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||||
|
// the call (or calls) finish.
|
||||||
|
//
|
||||||
|
// Note: to guarantee best results, either:
|
||||||
|
// 1. make sure 'num_nodes' >= 'width'
|
||||||
|
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||||
|
//
|
||||||
|
// If you don't do either of the above things, widths will be quantized to multiples
|
||||||
|
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||||
|
//
|
||||||
|
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||||
|
// may run out of temporary storage and be unable to pack some rectangles.
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||||
|
// Optionally call this function after init but before doing any packing to
|
||||||
|
// change the handling of the out-of-temp-memory scenario, described above.
|
||||||
|
// If you call init again, this will be reset to the default (false).
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||||
|
// Optionally select which packing heuristic the library should use. Different
|
||||||
|
// heuristics will produce better/worse results for different data sets.
|
||||||
|
// If you call init again, this will be reset to the default.
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP_HEURISTIC_Skyline_default=0,
|
||||||
|
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||||
|
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// the details of the following structures don't matter to you, but they must
|
||||||
|
// be visible so you can handle the memory allocations for them
|
||||||
|
|
||||||
|
struct stbrp_node
|
||||||
|
{
|
||||||
|
stbrp_coord x,y;
|
||||||
|
stbrp_node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stbrp_context
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int align;
|
||||||
|
int init_mode;
|
||||||
|
int heuristic;
|
||||||
|
int num_nodes;
|
||||||
|
stbrp_node *active_head;
|
||||||
|
stbrp_node *free_head;
|
||||||
|
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// IMPLEMENTATION SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#ifndef STBRP_SORT
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define STBRP_SORT qsort
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBRP_ASSERT
|
||||||
|
#include <assert.h>
|
||||||
|
#define STBRP_ASSERT assert
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define STBRP__NOTUSED(v) (void)(v)
|
||||||
|
#define STBRP__CDECL __cdecl
|
||||||
|
#else
|
||||||
|
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||||
|
#define STBRP__CDECL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP__INIT_skyline = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||||
|
{
|
||||||
|
switch (context->init_mode) {
|
||||||
|
case STBRP__INIT_skyline:
|
||||||
|
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||||
|
context->heuristic = heuristic;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
STBRP_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||||
|
{
|
||||||
|
if (allow_out_of_mem)
|
||||||
|
// if it's ok to run out of memory, then don't bother aligning them;
|
||||||
|
// this gives better packing, but may fail due to OOM (even though
|
||||||
|
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||||
|
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||||
|
context->align = 1;
|
||||||
|
else {
|
||||||
|
// if it's not ok to run out of memory, then quantize the widths
|
||||||
|
// so that num_nodes is always enough nodes.
|
||||||
|
//
|
||||||
|
// I.e. num_nodes * align >= width
|
||||||
|
// align >= width / num_nodes
|
||||||
|
// align = ceil(width/num_nodes)
|
||||||
|
|
||||||
|
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i < num_nodes-1; ++i)
|
||||||
|
nodes[i].next = &nodes[i+1];
|
||||||
|
nodes[i].next = NULL;
|
||||||
|
context->init_mode = STBRP__INIT_skyline;
|
||||||
|
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||||
|
context->free_head = &nodes[0];
|
||||||
|
context->active_head = &context->extra[0];
|
||||||
|
context->width = width;
|
||||||
|
context->height = height;
|
||||||
|
context->num_nodes = num_nodes;
|
||||||
|
stbrp_setup_allow_out_of_mem(context, 0);
|
||||||
|
|
||||||
|
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||||
|
context->extra[0].x = 0;
|
||||||
|
context->extra[0].y = 0;
|
||||||
|
context->extra[0].next = &context->extra[1];
|
||||||
|
context->extra[1].x = (stbrp_coord) width;
|
||||||
|
context->extra[1].y = (1<<30);
|
||||||
|
context->extra[1].next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find minimum y position if it starts at x1
|
||||||
|
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||||
|
{
|
||||||
|
stbrp_node *node = first;
|
||||||
|
int x1 = x0 + width;
|
||||||
|
int min_y, visited_width, waste_area;
|
||||||
|
|
||||||
|
STBRP__NOTUSED(c);
|
||||||
|
|
||||||
|
STBRP_ASSERT(first->x <= x0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// skip in case we're past the node
|
||||||
|
while (node->next->x <= x0)
|
||||||
|
++node;
|
||||||
|
#else
|
||||||
|
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_ASSERT(node->x <= x0);
|
||||||
|
|
||||||
|
min_y = 0;
|
||||||
|
waste_area = 0;
|
||||||
|
visited_width = 0;
|
||||||
|
while (node->x < x1) {
|
||||||
|
if (node->y > min_y) {
|
||||||
|
// raise min_y higher.
|
||||||
|
// we've accounted for all waste up to min_y,
|
||||||
|
// but we'll now add more waste for everything we've visted
|
||||||
|
waste_area += visited_width * (node->y - min_y);
|
||||||
|
min_y = node->y;
|
||||||
|
// the first time through, visited_width might be reduced
|
||||||
|
if (node->x < x0)
|
||||||
|
visited_width += node->next->x - x0;
|
||||||
|
else
|
||||||
|
visited_width += node->next->x - node->x;
|
||||||
|
} else {
|
||||||
|
// add waste area
|
||||||
|
int under_width = node->next->x - node->x;
|
||||||
|
if (under_width + visited_width > width)
|
||||||
|
under_width = width - visited_width;
|
||||||
|
waste_area += under_width * (min_y - node->y);
|
||||||
|
visited_width += under_width;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pwaste = waste_area;
|
||||||
|
return min_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x,y;
|
||||||
|
stbrp_node **prev_link;
|
||||||
|
} stbrp__findresult;
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||||
|
{
|
||||||
|
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||||
|
stbrp__findresult fr;
|
||||||
|
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||||
|
|
||||||
|
// align to multiple of c->align
|
||||||
|
width = (width + c->align - 1);
|
||||||
|
width -= width % c->align;
|
||||||
|
STBRP_ASSERT(width % c->align == 0);
|
||||||
|
|
||||||
|
// if it can't possibly fit, bail immediately
|
||||||
|
if (width > c->width || height > c->height) {
|
||||||
|
fr.prev_link = NULL;
|
||||||
|
fr.x = fr.y = 0;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
while (node->x + width <= c->width) {
|
||||||
|
int y,waste;
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||||
|
// bottom left
|
||||||
|
if (y < best_y) {
|
||||||
|
best_y = y;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// best-fit
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
// can only use it if it first vertically
|
||||||
|
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||||
|
|
||||||
|
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||||
|
//
|
||||||
|
// e.g, if fitting
|
||||||
|
//
|
||||||
|
// ____________________
|
||||||
|
// |____________________|
|
||||||
|
//
|
||||||
|
// into
|
||||||
|
//
|
||||||
|
// | |
|
||||||
|
// | ____________|
|
||||||
|
// |____________|
|
||||||
|
//
|
||||||
|
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||||
|
//
|
||||||
|
// This makes BF take about 2x the time
|
||||||
|
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||||
|
tail = c->active_head;
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
// find first node that's admissible
|
||||||
|
while (tail->x < width)
|
||||||
|
tail = tail->next;
|
||||||
|
while (tail) {
|
||||||
|
int xpos = tail->x - width;
|
||||||
|
int y,waste;
|
||||||
|
STBRP_ASSERT(xpos >= 0);
|
||||||
|
// find the left position that matches this
|
||||||
|
while (node->next->x <= xpos) {
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
if (y <= best_y) {
|
||||||
|
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||||
|
best_x = xpos;
|
||||||
|
//STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tail = tail->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fr.prev_link = best;
|
||||||
|
fr.x = best_x;
|
||||||
|
fr.y = best_y;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||||
|
{
|
||||||
|
// find best position according to heuristic
|
||||||
|
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||||
|
stbrp_node *node, *cur;
|
||||||
|
|
||||||
|
// bail if:
|
||||||
|
// 1. it failed
|
||||||
|
// 2. the best node doesn't fit (we don't always check this)
|
||||||
|
// 3. we're out of memory
|
||||||
|
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||||
|
res.prev_link = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// on success, create new node
|
||||||
|
node = context->free_head;
|
||||||
|
node->x = (stbrp_coord) res.x;
|
||||||
|
node->y = (stbrp_coord) (res.y + height);
|
||||||
|
|
||||||
|
context->free_head = node->next;
|
||||||
|
|
||||||
|
// insert the new node into the right starting point, and
|
||||||
|
// let 'cur' point to the remaining nodes needing to be
|
||||||
|
// stiched back in
|
||||||
|
|
||||||
|
cur = *res.prev_link;
|
||||||
|
if (cur->x < res.x) {
|
||||||
|
// preserve the existing one, so start testing with the next one
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
cur->next = node;
|
||||||
|
cur = next;
|
||||||
|
} else {
|
||||||
|
*res.prev_link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from here, traverse cur and free the nodes, until we get to one
|
||||||
|
// that shouldn't be freed
|
||||||
|
while (cur->next && cur->next->x <= res.x + width) {
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
// move the current node to the free list
|
||||||
|
cur->next = context->free_head;
|
||||||
|
context->free_head = cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stitch the list back in
|
||||||
|
node->next = cur;
|
||||||
|
|
||||||
|
if (cur->x < res.x + width)
|
||||||
|
cur->x = (stbrp_coord) (res.x + width);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur->x < context->width) {
|
||||||
|
STBRP_ASSERT(cur->x < cur->next->x);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(cur->next == NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
int count=0;
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur) {
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
cur = context->free_head;
|
||||||
|
while (cur) {
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(count == context->num_nodes+2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||||
|
if (p->h > q->h)
|
||||||
|
return -1;
|
||||||
|
if (p->h < q->h)
|
||||||
|
return 1;
|
||||||
|
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||||
|
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||||
|
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||||
|
{
|
||||||
|
int i, all_rects_packed = 1;
|
||||||
|
|
||||||
|
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort according to heuristic
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||||
|
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||||
|
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||||
|
} else {
|
||||||
|
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||||
|
if (fr.prev_link) {
|
||||||
|
rects[i].x = (stbrp_coord) fr.x;
|
||||||
|
rects[i].y = (stbrp_coord) fr.y;
|
||||||
|
} else {
|
||||||
|
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsort
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||||
|
|
||||||
|
// set was_packed flags and all_rects_packed status
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||||
|
if (!rects[i].was_packed)
|
||||||
|
all_rects_packed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the all_rects_packed status
|
||||||
|
return all_rects_packed;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
1488
Editor/imgui/imstb_textedit.h
Normal file
5085
Editor/imgui/imstb_truetype.h
Normal file
23
Editor/imgui/misc/README.txt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
misc/cpp/
|
||||||
|
InputText() wrappers for C++ standard library (STL) type: std::string.
|
||||||
|
This is also an example of how you may wrap your own similar types.
|
||||||
|
|
||||||
|
misc/debuggers/
|
||||||
|
Helper files for popular debuggers.
|
||||||
|
With the .natvis file, types like ImVector<> will be displayed nicely in Visual Studio debugger.
|
||||||
|
|
||||||
|
misc/fonts/
|
||||||
|
Fonts loading/merging instructions (e.g. How to handle glyph ranges, how to merge icons fonts).
|
||||||
|
Command line tool "binary_to_compressed_c" to create compressed arrays to embed data in source code.
|
||||||
|
Suggested fonts and links.
|
||||||
|
|
||||||
|
misc/freetype/
|
||||||
|
Font atlas builder/rasterizer using FreeType instead of stb_truetype.
|
||||||
|
Benefit from better FreeType rasterization, in particular for small fonts.
|
||||||
|
|
||||||
|
misc/single_file/
|
||||||
|
Single-file header stub.
|
||||||
|
We use this to validate compiling all *.cpp files in a same compilation unit.
|
||||||
|
Users of that technique (also called "Unity builds") can generally provide this themselves,
|
||||||
|
so we don't really recommend you use this in your projects.
|
||||||
13
Editor/imgui/misc/cpp/README.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
imgui_stdlib.h + imgui_stdlib.cpp
|
||||||
|
InputText() wrappers for C++ standard library (STL) type: std::string.
|
||||||
|
This is also an example of how you may wrap your own similar types.
|
||||||
|
|
||||||
|
imgui_scoped.h
|
||||||
|
[Experimental, not currently in main repository]
|
||||||
|
Additional header file with some RAII-style wrappers for common Dear ImGui functions.
|
||||||
|
Try by merging: https://github.com/ocornut/imgui/pull/2197
|
||||||
|
Discuss at: https://github.com/ocornut/imgui/issues/2096
|
||||||
|
|
||||||
|
See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
|
||||||
|
https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||||
88
Editor/imgui/misc/cpp/imgui_stdlib.cpp
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
|
||||||
|
// This is also an example of how you may wrap your own similar types.
|
||||||
|
|
||||||
|
// Changelog:
|
||||||
|
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
|
||||||
|
|
||||||
|
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
|
||||||
|
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui_stdlib.h"
|
||||||
|
|
||||||
|
// Clang warnings with -Weverything
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct InputTextCallback_UserData
|
||||||
|
{
|
||||||
|
std::string* Str;
|
||||||
|
ImGuiInputTextCallback ChainCallback;
|
||||||
|
void* ChainCallbackUserData;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int InputTextCallback(ImGuiInputTextCallbackData* data)
|
||||||
|
{
|
||||||
|
InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData;
|
||||||
|
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
|
||||||
|
{
|
||||||
|
// Resize string callback
|
||||||
|
// If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want.
|
||||||
|
std::string* str = user_data->Str;
|
||||||
|
IM_ASSERT(data->Buf == str->c_str());
|
||||||
|
str->resize(data->BufTextLen);
|
||||||
|
data->Buf = (char*)str->c_str();
|
||||||
|
}
|
||||||
|
else if (user_data->ChainCallback)
|
||||||
|
{
|
||||||
|
// Forward to user callback, if any
|
||||||
|
data->UserData = user_data->ChainCallbackUserData;
|
||||||
|
return user_data->ChainCallback(data);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||||
|
{
|
||||||
|
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||||
|
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||||
|
|
||||||
|
InputTextCallback_UserData cb_user_data;
|
||||||
|
cb_user_data.Str = str;
|
||||||
|
cb_user_data.ChainCallback = callback;
|
||||||
|
cb_user_data.ChainCallbackUserData = user_data;
|
||||||
|
return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||||
|
{
|
||||||
|
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||||
|
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||||
|
|
||||||
|
InputTextCallback_UserData cb_user_data;
|
||||||
|
cb_user_data.Str = str;
|
||||||
|
cb_user_data.ChainCallback = callback;
|
||||||
|
cb_user_data.ChainCallbackUserData = user_data;
|
||||||
|
return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||||
|
{
|
||||||
|
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||||
|
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||||
|
|
||||||
|
InputTextCallback_UserData cb_user_data;
|
||||||
|
cb_user_data.Str = str;
|
||||||
|
cb_user_data.ChainCallback = callback;
|
||||||
|
cb_user_data.ChainCallbackUserData = user_data;
|
||||||
|
return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
25
Editor/imgui/misc/cpp/imgui_stdlib.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
|
||||||
|
// This is also an example of how you may wrap your own similar types.
|
||||||
|
|
||||||
|
// Changelog:
|
||||||
|
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
|
||||||
|
|
||||||
|
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
|
||||||
|
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
// ImGui::InputText() with std::string
|
||||||
|
// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
|
||||||
|
IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||||
|
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||||
|
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
16
Editor/imgui/misc/debuggers/README.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
HELPER FILES FOR POPULAR DEBUGGERS
|
||||||
|
|
||||||
|
imgui.gdb
|
||||||
|
GDB: disable stepping into trivial functions.
|
||||||
|
(read comments inside file for details)
|
||||||
|
|
||||||
|
imgui.natstepfilter
|
||||||
|
Visual Studio Debugger: disable stepping into trivial functions.
|
||||||
|
(read comments inside file for details)
|
||||||
|
|
||||||
|
imgui.natvis
|
||||||
|
Visual Studio Debugger: describe Dear ImGui types for better display.
|
||||||
|
With this, types like ImVector<> will be displayed nicely in the debugger.
|
||||||
|
(read comments inside file for details)
|
||||||
|
|
||||||
12
Editor/imgui/misc/debuggers/imgui.gdb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# GDB configuration to aid debugging experience
|
||||||
|
|
||||||
|
# To enable these customizations edit $HOME/.gdbinit (or ./.gdbinit if local gdbinit is enabled) and add:
|
||||||
|
# add-auto-load-safe-path /path/to/imgui.gdb
|
||||||
|
# source /path/to/imgui.gdb
|
||||||
|
#
|
||||||
|
# More Information at:
|
||||||
|
# * https://sourceware.org/gdb/current/onlinedocs/gdb/gdbinit-man.html
|
||||||
|
# * https://sourceware.org/gdb/current/onlinedocs/gdb/Init-File-in-the-Current-Directory.html#Init-File-in-the-Current-Directory
|
||||||
|
|
||||||
|
# Disable stepping into trivial functions
|
||||||
|
skip -rfunction Im(Vec2|Vec4|Strv|Vector|Span)::.+
|
||||||
31
Editor/imgui/misc/debuggers/imgui.natstepfilter
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
.natstepfilter file for Visual Studio debugger.
|
||||||
|
Purpose: instruct debugger to skip some functions when using StepInto (F11)
|
||||||
|
|
||||||
|
Since Visual Studio 2022 version 17.6 Preview 2 (currently available as a "Preview" build on March 14, 2023)
|
||||||
|
It is possible to add the .natstepfilter file to your project file and it will automatically be used.
|
||||||
|
(https://developercommunity.visualstudio.com/t/allow-natstepfilter-and-natjmc-to-be-included-as-p/561718)
|
||||||
|
|
||||||
|
For older Visual Studio version prior to 2022 17.6 Preview 2:
|
||||||
|
* copy in %USERPROFILE%\Documents\Visual Studio XXXX\Visualizers (current user)
|
||||||
|
* or copy in %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers (all users)
|
||||||
|
If you have multiple VS version installed, the version that matters is the one you are using the IDE/debugger
|
||||||
|
of (not the compiling toolset). This is supported since Visual Studio 2012.
|
||||||
|
|
||||||
|
More information at: https://docs.microsoft.com/en-us/visualstudio/debugger/just-my-code?view=vs-2019#BKMK_C___Just_My_Code
|
||||||
|
-->
|
||||||
|
|
||||||
|
<StepFilter xmlns="http://schemas.microsoft.com/vstudio/debugger/natstepfilter/2010">
|
||||||
|
|
||||||
|
<!-- Disable stepping into trivial functions -->
|
||||||
|
<Function>
|
||||||
|
<Name>(ImVec2|ImVec4|ImStrv)::.+</Name>
|
||||||
|
<Action>NoStepInto</Action>
|
||||||
|
</Function>
|
||||||
|
<Function>
|
||||||
|
<Name>(ImVector|ImSpan).*::operator.+</Name>
|
||||||
|
<Action>NoStepInto</Action>
|
||||||
|
</Function>
|
||||||
|
|
||||||
|
</StepFilter>
|
||||||
58
Editor/imgui/misc/debuggers/imgui.natvis
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
.natvis file for Visual Studio debugger.
|
||||||
|
Purpose: provide nicer views on data types used by Dear ImGui.
|
||||||
|
|
||||||
|
To enable:
|
||||||
|
* include file in your VS project (most recommended: not intrusive and always kept up to date!)
|
||||||
|
* or copy in %USERPROFILE%\Documents\Visual Studio XXXX\Visualizers (current user)
|
||||||
|
* or copy in %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers (all users)
|
||||||
|
|
||||||
|
More information at: https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2019
|
||||||
|
-->
|
||||||
|
|
||||||
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||||
|
|
||||||
|
<Type Name="ImVector<*>">
|
||||||
|
<DisplayString>{{Size={Size} Capacity={Capacity}}}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>Size</Size>
|
||||||
|
<ValuePointer>Data</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="ImSpan<*>">
|
||||||
|
<DisplayString>{{Size={DataEnd-Data} }}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>DataEnd-Data</Size>
|
||||||
|
<ValuePointer>Data</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="ImVec2">
|
||||||
|
<DisplayString>{{x={x,g} y={y,g}}}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="ImVec4">
|
||||||
|
<DisplayString>{{x={x,g} y={y,g} z={z,g} w={w,g}}}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="ImRect">
|
||||||
|
<DisplayString>{{Min=({Min.x,g} {Min.y,g}) Max=({Max.x,g} {Max.y,g}) Size=({Max.x-Min.x,g} {Max.y-Min.y,g})}}</DisplayString>
|
||||||
|
<Expand>
|
||||||
|
<Item Name="Min">Min</Item>
|
||||||
|
<Item Name="Max">Max</Item>
|
||||||
|
<Item Name="[Width]">Max.x - Min.x</Item>
|
||||||
|
<Item Name="[Height]">Max.y - Min.y</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="ImGuiWindow">
|
||||||
|
<DisplayString>{{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}}</DisplayString>
|
||||||
|
</Type>
|
||||||
|
|
||||||
|
</AutoVisualizer>
|
||||||
BIN
Editor/imgui/misc/fonts/Cousine-Regular.ttf
Normal file
BIN
Editor/imgui/misc/fonts/DroidSans.ttf
Normal file
BIN
Editor/imgui/misc/fonts/Karla-Regular.ttf
Normal file
BIN
Editor/imgui/misc/fonts/ProggyClean.ttf
Normal file
BIN
Editor/imgui/misc/fonts/ProggyTiny.ttf
Normal file
BIN
Editor/imgui/misc/fonts/Roboto-Medium.ttf
Normal file
424
Editor/imgui/misc/fonts/binary_to_compressed_c.cpp
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
// dear imgui
|
||||||
|
// (binary_to_compressed_c.cpp)
|
||||||
|
// Helper tool to turn a file into a C array, if you want to embed font data in your source code.
|
||||||
|
|
||||||
|
// The data is first compressed with stb_compress() to reduce source code size.
|
||||||
|
// Then stored in a C array:
|
||||||
|
// - Base85: ~5 bytes of source code for 4 bytes of input data. 5 bytes stored in binary (suggested by @mmalex).
|
||||||
|
// - As int: ~11 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Endianness dependent, need swapping on big-endian CPU.
|
||||||
|
// - As char: ~12 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Not endianness dependent.
|
||||||
|
// Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF()
|
||||||
|
|
||||||
|
// Build with, e.g:
|
||||||
|
// # cl.exe binary_to_compressed_c.cpp
|
||||||
|
// # g++ binary_to_compressed_c.cpp
|
||||||
|
// # clang++ binary_to_compressed_c.cpp
|
||||||
|
// You can also find a precompiled Windows binary in the binary/demo package available from https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
// Usage:
|
||||||
|
// binary_to_compressed_c.exe [-nocompress] [-nostatic] [-base85] <inputfile> <symbolname>
|
||||||
|
// Usage example:
|
||||||
|
// # binary_to_compressed_c.exe myfont.ttf MyFont > myfont.cpp
|
||||||
|
// # binary_to_compressed_c.exe -base85 myfont.ttf MyFont > myfont.cpp
|
||||||
|
// Note:
|
||||||
|
// Base85 encoding will be obsoleted by future version of Dear ImGui!
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// stb_compress* from stb.h - declaration
|
||||||
|
typedef unsigned int stb_uint;
|
||||||
|
typedef unsigned char stb_uchar;
|
||||||
|
stb_uint stb_compress(stb_uchar* out, stb_uchar* in, stb_uint len);
|
||||||
|
|
||||||
|
enum SourceEncoding
|
||||||
|
{
|
||||||
|
SourceEncoding_U8, // New default since 2024/11
|
||||||
|
SourceEncoding_U32,
|
||||||
|
SourceEncoding_Base85,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool binary_to_compressed_c(const char* filename, const char* symbol, SourceEncoding source_encoding, bool use_compression, bool use_static);
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc < 3)
|
||||||
|
{
|
||||||
|
printf("Syntax: %s [-u8|-u32|-base85] [-nocompress] [-nostatic] <inputfile> <symbolname>\n", argv[0]);
|
||||||
|
printf("Source encoding types:\n");
|
||||||
|
printf(" -u8 = ~12 bytes of source per 4 bytes of data. 4 bytes in binary.\n");
|
||||||
|
printf(" -u32 = ~11 bytes of source per 4 bytes of data. 4 bytes in binary. Need endianness swapping on big-endian.\n");
|
||||||
|
printf(" -base85 = ~5 bytes of source per 4 bytes of data. 5 bytes in binary. Need decoder.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int argn = 1;
|
||||||
|
bool use_compression = true;
|
||||||
|
bool use_static = true;
|
||||||
|
SourceEncoding source_encoding = SourceEncoding_U8; // New default
|
||||||
|
while (argn < (argc - 2) && argv[argn][0] == '-')
|
||||||
|
{
|
||||||
|
if (strcmp(argv[argn], "-u8") == 0) { source_encoding = SourceEncoding_U8; argn++; }
|
||||||
|
else if (strcmp(argv[argn], "-u32") == 0) { source_encoding = SourceEncoding_U32; argn++; }
|
||||||
|
else if (strcmp(argv[argn], "-base85") == 0) { source_encoding = SourceEncoding_Base85; argn++; }
|
||||||
|
else if (strcmp(argv[argn], "-nocompress") == 0) { use_compression = false; argn++; }
|
||||||
|
else if (strcmp(argv[argn], "-nostatic") == 0) { use_static = false; argn++; }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unknown argument: '%s'\n", argv[argn]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = binary_to_compressed_c(argv[argn], argv[argn + 1], source_encoding, use_compression, use_static);
|
||||||
|
if (!ret)
|
||||||
|
fprintf(stderr, "Error opening or reading file: '%s'\n", argv[argn]);
|
||||||
|
return ret ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char Encode85Byte(unsigned int x)
|
||||||
|
{
|
||||||
|
x = (x % 85) + 35;
|
||||||
|
return (char)((x >= '\\') ? x + 1 : x);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary_to_compressed_c(const char* filename, const char* symbol, SourceEncoding source_encoding, bool use_compression, bool use_static)
|
||||||
|
{
|
||||||
|
// Read file
|
||||||
|
FILE* f = fopen(filename, "rb");
|
||||||
|
if (!f) return false;
|
||||||
|
int data_sz;
|
||||||
|
if (fseek(f, 0, SEEK_END) || (data_sz = (int)ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) { fclose(f); return false; }
|
||||||
|
char* data = new char[data_sz + 4];
|
||||||
|
if (fread(data, 1, data_sz, f) != (size_t)data_sz) { fclose(f); delete[] data; return false; }
|
||||||
|
memset((void*)(((char*)data) + data_sz), 0, 4);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
// Compress
|
||||||
|
int maxlen = data_sz + 512 + (data_sz >> 2) + sizeof(int); // total guess
|
||||||
|
char* compressed = use_compression ? new char[maxlen] : data;
|
||||||
|
int compressed_sz = use_compression ? stb_compress((stb_uchar*)compressed, (stb_uchar*)data, data_sz) : data_sz;
|
||||||
|
if (use_compression)
|
||||||
|
memset(compressed + compressed_sz, 0, maxlen - compressed_sz);
|
||||||
|
|
||||||
|
// Output as Base85 encoded
|
||||||
|
FILE* out = stdout;
|
||||||
|
fprintf(out, "// File: '%s' (%d bytes)\n", filename, (int)data_sz);
|
||||||
|
const char* static_str = use_static ? "static " : "";
|
||||||
|
const char* compressed_str = use_compression ? "compressed_" : "";
|
||||||
|
if (source_encoding == SourceEncoding_Base85)
|
||||||
|
{
|
||||||
|
fprintf(out, "// Exported using binary_to_compressed_c.exe -base85 \"%s\" %s\n", filename, symbol);
|
||||||
|
fprintf(out, "%sconst char %s_%sdata_base85[%d+1] =\n \"", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*5);
|
||||||
|
char prev_c = 0;
|
||||||
|
for (int src_i = 0; src_i < compressed_sz; src_i += 4)
|
||||||
|
{
|
||||||
|
// This is made a little more complicated by the fact that ??X sequences are interpreted as trigraphs by old C/C++ compilers. So we need to escape pairs of ??.
|
||||||
|
unsigned int d = *(unsigned int*)(compressed + src_i);
|
||||||
|
for (unsigned int n5 = 0; n5 < 5; n5++, d /= 85)
|
||||||
|
{
|
||||||
|
char c = Encode85Byte(d);
|
||||||
|
fprintf(out, (c == '?' && prev_c == '?') ? "\\%c" : "%c", c);
|
||||||
|
prev_c = c;
|
||||||
|
}
|
||||||
|
if ((src_i % 112) == 112 - 4)
|
||||||
|
fprintf(out, "\"\n \"");
|
||||||
|
}
|
||||||
|
fprintf(out, "\";\n\n");
|
||||||
|
}
|
||||||
|
else if (source_encoding == SourceEncoding_U8)
|
||||||
|
{
|
||||||
|
// As individual bytes, not subject to endianness issues.
|
||||||
|
fprintf(out, "// Exported using binary_to_compressed_c.exe -u8 \"%s\" %s\n", filename, symbol);
|
||||||
|
fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz);
|
||||||
|
fprintf(out, "%sconst unsigned char %s_%sdata[%d] =\n{", static_str, symbol, compressed_str, (int)compressed_sz);
|
||||||
|
int column = 0;
|
||||||
|
for (int i = 0; i < compressed_sz; i++)
|
||||||
|
{
|
||||||
|
unsigned char d = *(unsigned char*)(compressed + i);
|
||||||
|
if (column == 0)
|
||||||
|
fprintf(out, "\n ");
|
||||||
|
column += fprintf(out, "%d,", d);
|
||||||
|
if (column >= 180)
|
||||||
|
column = 0;
|
||||||
|
}
|
||||||
|
fprintf(out, "\n};\n\n");
|
||||||
|
}
|
||||||
|
else if (source_encoding == SourceEncoding_U32)
|
||||||
|
{
|
||||||
|
// As integers
|
||||||
|
fprintf(out, "// Exported using binary_to_compressed_c.exe -u32 \"%s\" %s\n", filename, symbol);
|
||||||
|
fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz);
|
||||||
|
fprintf(out, "%sconst unsigned int %s_%sdata[%d/4] =\n{", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*4);
|
||||||
|
int column = 0;
|
||||||
|
for (int i = 0; i < compressed_sz; i += 4)
|
||||||
|
{
|
||||||
|
unsigned int d = *(unsigned int*)(compressed + i);
|
||||||
|
if ((column++ % 14) == 0)
|
||||||
|
fprintf(out, "\n 0x%08x, ", d);
|
||||||
|
else
|
||||||
|
fprintf(out, "0x%08x, ", d);
|
||||||
|
}
|
||||||
|
fprintf(out, "\n};\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
delete[] data;
|
||||||
|
if (use_compression)
|
||||||
|
delete[] compressed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stb_compress* from stb.h - definition
|
||||||
|
|
||||||
|
//////////////////// compressor ///////////////////////
|
||||||
|
|
||||||
|
static stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen)
|
||||||
|
{
|
||||||
|
const unsigned long ADLER_MOD = 65521;
|
||||||
|
unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
|
||||||
|
unsigned long blocklen, i;
|
||||||
|
|
||||||
|
blocklen = buflen % 5552;
|
||||||
|
while (buflen) {
|
||||||
|
for (i=0; i + 7 < blocklen; i += 8) {
|
||||||
|
s1 += buffer[0], s2 += s1;
|
||||||
|
s1 += buffer[1], s2 += s1;
|
||||||
|
s1 += buffer[2], s2 += s1;
|
||||||
|
s1 += buffer[3], s2 += s1;
|
||||||
|
s1 += buffer[4], s2 += s1;
|
||||||
|
s1 += buffer[5], s2 += s1;
|
||||||
|
s1 += buffer[6], s2 += s1;
|
||||||
|
s1 += buffer[7], s2 += s1;
|
||||||
|
|
||||||
|
buffer += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < blocklen; ++i)
|
||||||
|
s1 += *buffer++, s2 += s1;
|
||||||
|
|
||||||
|
s1 %= ADLER_MOD, s2 %= ADLER_MOD;
|
||||||
|
buflen -= blocklen;
|
||||||
|
blocklen = 5552;
|
||||||
|
}
|
||||||
|
return (s2 << 16) + s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int stb_matchlen(stb_uchar *m1, stb_uchar *m2, stb_uint maxlen)
|
||||||
|
{
|
||||||
|
stb_uint i;
|
||||||
|
for (i=0; i < maxlen; ++i)
|
||||||
|
if (m1[i] != m2[i]) return i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// simple implementation that just takes the source data in a big block
|
||||||
|
|
||||||
|
static stb_uchar *stb__out;
|
||||||
|
static FILE *stb__outfile;
|
||||||
|
static stb_uint stb__outbytes;
|
||||||
|
|
||||||
|
static void stb__write(unsigned char v)
|
||||||
|
{
|
||||||
|
fputc(v, stb__outfile);
|
||||||
|
++stb__outbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v)))
|
||||||
|
#define stb_out(v) do { if (stb__out) *stb__out++ = (stb_uchar) (v); else stb__write((stb_uchar) (v)); } while (0)
|
||||||
|
|
||||||
|
static void stb_out2(stb_uint v) { stb_out(v >> 8); stb_out(v); }
|
||||||
|
static void stb_out3(stb_uint v) { stb_out(v >> 16); stb_out(v >> 8); stb_out(v); }
|
||||||
|
static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16); stb_out(v >> 8 ); stb_out(v); }
|
||||||
|
|
||||||
|
static void outliterals(stb_uchar *in, int numlit)
|
||||||
|
{
|
||||||
|
while (numlit > 65536) {
|
||||||
|
outliterals(in,65536);
|
||||||
|
in += 65536;
|
||||||
|
numlit -= 65536;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numlit == 0) ;
|
||||||
|
else if (numlit <= 32) stb_out (0x000020 + numlit-1);
|
||||||
|
else if (numlit <= 2048) stb_out2(0x000800 + numlit-1);
|
||||||
|
else /* numlit <= 65536) */ stb_out3(0x070000 + numlit-1);
|
||||||
|
|
||||||
|
if (stb__out) {
|
||||||
|
memcpy(stb__out,in,numlit);
|
||||||
|
stb__out += numlit;
|
||||||
|
} else
|
||||||
|
fwrite(in, 1, numlit, stb__outfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stb__window = 0x40000; // 256K
|
||||||
|
|
||||||
|
static int stb_not_crap(int best, int dist)
|
||||||
|
{
|
||||||
|
return ((best > 2 && dist <= 0x00100)
|
||||||
|
|| (best > 5 && dist <= 0x04000)
|
||||||
|
|| (best > 7 && dist <= 0x80000));
|
||||||
|
}
|
||||||
|
|
||||||
|
static stb_uint stb__hashsize = 32768;
|
||||||
|
|
||||||
|
// note that you can play with the hashing functions all you
|
||||||
|
// want without needing to change the decompressor
|
||||||
|
#define stb__hc(q,h,c) (((h) << 7) + ((h) >> 25) + q[c])
|
||||||
|
#define stb__hc2(q,h,c,d) (((h) << 14) + ((h) >> 18) + (q[c] << 7) + q[d])
|
||||||
|
#define stb__hc3(q,c,d,e) ((q[c] << 14) + (q[d] << 7) + q[e])
|
||||||
|
|
||||||
|
static unsigned int stb__running_adler;
|
||||||
|
|
||||||
|
static int stb_compress_chunk(stb_uchar *history,
|
||||||
|
stb_uchar *start,
|
||||||
|
stb_uchar *end,
|
||||||
|
int length,
|
||||||
|
int *pending_literals,
|
||||||
|
stb_uchar **chash,
|
||||||
|
stb_uint mask)
|
||||||
|
{
|
||||||
|
(void)history;
|
||||||
|
int window = stb__window;
|
||||||
|
stb_uint match_max;
|
||||||
|
stb_uchar *lit_start = start - *pending_literals;
|
||||||
|
stb_uchar *q = start;
|
||||||
|
|
||||||
|
#define STB__SCRAMBLE(h) (((h) + ((h) >> 16)) & mask)
|
||||||
|
|
||||||
|
// stop short of the end so we don't scan off the end doing
|
||||||
|
// the hashing; this means we won't compress the last few bytes
|
||||||
|
// unless they were part of something longer
|
||||||
|
while (q < start+length && q+12 < end) {
|
||||||
|
int m;
|
||||||
|
stb_uint h1,h2,h3,h4, h;
|
||||||
|
stb_uchar *t;
|
||||||
|
int best = 2, dist=0;
|
||||||
|
|
||||||
|
if (q+65536 > end)
|
||||||
|
match_max = (stb_uint)(end-q);
|
||||||
|
else
|
||||||
|
match_max = 65536;
|
||||||
|
|
||||||
|
#define stb__nc(b,d) ((d) <= window && ((b) > 9 || stb_not_crap((int)(b),(int)(d))))
|
||||||
|
|
||||||
|
#define STB__TRY(t,p) /* avoid retrying a match we already tried */ \
|
||||||
|
if (p ? dist != (int)(q-t) : 1) \
|
||||||
|
if ((m = stb_matchlen(t, q, match_max)) > best) \
|
||||||
|
if (stb__nc(m,q-(t))) \
|
||||||
|
best = m, dist = (int)(q - (t))
|
||||||
|
|
||||||
|
// rather than search for all matches, only try 4 candidate locations,
|
||||||
|
// chosen based on 4 different hash functions of different lengths.
|
||||||
|
// this strategy is inspired by LZO; hashing is unrolled here using the
|
||||||
|
// 'hc' macro
|
||||||
|
h = stb__hc3(q,0, 1, 2); h1 = STB__SCRAMBLE(h);
|
||||||
|
t = chash[h1]; if (t) STB__TRY(t,0);
|
||||||
|
h = stb__hc2(q,h, 3, 4); h2 = STB__SCRAMBLE(h);
|
||||||
|
h = stb__hc2(q,h, 5, 6); t = chash[h2]; if (t) STB__TRY(t,1);
|
||||||
|
h = stb__hc2(q,h, 7, 8); h3 = STB__SCRAMBLE(h);
|
||||||
|
h = stb__hc2(q,h, 9,10); t = chash[h3]; if (t) STB__TRY(t,1);
|
||||||
|
h = stb__hc2(q,h,11,12); h4 = STB__SCRAMBLE(h);
|
||||||
|
t = chash[h4]; if (t) STB__TRY(t,1);
|
||||||
|
|
||||||
|
// because we use a shared hash table, can only update it
|
||||||
|
// _after_ we've probed all of them
|
||||||
|
chash[h1] = chash[h2] = chash[h3] = chash[h4] = q;
|
||||||
|
|
||||||
|
if (best > 2)
|
||||||
|
assert(dist > 0);
|
||||||
|
|
||||||
|
// see if our best match qualifies
|
||||||
|
if (best < 3) { // fast path literals
|
||||||
|
++q;
|
||||||
|
} else if (best > 2 && best <= 0x80 && dist <= 0x100) {
|
||||||
|
outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best);
|
||||||
|
stb_out(0x80 + best-1);
|
||||||
|
stb_out(dist-1);
|
||||||
|
} else if (best > 5 && best <= 0x100 && dist <= 0x4000) {
|
||||||
|
outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best);
|
||||||
|
stb_out2(0x4000 + dist-1);
|
||||||
|
stb_out(best-1);
|
||||||
|
} else if (best > 7 && best <= 0x100 && dist <= 0x80000) {
|
||||||
|
outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best);
|
||||||
|
stb_out3(0x180000 + dist-1);
|
||||||
|
stb_out(best-1);
|
||||||
|
} else if (best > 8 && best <= 0x10000 && dist <= 0x80000) {
|
||||||
|
outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best);
|
||||||
|
stb_out3(0x100000 + dist-1);
|
||||||
|
stb_out2(best-1);
|
||||||
|
} else if (best > 9 && dist <= 0x1000000) {
|
||||||
|
if (best > 65536) best = 65536;
|
||||||
|
outliterals(lit_start, (int)(q-lit_start)); lit_start = (q += best);
|
||||||
|
if (best <= 0x100) {
|
||||||
|
stb_out(0x06);
|
||||||
|
stb_out3(dist-1);
|
||||||
|
stb_out(best-1);
|
||||||
|
} else {
|
||||||
|
stb_out(0x04);
|
||||||
|
stb_out3(dist-1);
|
||||||
|
stb_out2(best-1);
|
||||||
|
}
|
||||||
|
} else { // fallback literals if no match was a balanced tradeoff
|
||||||
|
++q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we didn't get all the way, add the rest to literals
|
||||||
|
if (q-start < length)
|
||||||
|
q = start+length;
|
||||||
|
|
||||||
|
// the literals are everything from lit_start to q
|
||||||
|
*pending_literals = (int)(q - lit_start);
|
||||||
|
|
||||||
|
stb__running_adler = stb_adler32(stb__running_adler, start, (stb_uint)(q - start));
|
||||||
|
return (int)(q - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stb_compress_inner(stb_uchar *input, stb_uint length)
|
||||||
|
{
|
||||||
|
int literals = 0;
|
||||||
|
stb_uint len,i;
|
||||||
|
|
||||||
|
stb_uchar **chash;
|
||||||
|
chash = (stb_uchar**) malloc(stb__hashsize * sizeof(stb_uchar*));
|
||||||
|
if (chash == nullptr) return 0; // failure
|
||||||
|
for (i=0; i < stb__hashsize; ++i)
|
||||||
|
chash[i] = nullptr;
|
||||||
|
|
||||||
|
// stream signature
|
||||||
|
stb_out(0x57); stb_out(0xbc);
|
||||||
|
stb_out2(0);
|
||||||
|
|
||||||
|
stb_out4(0); // 64-bit length requires 32-bit leading 0
|
||||||
|
stb_out4(length);
|
||||||
|
stb_out4(stb__window);
|
||||||
|
|
||||||
|
stb__running_adler = 1;
|
||||||
|
|
||||||
|
len = stb_compress_chunk(input, input, input+length, length, &literals, chash, stb__hashsize-1);
|
||||||
|
assert(len == length);
|
||||||
|
|
||||||
|
outliterals(input+length - literals, literals);
|
||||||
|
|
||||||
|
free(chash);
|
||||||
|
|
||||||
|
stb_out2(0x05fa); // end opcode
|
||||||
|
|
||||||
|
stb_out4(stb__running_adler);
|
||||||
|
|
||||||
|
return 1; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
stb_uint stb_compress(stb_uchar *out, stb_uchar *input, stb_uint length)
|
||||||
|
{
|
||||||
|
stb__out = out;
|
||||||
|
stb__outfile = nullptr;
|
||||||
|
|
||||||
|
stb_compress_inner(input, length);
|
||||||
|
|
||||||
|
return (stb_uint)(stb__out - out);
|
||||||
|
}
|
||||||
54
Editor/imgui/misc/freetype/README.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# imgui_freetype
|
||||||
|
|
||||||
|
Build font atlases using FreeType instead of stb_truetype (which is the default font rasterizer).
|
||||||
|
<br>by @vuhdo, @mikesart, @ocornut.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype --triplet=x64-windows`, `vcpkg integrate install`).
|
||||||
|
2. Add imgui_freetype.h/cpp alongside your project files.
|
||||||
|
3. Add `#define IMGUI_ENABLE_FREETYPE` in your [imconfig.h](https://github.com/ocornut/imgui/blob/master/imconfig.h) file
|
||||||
|
|
||||||
|
### About Gamma Correct Blending
|
||||||
|
|
||||||
|
FreeType assumes blending in linear space rather than gamma space.
|
||||||
|
See FreeType note for [FT_Render_Glyph](https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_render_glyph).
|
||||||
|
For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
||||||
|
The default Dear ImGui styles will be impacted by this change (alpha values will need tweaking).
|
||||||
|
|
||||||
|
### Testbed for toying with settings (for developers)
|
||||||
|
|
||||||
|
See https://gist.github.com/ocornut/b3a9ecf13502fd818799a452969649ad
|
||||||
|
|
||||||
|
### Known issues
|
||||||
|
|
||||||
|
- Oversampling settings are ignored but also not so much necessary with the higher quality rendering.
|
||||||
|
|
||||||
|
### Comparison
|
||||||
|
|
||||||
|
Small, thin anti-aliased fonts typically benefit a lot from FreeType's hinting:
|
||||||
|

|
||||||
|
|
||||||
|
### Colorful glyphs/emojis
|
||||||
|
|
||||||
|
You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain colorful glyphs. See the
|
||||||
|
["Using Colorful Glyphs/Emojis"](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md#using-colorful-glyphsemojis) section of FONTS.md.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Using OpenType SVG fonts (SVGinOT)
|
||||||
|
- *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations.
|
||||||
|
- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT.
|
||||||
|
- Two alternatives are possible to render SVG fonts: use "lunasvg" or "plutosvg". plutosvg will support some more fonts (e.g. NotoColorEmoji-Regular) and may load them faster.
|
||||||
|
|
||||||
|
#### Using lunasvg
|
||||||
|
Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above
|
||||||
|
- Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`.
|
||||||
|
- Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`.
|
||||||
|
|
||||||
|
#### Using plutosvg (and plutovg)
|
||||||
|
- Add `#define IMGUI_ENABLE_FREETYPE_PLUTOSVG` in your `imconfig.h`.
|
||||||
|
- Get latest plutosvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install plutosvg --triplet=x64-windows`. Alternatively, if you build imgui from vcpkg, you just need to enable the plutosvg feature: `vcpkg install imgui[plutosvg] --triplet=x64-windows`
|
||||||
|
- If you prefer to build plutosvg manually:
|
||||||
|
- Compilation hints for plutovg: Compile all source files in `plutovg/source/*.c` + Add include directory: `plutovg/include` + `plutovg/stb`
|
||||||
|
- Compilation hints for plutosvg: Compile `plutosvg/source/plutosvg.c` + Add include directory: `plutosvg/source` + Add define: `PLUTOSVG_HAS_FREETYPE` + Link with: plutovg, freetype
|
||||||
987
Editor/imgui/misc/freetype/imgui_freetype.cpp
Normal file
@@ -0,0 +1,987 @@
|
|||||||
|
// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)
|
||||||
|
// (code)
|
||||||
|
|
||||||
|
// Get the latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
|
||||||
|
// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained since 2019 by @ocornut.
|
||||||
|
|
||||||
|
// CHANGELOG
|
||||||
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2024/10/17: added plutosvg support for SVG Fonts (seems faster/better than lunasvg). Enable by using '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG'. (#7927)
|
||||||
|
// 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics.
|
||||||
|
// 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG'. (#6591)
|
||||||
|
// 2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly.
|
||||||
|
// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns nullptr.
|
||||||
|
// 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs.
|
||||||
|
// 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a preferred texture format.
|
||||||
|
// 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+).
|
||||||
|
// 2021/01/26: simplified integration by using '#define IMGUI_ENABLE_FREETYPE'. renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. removed ImGuiFreeType::BuildFontAtlas().
|
||||||
|
// 2020/06/04: fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails.
|
||||||
|
// 2019/02/09: added RasterizerFlags::Monochrome flag to disable font anti-aliasing (combine with ::MonoHinting for best results!)
|
||||||
|
// 2019/01/15: added support for imgui allocators + added FreeType only override function SetAllocatorFunctions().
|
||||||
|
// 2019/01/10: re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.
|
||||||
|
// 2018/06/08: added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX.
|
||||||
|
// 2018/02/04: moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
|
||||||
|
// 2018/01/22: fix for addition of ImFontAtlas::TexUvscale member.
|
||||||
|
// 2017/10/22: minor inconsequential change to match change in master (removed an unnecessary statement).
|
||||||
|
// 2017/09/26: fixes for imgui internal changes.
|
||||||
|
// 2017/08/26: cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply.
|
||||||
|
// 2017/08/16: imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
|
||||||
|
|
||||||
|
// About Gamma Correct Blending:
|
||||||
|
// - FreeType assumes blending in linear space rather than gamma space.
|
||||||
|
// - See https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph
|
||||||
|
// - For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
|
||||||
|
// - The default dear imgui styles will be impacted by this change (alpha values will need tweaking).
|
||||||
|
|
||||||
|
// FIXME: cfg.OversampleH, OversampleV are not supported, but generally not necessary with this rasterizer because Hinting makes everything look better.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui_freetype.h"
|
||||||
|
#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H // <freetype/freetype.h>
|
||||||
|
#include FT_MODULE_H // <freetype/ftmodapi.h>
|
||||||
|
#include FT_GLYPH_H // <freetype/ftglyph.h>
|
||||||
|
#include FT_SYNTHESIS_H // <freetype/ftsynth.h>
|
||||||
|
|
||||||
|
// Handle LunaSVG and PlutoSVG
|
||||||
|
#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) && defined(IMGUI_ENABLE_FREETYPE_PLUTOSVG)
|
||||||
|
#error "Cannot enable both IMGUI_ENABLE_FREETYPE_LUNASVG and IMGUI_ENABLE_FREETYPE_PLUTOSVG"
|
||||||
|
#endif
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
#include FT_OTSVG_H // <freetype/otsvg.h>
|
||||||
|
#include FT_BBOX_H // <freetype/ftbbox.h>
|
||||||
|
#include <lunasvg.h>
|
||||||
|
#endif
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||||
|
#include <plutosvg.h>
|
||||||
|
#endif
|
||||||
|
#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) || defined (IMGUI_ENABLE_FREETYPE_PLUTOSVG)
|
||||||
|
#if !((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12))
|
||||||
|
#error IMGUI_ENABLE_FREETYPE_PLUTOSVG or IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||||
|
#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||||
|
#ifndef __clang__
|
||||||
|
#pragma GCC diagnostic ignored "-Wsubobject-linkage" // warning: 'xxxx' has a field 'xxxx' whose type uses the anonymous namespace
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Data
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Default memory allocators
|
||||||
|
static void* ImGuiFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return IM_ALLOC(size); }
|
||||||
|
static void ImGuiFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_FREE(ptr); }
|
||||||
|
|
||||||
|
// Current memory allocators
|
||||||
|
static void* (*GImGuiFreeTypeAllocFunc)(size_t size, void* user_data) = ImGuiFreeTypeDefaultAllocFunc;
|
||||||
|
static void (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc;
|
||||||
|
static void* GImGuiFreeTypeAllocatorUserData = nullptr;
|
||||||
|
|
||||||
|
// Lunasvg support
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
static FT_Error ImGuiLunasvgPortInit(FT_Pointer* state);
|
||||||
|
static void ImGuiLunasvgPortFree(FT_Pointer* state);
|
||||||
|
static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state);
|
||||||
|
static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Code
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define FT_CEIL(X) (((X + 63) & -64) / 64) // From SDL_ttf: Handy routines for converting from fixed point
|
||||||
|
#define FT_SCALEFACTOR 64.0f
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Glyph metrics:
|
||||||
|
// --------------
|
||||||
|
//
|
||||||
|
// xmin xmax
|
||||||
|
// | |
|
||||||
|
// |<-------- width -------->|
|
||||||
|
// | |
|
||||||
|
// | +-------------------------+----------------- ymax
|
||||||
|
// | | ggggggggg ggggg | ^ ^
|
||||||
|
// | | g:::::::::ggg::::g | | |
|
||||||
|
// | | g:::::::::::::::::g | | |
|
||||||
|
// | | g::::::ggggg::::::gg | | |
|
||||||
|
// | | g:::::g g:::::g | | |
|
||||||
|
// offsetX -|-------->| g:::::g g:::::g | offsetY |
|
||||||
|
// | | g:::::g g:::::g | | |
|
||||||
|
// | | g::::::g g:::::g | | |
|
||||||
|
// | | g:::::::ggggg:::::g | | |
|
||||||
|
// | | g::::::::::::::::g | | height
|
||||||
|
// | | gg::::::::::::::g | | |
|
||||||
|
// baseline ---*---------|---- gggggggg::::::g-----*-------- |
|
||||||
|
// / | | g:::::g | |
|
||||||
|
// origin | | gggggg g:::::g | |
|
||||||
|
// | | g:::::gg gg:::::g | |
|
||||||
|
// | | g::::::ggg:::::::g | |
|
||||||
|
// | | gg:::::::::::::g | |
|
||||||
|
// | | ggg::::::ggg | |
|
||||||
|
// | | gggggg | v
|
||||||
|
// | +-------------------------+----------------- ymin
|
||||||
|
// | |
|
||||||
|
// |------------- advanceX ----------->|
|
||||||
|
|
||||||
|
// A structure that describe a glyph.
|
||||||
|
struct GlyphInfo
|
||||||
|
{
|
||||||
|
int Width; // Glyph's width in pixels.
|
||||||
|
int Height; // Glyph's height in pixels.
|
||||||
|
FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
|
||||||
|
FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
|
||||||
|
float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
|
||||||
|
bool IsColored; // The glyph is colored
|
||||||
|
};
|
||||||
|
|
||||||
|
// Font parameters and metrics.
|
||||||
|
struct FontInfo
|
||||||
|
{
|
||||||
|
uint32_t PixelHeight; // Size this font was generated with.
|
||||||
|
float Ascender; // The pixel extents above the baseline in pixels (typically positive).
|
||||||
|
float Descender; // The extents below the baseline in pixels (typically negative).
|
||||||
|
float LineSpacing; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate.
|
||||||
|
float LineGap; // The spacing in pixels between one row's descent and the next row's ascent.
|
||||||
|
float MaxAdvanceWidth; // This field gives the maximum horizontal cursor advance for all glyphs in the font.
|
||||||
|
};
|
||||||
|
|
||||||
|
// FreeType glyph rasterizer.
|
||||||
|
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
|
||||||
|
struct FreeTypeFont
|
||||||
|
{
|
||||||
|
bool InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
|
||||||
|
void CloseFont();
|
||||||
|
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
|
||||||
|
const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
|
||||||
|
const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);
|
||||||
|
void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr);
|
||||||
|
FreeTypeFont() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
~FreeTypeFont() { CloseFont(); }
|
||||||
|
|
||||||
|
// [Internals]
|
||||||
|
FontInfo Info; // Font descriptor of the current font.
|
||||||
|
FT_Face Face;
|
||||||
|
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
|
||||||
|
FT_Int32 LoadFlags;
|
||||||
|
FT_Render_Mode RenderMode;
|
||||||
|
float RasterizationDensity;
|
||||||
|
float InvRasterizationDensity;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_font_builder_flags)
|
||||||
|
{
|
||||||
|
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src.FontData, (uint32_t)src.FontDataSize, (uint32_t)src.FontNo, &Face);
|
||||||
|
if (error != 0)
|
||||||
|
return false;
|
||||||
|
error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
|
||||||
|
if (error != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Convert to FreeType flags (NB: Bold and Oblique are processed separately)
|
||||||
|
UserFlags = src.FontBuilderFlags | extra_font_builder_flags;
|
||||||
|
|
||||||
|
LoadFlags = 0;
|
||||||
|
if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0)
|
||||||
|
LoadFlags |= FT_LOAD_NO_BITMAP;
|
||||||
|
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_NoHinting)
|
||||||
|
LoadFlags |= FT_LOAD_NO_HINTING;
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_NoAutoHint)
|
||||||
|
LoadFlags |= FT_LOAD_NO_AUTOHINT;
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_ForceAutoHint)
|
||||||
|
LoadFlags |= FT_LOAD_FORCE_AUTOHINT;
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_LightHinting)
|
||||||
|
LoadFlags |= FT_LOAD_TARGET_LIGHT;
|
||||||
|
else if (UserFlags & ImGuiFreeTypeBuilderFlags_MonoHinting)
|
||||||
|
LoadFlags |= FT_LOAD_TARGET_MONO;
|
||||||
|
else
|
||||||
|
LoadFlags |= FT_LOAD_TARGET_NORMAL;
|
||||||
|
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_Monochrome)
|
||||||
|
RenderMode = FT_RENDER_MODE_MONO;
|
||||||
|
else
|
||||||
|
RenderMode = FT_RENDER_MODE_NORMAL;
|
||||||
|
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor)
|
||||||
|
LoadFlags |= FT_LOAD_COLOR;
|
||||||
|
|
||||||
|
RasterizationDensity = src.RasterizerDensity;
|
||||||
|
InvRasterizationDensity = 1.0f / RasterizationDensity;
|
||||||
|
|
||||||
|
memset(&Info, 0, sizeof(Info));
|
||||||
|
SetPixelHeight((uint32_t)src.SizePixels);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeTypeFont::CloseFont()
|
||||||
|
{
|
||||||
|
if (Face)
|
||||||
|
{
|
||||||
|
FT_Done_Face(Face);
|
||||||
|
Face = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeTypeFont::SetPixelHeight(int pixel_height)
|
||||||
|
{
|
||||||
|
// Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
|
||||||
|
// is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
|
||||||
|
// NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result.
|
||||||
|
FT_Size_RequestRec req;
|
||||||
|
req.type = (UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||||
|
req.width = 0;
|
||||||
|
req.height = (uint32_t)(pixel_height * 64 * RasterizationDensity);
|
||||||
|
req.horiResolution = 0;
|
||||||
|
req.vertResolution = 0;
|
||||||
|
FT_Request_Size(Face, &req);
|
||||||
|
|
||||||
|
// Update font info
|
||||||
|
FT_Size_Metrics metrics = Face->size->metrics;
|
||||||
|
Info.PixelHeight = (uint32_t)(pixel_height * InvRasterizationDensity);
|
||||||
|
Info.Ascender = (float)FT_CEIL(metrics.ascender) * InvRasterizationDensity;
|
||||||
|
Info.Descender = (float)FT_CEIL(metrics.descender) * InvRasterizationDensity;
|
||||||
|
Info.LineSpacing = (float)FT_CEIL(metrics.height) * InvRasterizationDensity;
|
||||||
|
Info.LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * InvRasterizationDensity;
|
||||||
|
Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * InvRasterizationDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint)
|
||||||
|
{
|
||||||
|
uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);
|
||||||
|
if (glyph_index == 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
|
||||||
|
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
|
||||||
|
// - https://github.com/ocornut/imgui/issues/4567
|
||||||
|
// - https://github.com/ocornut/imgui/issues/4566
|
||||||
|
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
|
||||||
|
FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
|
||||||
|
if (error)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Need an outline for this to work
|
||||||
|
FT_GlyphSlot slot = Face->glyph;
|
||||||
|
#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) || defined(IMGUI_ENABLE_FREETYPE_PLUTOSVG)
|
||||||
|
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG);
|
||||||
|
#else
|
||||||
|
#if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12))
|
||||||
|
IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_PLUTOSVG or IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font");
|
||||||
|
#endif
|
||||||
|
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP);
|
||||||
|
#endif // IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
|
// Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting)
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_Bold)
|
||||||
|
FT_GlyphSlot_Embolden(slot);
|
||||||
|
if (UserFlags & ImGuiFreeTypeBuilderFlags_Oblique)
|
||||||
|
{
|
||||||
|
FT_GlyphSlot_Oblique(slot);
|
||||||
|
//FT_BBox bbox;
|
||||||
|
//FT_Outline_Get_BBox(&slot->outline, &bbox);
|
||||||
|
//slot->metrics.width = bbox.xMax - bbox.xMin;
|
||||||
|
//slot->metrics.height = bbox.yMax - bbox.yMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &slot->metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
|
||||||
|
{
|
||||||
|
FT_GlyphSlot slot = Face->glyph;
|
||||||
|
FT_Error error = FT_Render_Glyph(slot, RenderMode);
|
||||||
|
if (error != 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
FT_Bitmap* ft_bitmap = &Face->glyph->bitmap;
|
||||||
|
out_glyph_info->Width = (int)ft_bitmap->width;
|
||||||
|
out_glyph_info->Height = (int)ft_bitmap->rows;
|
||||||
|
out_glyph_info->OffsetX = Face->glyph->bitmap_left;
|
||||||
|
out_glyph_info->OffsetY = -Face->glyph->bitmap_top;
|
||||||
|
out_glyph_info->AdvanceX = (float)slot->advance.x / FT_SCALEFACTOR;
|
||||||
|
out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);
|
||||||
|
|
||||||
|
return ft_bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
|
||||||
|
{
|
||||||
|
IM_ASSERT(ft_bitmap != nullptr);
|
||||||
|
const uint32_t w = ft_bitmap->width;
|
||||||
|
const uint32_t h = ft_bitmap->rows;
|
||||||
|
const uint8_t* src = ft_bitmap->buffer;
|
||||||
|
const uint32_t src_pitch = ft_bitmap->pitch;
|
||||||
|
|
||||||
|
switch (ft_bitmap->pixel_mode)
|
||||||
|
{
|
||||||
|
case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel.
|
||||||
|
{
|
||||||
|
if (multiply_table == nullptr)
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
for (uint32_t x = 0; x < w; x++)
|
||||||
|
dst[x] = IM_COL32(255, 255, 255, src[x]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
for (uint32_t x = 0; x < w; x++)
|
||||||
|
dst[x] = IM_COL32(255, 255, 255, multiply_table[src[x]]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB.
|
||||||
|
{
|
||||||
|
uint8_t color0 = multiply_table ? multiply_table[0] : 0;
|
||||||
|
uint8_t color1 = multiply_table ? multiply_table[255] : 255;
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
{
|
||||||
|
uint8_t bits = 0;
|
||||||
|
const uint8_t* bits_ptr = src;
|
||||||
|
for (uint32_t x = 0; x < w; x++, bits <<= 1)
|
||||||
|
{
|
||||||
|
if ((x & 7) == 0)
|
||||||
|
bits = *bits_ptr++;
|
||||||
|
dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? color1 : color0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FT_PIXEL_MODE_BGRA:
|
||||||
|
{
|
||||||
|
// FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good.
|
||||||
|
#define DE_MULTIPLY(color, alpha) ImMin((ImU32)(255.0f * (float)color / (float)(alpha + FLT_MIN) + 0.5f), 255u)
|
||||||
|
if (multiply_table == nullptr)
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
for (uint32_t x = 0; x < w; x++)
|
||||||
|
{
|
||||||
|
uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
||||||
|
dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
||||||
|
{
|
||||||
|
for (uint32_t x = 0; x < w; x++)
|
||||||
|
{
|
||||||
|
uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
||||||
|
dst[x] = IM_COL32(multiply_table[DE_MULTIPLY(r, a)], multiply_table[DE_MULTIPLY(g, a)], multiply_table[DE_MULTIPLY(b, a)], multiply_table[a]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef DE_MULTIPLY
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
|
||||||
|
#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0)
|
||||||
|
#define STBRP_STATIC
|
||||||
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#endif
|
||||||
|
#ifdef IMGUI_STB_RECT_PACK_FILENAME
|
||||||
|
#include IMGUI_STB_RECT_PACK_FILENAME
|
||||||
|
#else
|
||||||
|
#include "imstb_rectpack.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ImFontBuildSrcGlyphFT
|
||||||
|
{
|
||||||
|
GlyphInfo Info;
|
||||||
|
uint32_t Codepoint;
|
||||||
|
unsigned int* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array
|
||||||
|
|
||||||
|
ImFontBuildSrcGlyphFT() { memset((void*)this, 0, sizeof(*this)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImFontBuildSrcDataFT
|
||||||
|
{
|
||||||
|
FreeTypeFont Font;
|
||||||
|
stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
|
||||||
|
const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
|
||||||
|
int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
|
||||||
|
int GlyphsHighest; // Highest requested codepoint
|
||||||
|
int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
|
||||||
|
ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
|
||||||
|
ImVector<ImFontBuildSrcGlyphFT> GlyphsList;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
|
||||||
|
struct ImFontBuildDstDataFT
|
||||||
|
{
|
||||||
|
int SrcCount; // Number of source fonts targeting this destination font.
|
||||||
|
int GlyphsHighest;
|
||||||
|
int GlyphsCount;
|
||||||
|
ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
|
||||||
|
{
|
||||||
|
IM_ASSERT(atlas->Sources.Size > 0);
|
||||||
|
|
||||||
|
ImFontAtlasBuildInit(atlas);
|
||||||
|
|
||||||
|
// Clear atlas
|
||||||
|
atlas->TexID = 0;
|
||||||
|
atlas->TexWidth = atlas->TexHeight = 0;
|
||||||
|
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
||||||
|
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
||||||
|
atlas->ClearTexData();
|
||||||
|
|
||||||
|
// Temporary storage for building
|
||||||
|
bool src_load_color = false;
|
||||||
|
ImVector<ImFontBuildSrcDataFT> src_tmp_array;
|
||||||
|
ImVector<ImFontBuildDstDataFT> dst_tmp_array;
|
||||||
|
src_tmp_array.resize(atlas->Sources.Size);
|
||||||
|
dst_tmp_array.resize(atlas->Fonts.Size);
|
||||||
|
memset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
||||||
|
memset((void*)dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
||||||
|
|
||||||
|
// 1. Initialize font loading structure, check font data validity
|
||||||
|
for (int src_i = 0; src_i < atlas->Sources.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontConfig& src = atlas->Sources[src_i];
|
||||||
|
FreeTypeFont& font_face = src_tmp.Font;
|
||||||
|
IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas));
|
||||||
|
|
||||||
|
// Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
||||||
|
src_tmp.DstIndex = -1;
|
||||||
|
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
||||||
|
if (src.DstFont == atlas->Fonts[output_i])
|
||||||
|
src_tmp.DstIndex = output_i;
|
||||||
|
IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array?
|
||||||
|
if (src_tmp.DstIndex == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Load font
|
||||||
|
if (!font_face.InitFont(ft_library, src, extra_flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Measure highest codepoints
|
||||||
|
src_load_color |= (src.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;
|
||||||
|
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||||
|
src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||||
|
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||||
|
{
|
||||||
|
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||||
|
// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent,
|
||||||
|
// or to forget to zero-terminate the glyph range array.
|
||||||
|
IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?");
|
||||||
|
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
|
||||||
|
}
|
||||||
|
dst_tmp.SrcCount++;
|
||||||
|
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
|
||||||
|
int total_glyphs_count = 0;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||||
|
src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);
|
||||||
|
if (dst_tmp.GlyphsSet.Storage.empty())
|
||||||
|
dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);
|
||||||
|
|
||||||
|
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||||
|
for (int codepoint = src_range[0]; codepoint <= (int)src_range[1]; codepoint++)
|
||||||
|
{
|
||||||
|
if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
|
||||||
|
continue;
|
||||||
|
uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)
|
||||||
|
if (glyph_index == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Add to avail set/counters
|
||||||
|
src_tmp.GlyphsCount++;
|
||||||
|
dst_tmp.GlyphsCount++;
|
||||||
|
src_tmp.GlyphsSet.SetBit(codepoint);
|
||||||
|
dst_tmp.GlyphsSet.SetBit(codepoint);
|
||||||
|
total_glyphs_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
|
||||||
|
|
||||||
|
IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(ImU32));
|
||||||
|
const ImU32* it_begin = src_tmp.GlyphsSet.Storage.begin();
|
||||||
|
const ImU32* it_end = src_tmp.GlyphsSet.Storage.end();
|
||||||
|
for (const ImU32* it = it_begin; it < it_end; it++)
|
||||||
|
if (ImU32 entries_32 = *it)
|
||||||
|
for (ImU32 bit_n = 0; bit_n < 32; bit_n++)
|
||||||
|
if (entries_32 & ((ImU32)1 << bit_n))
|
||||||
|
{
|
||||||
|
ImFontBuildSrcGlyphFT src_glyph;
|
||||||
|
src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n);
|
||||||
|
//src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it..
|
||||||
|
src_tmp.GlyphsList.push_back(src_glyph);
|
||||||
|
}
|
||||||
|
src_tmp.GlyphsSet.Clear();
|
||||||
|
IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
|
||||||
|
}
|
||||||
|
for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
|
||||||
|
dst_tmp_array[dst_i].GlyphsSet.Clear();
|
||||||
|
dst_tmp_array.clear();
|
||||||
|
|
||||||
|
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
|
||||||
|
// (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
|
||||||
|
ImVector<stbrp_rect> buf_rects;
|
||||||
|
buf_rects.resize(total_glyphs_count);
|
||||||
|
memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
|
||||||
|
|
||||||
|
// Allocate temporary rasterization data buffers.
|
||||||
|
// We could not find a way to retrieve accurate glyph size without rendering them.
|
||||||
|
// (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)
|
||||||
|
// We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't mind the temporary allocations.
|
||||||
|
const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
|
||||||
|
int buf_bitmap_current_used_bytes = 0;
|
||||||
|
ImVector<unsigned char*> buf_bitmap_buffers;
|
||||||
|
buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
|
||||||
|
|
||||||
|
// 4. Gather glyphs sizes so we can pack them in our virtual canvas.
|
||||||
|
// 8. Render/rasterize font characters into the texture
|
||||||
|
int total_surface = 0;
|
||||||
|
int buf_rects_out_n = 0;
|
||||||
|
const int pack_padding = atlas->TexGlyphPadding;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
ImFontConfig& src = atlas->Sources[src_i];
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
src_tmp.Rects = &buf_rects[buf_rects_out_n];
|
||||||
|
buf_rects_out_n += src_tmp.GlyphsCount;
|
||||||
|
|
||||||
|
// Compute multiply table if requested
|
||||||
|
const bool multiply_enabled = (src.RasterizerMultiply != 1.0f);
|
||||||
|
unsigned char multiply_table[256];
|
||||||
|
if (multiply_enabled)
|
||||||
|
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply);
|
||||||
|
|
||||||
|
// Gather the sizes of all rectangles we will need to pack
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
||||||
|
|
||||||
|
const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint);
|
||||||
|
if (metrics == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Render glyph into a bitmap (currently held by FreeType)
|
||||||
|
const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
|
||||||
|
if (ft_bitmap == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Allocate new temporary chunk if needed
|
||||||
|
const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4;
|
||||||
|
if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
buf_bitmap_current_used_bytes = 0;
|
||||||
|
buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
|
||||||
|
}
|
||||||
|
IM_ASSERT(buf_bitmap_current_used_bytes + bitmap_size_in_bytes <= BITMAP_BUFFERS_CHUNK_SIZE); // We could probably allocate custom-sized buffer instead.
|
||||||
|
|
||||||
|
// Blit rasterized pixels to our temporary buffer and keep a pointer to it.
|
||||||
|
src_glyph.BitmapData = (unsigned int*)(buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes);
|
||||||
|
buf_bitmap_current_used_bytes += bitmap_size_in_bytes;
|
||||||
|
src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : nullptr);
|
||||||
|
|
||||||
|
src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + pack_padding);
|
||||||
|
src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + pack_padding);
|
||||||
|
total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < atlas->CustomRects.Size; i++)
|
||||||
|
total_surface += (atlas->CustomRects[i].Width + pack_padding) * (atlas->CustomRects[i].Height + pack_padding);
|
||||||
|
|
||||||
|
// We need a width for the skyline algorithm, any width!
|
||||||
|
// The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
||||||
|
// User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
|
||||||
|
const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
|
||||||
|
atlas->TexHeight = 0;
|
||||||
|
if (atlas->TexDesiredWidth > 0)
|
||||||
|
atlas->TexWidth = atlas->TexDesiredWidth;
|
||||||
|
else
|
||||||
|
atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;
|
||||||
|
|
||||||
|
// 5. Start packing
|
||||||
|
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
||||||
|
const int TEX_HEIGHT_MAX = 1024 * 32;
|
||||||
|
const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding;
|
||||||
|
ImVector<stbrp_node> pack_nodes;
|
||||||
|
pack_nodes.resize(num_nodes_for_packing_algorithm);
|
||||||
|
stbrp_context pack_context;
|
||||||
|
stbrp_init_target(&pack_context, atlas->TexWidth - atlas->TexGlyphPadding, TEX_HEIGHT_MAX - atlas->TexGlyphPadding, pack_nodes.Data, pack_nodes.Size);
|
||||||
|
ImFontAtlasBuildPackCustomRects(atlas, &pack_context);
|
||||||
|
|
||||||
|
// 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount);
|
||||||
|
|
||||||
|
// Extend texture height and mark missing glyphs as non-packed so we won't render them.
|
||||||
|
// FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||||
|
if (src_tmp.Rects[glyph_i].was_packed)
|
||||||
|
atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Allocate texture
|
||||||
|
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
|
||||||
|
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
||||||
|
if (src_load_color)
|
||||||
|
{
|
||||||
|
size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 4;
|
||||||
|
atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(tex_size);
|
||||||
|
memset(atlas->TexPixelsRGBA32, 0, tex_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 1;
|
||||||
|
atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(tex_size);
|
||||||
|
memset(atlas->TexPixelsAlpha8, 0, tex_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. Copy rasterized font characters back into the main texture
|
||||||
|
// 9. Setup ImFont and glyphs for runtime
|
||||||
|
bool tex_use_colors = false;
|
||||||
|
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
||||||
|
|
||||||
|
// When merging fonts with MergeMode=true:
|
||||||
|
// - We can have multiple input fonts writing into a same destination font.
|
||||||
|
// - dst_font->Sources is != from src which is our source configuration.
|
||||||
|
ImFontConfig& src = atlas->Sources[src_i];
|
||||||
|
ImFont* dst_font = src.DstFont;
|
||||||
|
|
||||||
|
const float ascent = src_tmp.Font.Info.Ascender;
|
||||||
|
const float descent = src_tmp.Font.Info.Descender;
|
||||||
|
ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent);
|
||||||
|
|
||||||
|
if (src_tmp.GlyphsCount == 0)
|
||||||
|
continue;
|
||||||
|
const float font_off_x = src.GlyphOffset.x;
|
||||||
|
const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||||
|
|
||||||
|
const int padding = atlas->TexGlyphPadding;
|
||||||
|
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||||
|
{
|
||||||
|
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
||||||
|
stbrp_rect& pack_rect = src_tmp.Rects[glyph_i];
|
||||||
|
IM_ASSERT(pack_rect.was_packed);
|
||||||
|
if (pack_rect.w == 0 && pack_rect.h == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
GlyphInfo& info = src_glyph.Info;
|
||||||
|
IM_ASSERT(info.Width + padding <= pack_rect.w);
|
||||||
|
IM_ASSERT(info.Height + padding <= pack_rect.h);
|
||||||
|
const int tx = pack_rect.x + padding;
|
||||||
|
const int ty = pack_rect.y + padding;
|
||||||
|
|
||||||
|
// Register glyph
|
||||||
|
float x0 = info.OffsetX * src_tmp.Font.InvRasterizationDensity + font_off_x;
|
||||||
|
float y0 = info.OffsetY * src_tmp.Font.InvRasterizationDensity + font_off_y;
|
||||||
|
float x1 = x0 + info.Width * src_tmp.Font.InvRasterizationDensity;
|
||||||
|
float y1 = y0 + info.Height * src_tmp.Font.InvRasterizationDensity;
|
||||||
|
float u0 = (tx) / (float)atlas->TexWidth;
|
||||||
|
float v0 = (ty) / (float)atlas->TexHeight;
|
||||||
|
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
||||||
|
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
||||||
|
dst_font->AddGlyph(&src, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity);
|
||||||
|
|
||||||
|
ImFontGlyph* dst_glyph = &dst_font->Glyphs.back();
|
||||||
|
IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);
|
||||||
|
if (src_glyph.Info.IsColored)
|
||||||
|
dst_glyph->Colored = tex_use_colors = true;
|
||||||
|
|
||||||
|
// Blit from temporary buffer to final texture
|
||||||
|
size_t blit_src_stride = (size_t)src_glyph.Info.Width;
|
||||||
|
size_t blit_dst_stride = (size_t)atlas->TexWidth;
|
||||||
|
unsigned int* blit_src = src_glyph.BitmapData;
|
||||||
|
if (atlas->TexPixelsAlpha8 != nullptr)
|
||||||
|
{
|
||||||
|
unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;
|
||||||
|
for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
||||||
|
for (int x = 0; x < info.Width; x++)
|
||||||
|
blit_dst[x] = (unsigned char)((blit_src[x] >> IM_COL32_A_SHIFT) & 0xFF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int* blit_dst = atlas->TexPixelsRGBA32 + (ty * blit_dst_stride) + tx;
|
||||||
|
for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
||||||
|
for (int x = 0; x < info.Width; x++)
|
||||||
|
blit_dst[x] = blit_src[x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src_tmp.Rects = nullptr;
|
||||||
|
}
|
||||||
|
atlas->TexPixelsUseColors = tex_use_colors;
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
|
||||||
|
IM_FREE(buf_bitmap_buffers[buf_i]);
|
||||||
|
src_tmp_array.clear_destruct();
|
||||||
|
|
||||||
|
ImFontAtlasBuildFinish(atlas);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FreeType memory allocation callbacks
|
||||||
|
static void* FreeType_Alloc(FT_Memory /*memory*/, long size)
|
||||||
|
{
|
||||||
|
return GImGuiFreeTypeAllocFunc((size_t)size, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeType_Free(FT_Memory /*memory*/, void* block)
|
||||||
|
{
|
||||||
|
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size, void* block)
|
||||||
|
{
|
||||||
|
// Implement realloc() as we don't ask user to provide it.
|
||||||
|
if (block == nullptr)
|
||||||
|
return GImGuiFreeTypeAllocFunc((size_t)new_size, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
|
||||||
|
if (new_size == 0)
|
||||||
|
{
|
||||||
|
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_size > cur_size)
|
||||||
|
{
|
||||||
|
void* new_block = GImGuiFreeTypeAllocFunc((size_t)new_size, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
memcpy(new_block, block, (size_t)cur_size);
|
||||||
|
GImGuiFreeTypeFreeFunc(block, GImGuiFreeTypeAllocatorUserData);
|
||||||
|
return new_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas)
|
||||||
|
{
|
||||||
|
// FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html
|
||||||
|
FT_MemoryRec_ memory_rec = {};
|
||||||
|
memory_rec.user = nullptr;
|
||||||
|
memory_rec.alloc = &FreeType_Alloc;
|
||||||
|
memory_rec.free = &FreeType_Free;
|
||||||
|
memory_rec.realloc = &FreeType_Realloc;
|
||||||
|
|
||||||
|
// https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library
|
||||||
|
FT_Library ft_library;
|
||||||
|
FT_Error error = FT_New_Library(&memory_rec, &ft_library);
|
||||||
|
if (error != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator.
|
||||||
|
FT_Add_Default_Modules(ft_library);
|
||||||
|
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
// Install svg hooks for FreeType
|
||||||
|
// https://freetype.org/freetype2/docs/reference/ft2-properties.html#svg-hooks
|
||||||
|
// https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html#svg_fonts
|
||||||
|
SVG_RendererHooks hooks = { ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot };
|
||||||
|
FT_Property_Set(ft_library, "ot-svg", "svg-hooks", &hooks);
|
||||||
|
#endif // IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||||
|
// With plutosvg, use provided hooks
|
||||||
|
FT_Property_Set(ft_library, "ot-svg", "svg-hooks", plutosvg_ft_svg_hooks());
|
||||||
|
#endif // IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||||
|
|
||||||
|
bool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags);
|
||||||
|
FT_Done_Library(ft_library);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImFontBuilderIO* ImGuiFreeType::GetBuilderForFreeType()
|
||||||
|
{
|
||||||
|
static ImFontBuilderIO io;
|
||||||
|
io.FontBuilder_Build = ImFontAtlasBuildWithFreeType;
|
||||||
|
return &io;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
|
||||||
|
{
|
||||||
|
GImGuiFreeTypeAllocFunc = alloc_func;
|
||||||
|
GImGuiFreeTypeFreeFunc = free_func;
|
||||||
|
GImGuiFreeTypeAllocatorUserData = user_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
// For more details, see https://gitlab.freedesktop.org/freetype/freetype-demos/-/blob/master/src/rsvg-port.c
|
||||||
|
// The original code from the demo is licensed under CeCILL-C Free Software License Agreement (https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT)
|
||||||
|
struct LunasvgPortState
|
||||||
|
{
|
||||||
|
FT_Error err = FT_Err_Ok;
|
||||||
|
lunasvg::Matrix matrix;
|
||||||
|
std::unique_ptr<lunasvg::Document> svg = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static FT_Error ImGuiLunasvgPortInit(FT_Pointer* _state)
|
||||||
|
{
|
||||||
|
*_state = IM_NEW(LunasvgPortState)();
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGuiLunasvgPortFree(FT_Pointer* _state)
|
||||||
|
{
|
||||||
|
IM_DELETE(*(LunasvgPortState**)_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state)
|
||||||
|
{
|
||||||
|
LunasvgPortState* state = *(LunasvgPortState**)_state;
|
||||||
|
|
||||||
|
// If there was an error while loading the svg in ImGuiLunasvgPortPresetSlot(), the renderer hook still get called, so just returns the error.
|
||||||
|
if (state->err != FT_Err_Ok)
|
||||||
|
return state->err;
|
||||||
|
|
||||||
|
// rows is height, pitch (or stride) equals to width * sizeof(int32)
|
||||||
|
lunasvg::Bitmap bitmap((uint8_t*)slot->bitmap.buffer, slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch);
|
||||||
|
#if LUNASVG_VERSION_MAJOR >= 3
|
||||||
|
state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated
|
||||||
|
#else
|
||||||
|
state->svg->setMatrix(state->svg->matrix().identity()); // Reset the svg matrix to the default value
|
||||||
|
state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated
|
||||||
|
#endif
|
||||||
|
state->err = FT_Err_Ok;
|
||||||
|
return state->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_Pointer* _state)
|
||||||
|
{
|
||||||
|
FT_SVG_Document document = (FT_SVG_Document)slot->other;
|
||||||
|
LunasvgPortState* state = *(LunasvgPortState**)_state;
|
||||||
|
FT_Size_Metrics& metrics = document->metrics;
|
||||||
|
|
||||||
|
// This function is called twice, once in the FT_Load_Glyph() and another right before ImGuiLunasvgPortRender().
|
||||||
|
// If it's the latter, don't do anything because it's // already done in the former.
|
||||||
|
if (cache)
|
||||||
|
return state->err;
|
||||||
|
|
||||||
|
state->svg = lunasvg::Document::loadFromData((const char*)document->svg_document, document->svg_document_length);
|
||||||
|
if (state->svg == nullptr)
|
||||||
|
{
|
||||||
|
state->err = FT_Err_Invalid_SVG_Document;
|
||||||
|
return state->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LUNASVG_VERSION_MAJOR >= 3
|
||||||
|
lunasvg::Box box = state->svg->boundingBox();
|
||||||
|
#else
|
||||||
|
lunasvg::Box box = state->svg->box();
|
||||||
|
#endif
|
||||||
|
double scale = std::min(metrics.x_ppem / box.w, metrics.y_ppem / box.h);
|
||||||
|
double xx = (double)document->transform.xx / (1 << 16);
|
||||||
|
double xy = -(double)document->transform.xy / (1 << 16);
|
||||||
|
double yx = -(double)document->transform.yx / (1 << 16);
|
||||||
|
double yy = (double)document->transform.yy / (1 << 16);
|
||||||
|
double x0 = (double)document->delta.x / 64 * box.w / metrics.x_ppem;
|
||||||
|
double y0 = -(double)document->delta.y / 64 * box.h / metrics.y_ppem;
|
||||||
|
|
||||||
|
#if LUNASVG_VERSION_MAJOR >= 3
|
||||||
|
// Scale, transform and pre-translate the matrix for the rendering step
|
||||||
|
state->matrix = lunasvg::Matrix::translated(-box.x, -box.y);
|
||||||
|
state->matrix.multiply(lunasvg::Matrix(xx, xy, yx, yy, x0, y0));
|
||||||
|
state->matrix.scale(scale, scale);
|
||||||
|
|
||||||
|
// Apply updated transformation to the bounding box
|
||||||
|
box.transform(state->matrix);
|
||||||
|
#else
|
||||||
|
// Scale and transform, we don't translate the svg yet
|
||||||
|
state->matrix.identity();
|
||||||
|
state->matrix.scale(scale, scale);
|
||||||
|
state->matrix.transform(xx, xy, yx, yy, x0, y0);
|
||||||
|
state->svg->setMatrix(state->matrix);
|
||||||
|
|
||||||
|
// Pre-translate the matrix for the rendering step
|
||||||
|
state->matrix.translate(-box.x, -box.y);
|
||||||
|
|
||||||
|
// Get the box again after the transformation
|
||||||
|
box = state->svg->box();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Calculate the bitmap size
|
||||||
|
slot->bitmap_left = FT_Int(box.x);
|
||||||
|
slot->bitmap_top = FT_Int(-box.y);
|
||||||
|
slot->bitmap.rows = (unsigned int)(ImCeil((float)box.h));
|
||||||
|
slot->bitmap.width = (unsigned int)(ImCeil((float)box.w));
|
||||||
|
slot->bitmap.pitch = slot->bitmap.width * 4;
|
||||||
|
slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||||
|
|
||||||
|
// Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box.
|
||||||
|
double metrics_width = box.w;
|
||||||
|
double metrics_height = box.h;
|
||||||
|
double horiBearingX = box.x;
|
||||||
|
double horiBearingY = -box.y;
|
||||||
|
double vertBearingX = slot->metrics.horiBearingX / 64.0 - slot->metrics.horiAdvance / 64.0 / 2.0;
|
||||||
|
double vertBearingY = (slot->metrics.vertAdvance / 64.0 - slot->metrics.height / 64.0) / 2.0;
|
||||||
|
slot->metrics.width = FT_Pos(IM_ROUND(metrics_width * 64.0)); // Using IM_ROUND() assume width and height are positive
|
||||||
|
slot->metrics.height = FT_Pos(IM_ROUND(metrics_height * 64.0));
|
||||||
|
slot->metrics.horiBearingX = FT_Pos(horiBearingX * 64);
|
||||||
|
slot->metrics.horiBearingY = FT_Pos(horiBearingY * 64);
|
||||||
|
slot->metrics.vertBearingX = FT_Pos(vertBearingX * 64);
|
||||||
|
slot->metrics.vertBearingY = FT_Pos(vertBearingY * 64);
|
||||||
|
|
||||||
|
if (slot->metrics.vertAdvance == 0)
|
||||||
|
slot->metrics.vertAdvance = FT_Pos(metrics_height * 1.2 * 64.0);
|
||||||
|
|
||||||
|
state->err = FT_Err_Ok;
|
||||||
|
return state->err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
58
Editor/imgui/misc/freetype/imgui_freetype.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// dear imgui: FreeType font builder (used as a replacement for the stb_truetype builder)
|
||||||
|
// (headers)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_API
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
|
||||||
|
// Usage:
|
||||||
|
// - Add '#define IMGUI_ENABLE_FREETYPE' in your imconfig to enable support for imgui_freetype in imgui.
|
||||||
|
|
||||||
|
// Optional support for OpenType SVG fonts:
|
||||||
|
// - Add '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG' to use plutosvg (not provided). See #7927.
|
||||||
|
// - Add '#define IMGUI_ENABLE_FREETYPE_LUNASVG' to use lunasvg (not provided). See #6591.
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
struct ImFontAtlas;
|
||||||
|
struct ImFontBuilderIO;
|
||||||
|
|
||||||
|
// Hinting greatly impacts visuals (and glyph sizes).
|
||||||
|
// - By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter.
|
||||||
|
// - When disabled, FreeType generates blurrier glyphs, more or less matches the stb_truetype.h
|
||||||
|
// - The Default hinting mode usually looks good, but may distort glyphs in an unusual way.
|
||||||
|
// - The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer.
|
||||||
|
// You can set those flags globally in ImFontAtlas::FontBuilderFlags
|
||||||
|
// You can set those flags on a per font basis in ImFontConfig::FontBuilderFlags
|
||||||
|
enum ImGuiFreeTypeBuilderFlags
|
||||||
|
{
|
||||||
|
ImGuiFreeTypeBuilderFlags_NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes.
|
||||||
|
ImGuiFreeTypeBuilderFlags_NoAutoHint = 1 << 1, // Disable auto-hinter.
|
||||||
|
ImGuiFreeTypeBuilderFlags_ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter.
|
||||||
|
ImGuiFreeTypeBuilderFlags_LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text.
|
||||||
|
ImGuiFreeTypeBuilderFlags_MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output.
|
||||||
|
ImGuiFreeTypeBuilderFlags_Bold = 1 << 5, // Styling: Should we artificially embolden the font?
|
||||||
|
ImGuiFreeTypeBuilderFlags_Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style?
|
||||||
|
ImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7, // Disable anti-aliasing. Combine this with MonoHinting for best results!
|
||||||
|
ImGuiFreeTypeBuilderFlags_LoadColor = 1 << 8, // Enable FreeType color-layered glyphs
|
||||||
|
ImGuiFreeTypeBuilderFlags_Bitmap = 1 << 9 // Enable FreeType bitmap glyphs
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ImGuiFreeType
|
||||||
|
{
|
||||||
|
// This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'.
|
||||||
|
// If you need to dynamically select between multiple builders:
|
||||||
|
// - you can manually assign this builder with 'atlas->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()'
|
||||||
|
// - prefer deep-copying this into your own ImFontBuilderIO instance if you use hot-reloading that messes up static data.
|
||||||
|
IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType();
|
||||||
|
|
||||||
|
// Override allocators. By default ImGuiFreeType will use IM_ALLOC()/IM_FREE()
|
||||||
|
// However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired.
|
||||||
|
IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = nullptr);
|
||||||
|
|
||||||
|
// Obsolete names (will be removed soon)
|
||||||
|
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
//static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE'
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
29
Editor/imgui/misc/single_file/imgui_single_file.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// dear imgui: single-file wrapper include
|
||||||
|
// We use this to validate compiling all *.cpp files in a same compilation unit.
|
||||||
|
// Users of that technique (also called "Unity builds") can generally provide this themselves,
|
||||||
|
// so we don't really recommend you use this in your projects.
|
||||||
|
|
||||||
|
// Do this:
|
||||||
|
// #define IMGUI_IMPLEMENTATION
|
||||||
|
// Before you include this file in *one* C++ file to create the implementation.
|
||||||
|
// Using this in your project will leak the contents of imgui_internal.h and ImVec2 operators in this compilation unit.
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPLEMENTATION
|
||||||
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../../imgui.h"
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE
|
||||||
|
#include "../../misc/freetype/imgui_freetype.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IMGUI_IMPLEMENTATION
|
||||||
|
#include "../../imgui.cpp"
|
||||||
|
#include "../../imgui_demo.cpp"
|
||||||
|
#include "../../imgui_draw.cpp"
|
||||||
|
#include "../../imgui_tables.cpp"
|
||||||
|
#include "../../imgui_widgets.cpp"
|
||||||
|
#ifdef IMGUI_ENABLE_FREETYPE
|
||||||
|
#include "../../misc/freetype/imgui_freetype.cpp"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
1
Editor/imgui_impl_sdl2.h
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
imgui/backends/imgui_impl_sdl2.h
|
||||||
1
Editor/imgui_impl_sdlrenderer2.h
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
imgui/backends/imgui_impl_sdlrenderer2.h
|
||||||
118
Editor/main.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <random>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_sdl2.h"
|
||||||
|
#include "imgui_impl_sdlrenderer2.h"
|
||||||
|
#include "serialib.h"
|
||||||
|
|
||||||
|
#include "ssup.h"
|
||||||
|
|
||||||
|
#include "editor.cpp"
|
||||||
|
#include "connector.cpp"
|
||||||
|
#include "pages.cpp"
|
||||||
|
#include "menu.cpp"
|
||||||
|
#include "help.cpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]){
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0){
|
||||||
|
cerr << "Error: " << SDL_GetError() << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Window* window = SDL_CreateWindow("SpEdit", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||||
|
if (window == nullptr) {
|
||||||
|
cerr << "Error: SDL_CreateWindow(): " << SDL_GetError() << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
|
||||||
|
if (renderer == nullptr){
|
||||||
|
cerr << "Error creating SDL_Renderer!" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
|
||||||
|
io.IniFilename = NULL;
|
||||||
|
io.LogFilename = NULL;
|
||||||
|
updateAppStyle();
|
||||||
|
|
||||||
|
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
|
||||||
|
ImGui_ImplSDLRenderer2_Init(renderer);
|
||||||
|
|
||||||
|
addPage(PAGETYPE::TEXT);
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
while (!done){
|
||||||
|
SDL_Delay(10);
|
||||||
|
SDL_Event event;
|
||||||
|
|
||||||
|
while (SDL_PollEvent(&event)){
|
||||||
|
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||||
|
if (event.type == SDL_QUIT)
|
||||||
|
done = true;
|
||||||
|
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) {
|
||||||
|
SDL_Delay(10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplSDLRenderer2_NewFrame();
|
||||||
|
ImGui_ImplSDL2_NewFrame();
|
||||||
|
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
renderMenu();
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(270, 30), ImGuiCond_Always);
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(ImGui::GetMainViewport()->Size.x - 280, ImGui::GetMainViewport()->Size.y - 40), ImGuiCond_Always);
|
||||||
|
ImGui::Begin("###TABWIN", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse);
|
||||||
|
ImGui::BeginTabBar("Tablol");
|
||||||
|
|
||||||
|
renderConnectModule();
|
||||||
|
renderPageEditor();
|
||||||
|
renderHelpMenu();
|
||||||
|
|
||||||
|
ImGui::EndTabBar();
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
renderPageAllocator(currentPage);
|
||||||
|
|
||||||
|
ImGui::Render();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SDL_RenderSetScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
|
||||||
|
|
||||||
|
ImVec4 bgCol = ImGui::GetStyleColorVec4(ImGuiCol_FrameBg);
|
||||||
|
SDL_SetRenderDrawColor(renderer, bgCol.x * 255, bgCol.y * 255, bgCol.z * 255, bgCol.w * 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), renderer);
|
||||||
|
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
serial.closeDevice();
|
||||||
|
|
||||||
|
ImGui_ImplSDLRenderer2_Shutdown();
|
||||||
|
ImGui_ImplSDL2_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
98
Editor/menu.cpp
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "ssup.h"
|
||||||
|
|
||||||
|
#include "actions.cpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
void updateAppStyle(){
|
||||||
|
switch (applicationStyle){
|
||||||
|
case 0:
|
||||||
|
ImGui::StyleColorsLight();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ImGui::StyleColorsClassic();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderMenu(){
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(ImGui::GetMainViewport()->Size.x, 0), ImGuiCond_Always);
|
||||||
|
ImGui::Begin("###INVISFRAME", NULL, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_MenuBar);
|
||||||
|
|
||||||
|
if (ImGui::BeginMenuBar()){
|
||||||
|
if (ImGui::BeginMenu(appLang == LANG::ENGLISH ? "Edit" : "Bearbeiten")){
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
} if (ImGui::BeginMenu(appLang == LANG::ENGLISH ? "Actions" : "Aktionen")){
|
||||||
|
|
||||||
|
renderActions(),
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
} if (ImGui::BeginMenu(appLang == LANG::ENGLISH ? "Settings" : "Einstellungen")){
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::SeparatorText("Application Style");
|
||||||
|
if (ImGui::RadioButton(appLang == LANG::ENGLISH ? "Light" : "Hell", &applicationStyle, 0)) updateAppStyle();
|
||||||
|
if (ImGui::RadioButton(appLang == LANG::ENGLISH ? "Dark" : "Dunkel", &applicationStyle, 1)) updateAppStyle();
|
||||||
|
if (ImGui::RadioButton(appLang == LANG::ENGLISH ? "Classic" : "Klassisch", &applicationStyle, 2)) updateAppStyle();
|
||||||
|
|
||||||
|
ImGui::SeparatorText(appLang == LANG::ENGLISH ? "Language" : "Sprache");
|
||||||
|
ImGui::RadioButton(appLang == LANG::ENGLISH ? "English" : "Englisch", &appLang, LANG::ENGLISH);
|
||||||
|
ImGui::RadioButton(appLang == LANG::ENGLISH ? "Deutsch" : "German", &appLang, LANG::GERMAN);
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
} if (ImGui::BeginMenu("About")){
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Why does this exist?" : "Warum existiert sowas?")) ImGui::OpenPopup("Fuck School");
|
||||||
|
|
||||||
|
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||||
|
ImGui::SetNextWindowPos(center, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||||
|
if (ImGui::BeginPopupModal("Fuck School", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ?
|
||||||
|
"Because: Fuck school\nBecause: Fuck math\nBecause: Free time is more valuable than fucking school" :
|
||||||
|
"Weil: Fick Schule\nWeil: Fick Mathe\nWeil: Freizeit viel mehr Wert ist als scheiß Schule");
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
if (ImGui::Button("OK", ImVec2(120, 0))) ImGui::CloseCurrentPopup();
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "License information" : "Lizenz Information")) ImGui::OpenPopup("Licence Info");
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos(center, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||||
|
if (ImGui::BeginPopupModal("Licence Info", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ?
|
||||||
|
"This shit is licenced under the GNU-GPL3 licence.\nThis means you can edit and modify this shit how ever you like.\nThe sourcecode and all info regarding the project can be found" :
|
||||||
|
"Diese Scheiße ist unter der GNU-GPL3 Lizenz lizenziert.\nDas heißt du kannst änderungen und modifikationen vorhehmen, wie du möchtest.\nDer Source-Code und jegliche Info über das Projekt kann");
|
||||||
|
ImGui::TextLinkOpenURL(appLang == LANG::ENGLISH ? "here at my Git instance" : "hier auf meiner Git Instanz", "https://git.weingardt.dev");
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "or" : "oder");
|
||||||
|
ImGui::TextLinkOpenURL(appLang == LANG::ENGLISH ? "here on my website" : "hier auf meiner Webseite gefunden werden", "https://weingardt.dev/ssup");
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
if (ImGui::Button("OK", ImVec2(120, 0))) ImGui::CloseCurrentPopup();
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
113
Editor/pages.cpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
|
#include "ssup.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void addPage(PAGETYPE type){
|
||||||
|
page* pg = new page();
|
||||||
|
pg->type = type;
|
||||||
|
|
||||||
|
if (type == PAGETYPE::IMAGE){
|
||||||
|
pg->data = malloc((((config.imagex / 8) * config.imagey)*sizeof(uint8_t)));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pg->data = malloc(config.texty*sizeof(char*));
|
||||||
|
char** txt = (char**)pg->data;
|
||||||
|
for (int i = 0; i < config.texty; i++) {
|
||||||
|
txt[i] = (char*)malloc((config.textx + 1)*sizeof(char));
|
||||||
|
for (int j = 0; j < config.textx + 1; j++) txt[i][j] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
pages.push_back(pg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pageGetter(void* data, int index, const char** output) {
|
||||||
|
vector<page*>* pages = (vector<page*>*)data;
|
||||||
|
|
||||||
|
static char buff[16];
|
||||||
|
if (pages->at(index)->type == PAGETYPE::IMAGE) sprintf(buff, appLang == LANG::ENGLISH ? "%d : Image" : "%d : Bild", index);
|
||||||
|
else sprintf(buff, "%d : Text", index);
|
||||||
|
*output = buff;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderPageAllocator(int ¤tPage){
|
||||||
|
static int usedMemory = 0;
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(250, ImGui::GetMainViewport()->Size.y - 40));
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(10, 30), ImGuiCond_Always);
|
||||||
|
ImGui::Begin(appLang == LANG::ENGLISH ? "Pages" : "Seiten", NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(usedMemory < (config.textx * config.texty));
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Add Text" : "Text hinzufügen", ImVec2(130, 0))) addPage(PAGETYPE::TEXT);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("%d Bytes", (config.textx * config.texty));
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(usedMemory < ((config.imagex / 8) * config.imagey));
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Add Image" : "Bild hinzufügen", ImVec2(130, 0))) addPage(PAGETYPE::IMAGE);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("%d Bytes", ((config.imagex / 8) * config.imagey));
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - 20);
|
||||||
|
ImGui::ListBox("###Pages", ¤tPage, pageGetter, &pages, pages.size(), 16);
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(currentPage == 0);
|
||||||
|
if (ImGui::ArrowButton("###PUSHUP", ImGuiDir_Up)){
|
||||||
|
page* swap = pages[currentPage];
|
||||||
|
pages[currentPage] = pages[currentPage - 1];
|
||||||
|
pages[currentPage - 1] = swap;
|
||||||
|
|
||||||
|
currentPage--;
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
ImGui::BeginDisabled(currentPage >= (int)pages.size() - 1);
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::ArrowButton("###PUSHDOWN", ImGuiDir_Down)){
|
||||||
|
page* swap = pages[currentPage];
|
||||||
|
pages[currentPage] = pages[currentPage + 1];
|
||||||
|
pages[currentPage + 1] = swap;
|
||||||
|
|
||||||
|
currentPage++;
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "Arrange Pages" : "Seiten Sortieren");
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(pages.size() <= 0);
|
||||||
|
if (ImGui::Button(appLang == LANG::ENGLISH ? "Delete Page" : "Seite löschen")){
|
||||||
|
vector<page*>::iterator it = pages.begin();
|
||||||
|
advance(it, currentPage);
|
||||||
|
pages.erase(it);
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
if (connected){
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
usedMemory = 0;
|
||||||
|
for (uint i = 0; i < pages.size(); i++) usedMemory += ( pages[i]->type == PAGETYPE::IMAGE ? ((config.imagex / 8) * config.imagey) : ((config.textx * config.texty)));
|
||||||
|
usedMemory = (config.eeprom_size * 1024) - usedMemory - config.toc_size;
|
||||||
|
|
||||||
|
ImGui::Text(appLang == LANG::ENGLISH ? "%d Bytes left\n%d%% Used" : "%d Bytes verbleibend\n%d%% genutzt",
|
||||||
|
usedMemory, (int)(((float)((config.eeprom_size * 1024) - usedMemory) / (float)(config.eeprom_size * 1024)) * 100));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
1134
Editor/serialib.cpp
Normal file
269
Editor/serialib.h
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
/*!
|
||||||
|
\file serialib.h
|
||||||
|
\brief Header file of the class serialib. This class is used for communication over a serial device.
|
||||||
|
\author Philippe Lucidarme (University of Angers)
|
||||||
|
\version 2.0
|
||||||
|
\date december the 27th of 2019
|
||||||
|
This Serial library is used to communicate through serial port.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
|
||||||
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
This is a licence-free software, it can be used by anyone who try to build a better world.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SERIALIB_H
|
||||||
|
#define SERIALIB_H
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
// This is Cygwin special case
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Include for windows
|
||||||
|
#if defined (_WIN32) || defined (_WIN64)
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
// This is MinGW special case
|
||||||
|
#include <sys/time.h>
|
||||||
|
#else
|
||||||
|
// sys/time.h does not exist on "actual" Windows
|
||||||
|
#define NO_POSIX_TIME
|
||||||
|
#endif
|
||||||
|
// Accessing to the serial port under Windows
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Include for Linux
|
||||||
|
#if defined (__linux__) || defined(__APPLE__)
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sys/time.h>
|
||||||
|
// File control definitions
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! To avoid unused parameters */
|
||||||
|
#define UNUSED(x) (void)(x)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of serial data bits
|
||||||
|
*/
|
||||||
|
enum SerialDataBits {
|
||||||
|
SERIAL_DATABITS_5, /**< 5 databits */
|
||||||
|
SERIAL_DATABITS_6, /**< 6 databits */
|
||||||
|
SERIAL_DATABITS_7, /**< 7 databits */
|
||||||
|
SERIAL_DATABITS_8, /**< 8 databits */
|
||||||
|
SERIAL_DATABITS_16, /**< 16 databits */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of serial stop bits
|
||||||
|
*/
|
||||||
|
enum SerialStopBits {
|
||||||
|
SERIAL_STOPBITS_1, /**< 1 stop bit */
|
||||||
|
SERIAL_STOPBITS_1_5, /**< 1.5 stop bits */
|
||||||
|
SERIAL_STOPBITS_2, /**< 2 stop bits */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* type of serial parity bits
|
||||||
|
*/
|
||||||
|
enum SerialParity {
|
||||||
|
SERIAL_PARITY_NONE, /**< no parity bit */
|
||||||
|
SERIAL_PARITY_EVEN, /**< even parity bit */
|
||||||
|
SERIAL_PARITY_ODD, /**< odd parity bit */
|
||||||
|
SERIAL_PARITY_MARK, /**< mark parity */
|
||||||
|
SERIAL_PARITY_SPACE /**< space bit */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \class serialib
|
||||||
|
\brief This class is used for communication over a serial device.
|
||||||
|
*/
|
||||||
|
class serialib
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
//_____________________________________
|
||||||
|
// ::: Constructors and destructors :::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor of the class
|
||||||
|
serialib ();
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~serialib ();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//_________________________________________
|
||||||
|
// ::: Configuration and initialization :::
|
||||||
|
|
||||||
|
|
||||||
|
// Open a device
|
||||||
|
char openDevice(const char *Device, const unsigned int Bauds,
|
||||||
|
SerialDataBits Databits = SERIAL_DATABITS_8,
|
||||||
|
SerialParity Parity = SERIAL_PARITY_NONE,
|
||||||
|
SerialStopBits Stopbits = SERIAL_STOPBITS_1);
|
||||||
|
|
||||||
|
// Check device opening state
|
||||||
|
bool isDeviceOpen();
|
||||||
|
|
||||||
|
// Close the current device
|
||||||
|
void closeDevice();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//___________________________________________
|
||||||
|
// ::: Read/Write operation on characters :::
|
||||||
|
|
||||||
|
|
||||||
|
// Write a char
|
||||||
|
int writeChar (char);
|
||||||
|
|
||||||
|
// Read a char (with timeout)
|
||||||
|
int readChar (char *pByte,const unsigned int timeOut_ms=0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//________________________________________
|
||||||
|
// ::: Read/Write operation on strings :::
|
||||||
|
|
||||||
|
|
||||||
|
// Write a string
|
||||||
|
int writeString (const char *String);
|
||||||
|
|
||||||
|
// Read a string (with timeout)
|
||||||
|
int readString ( char *receivedString,
|
||||||
|
char finalChar,
|
||||||
|
unsigned int maxNbBytes,
|
||||||
|
const unsigned int timeOut_ms=0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// _____________________________________
|
||||||
|
// ::: Read/Write operation on bytes :::
|
||||||
|
|
||||||
|
|
||||||
|
// Write an array of bytes
|
||||||
|
int writeBytes (const void *Buffer, const unsigned int NbBytes);
|
||||||
|
|
||||||
|
// Read an array of byte (with timeout)
|
||||||
|
int readBytes (void *buffer,unsigned int maxNbBytes,const unsigned int timeOut_ms=0, unsigned int sleepDuration_us=100);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// _________________________
|
||||||
|
// ::: Special operation :::
|
||||||
|
|
||||||
|
|
||||||
|
// Empty the received buffer
|
||||||
|
char flushReceiver();
|
||||||
|
|
||||||
|
// Return the number of bytes in the received buffer
|
||||||
|
int available();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// _________________________
|
||||||
|
// ::: Access to IO bits :::
|
||||||
|
|
||||||
|
|
||||||
|
// Set CTR status (Data Terminal Ready, pin 4)
|
||||||
|
bool DTR(bool status);
|
||||||
|
bool setDTR();
|
||||||
|
bool clearDTR();
|
||||||
|
|
||||||
|
// Set RTS status (Request To Send, pin 7)
|
||||||
|
bool RTS(bool status);
|
||||||
|
bool setRTS();
|
||||||
|
bool clearRTS();
|
||||||
|
|
||||||
|
// Get RI status (Ring Indicator, pin 9)
|
||||||
|
bool isRI();
|
||||||
|
|
||||||
|
// Get DCD status (Data Carrier Detect, pin 1)
|
||||||
|
bool isDCD();
|
||||||
|
|
||||||
|
// Get CTS status (Clear To Send, pin 8)
|
||||||
|
bool isCTS();
|
||||||
|
|
||||||
|
// Get DSR status (Data Set Ready, pin 9)
|
||||||
|
bool isDSR();
|
||||||
|
|
||||||
|
// Get RTS status (Request To Send, pin 7)
|
||||||
|
bool isRTS();
|
||||||
|
|
||||||
|
// Get CTR status (Data Terminal Ready, pin 4)
|
||||||
|
bool isDTR();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Read a string (no timeout)
|
||||||
|
int readStringNoTimeOut (char *String,char FinalChar,unsigned int MaxNbBytes);
|
||||||
|
|
||||||
|
// Current DTR and RTS state (can't be read on WIndows)
|
||||||
|
bool currentStateRTS;
|
||||||
|
bool currentStateDTR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined (_WIN32) || defined( _WIN64)
|
||||||
|
// Handle on serial device
|
||||||
|
HANDLE hSerial;
|
||||||
|
// For setting serial port timeouts
|
||||||
|
COMMTIMEOUTS timeouts;
|
||||||
|
#endif
|
||||||
|
#if defined (__linux__) || defined(__APPLE__)
|
||||||
|
int fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! \class timeOut
|
||||||
|
\brief This class can manage a timer which is used as a timeout.
|
||||||
|
*/
|
||||||
|
// Class timeOut
|
||||||
|
class timeOut
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
timeOut();
|
||||||
|
|
||||||
|
// Init the timer
|
||||||
|
void initTimer();
|
||||||
|
|
||||||
|
// Return the elapsed time since initialization
|
||||||
|
unsigned long int elapsedTime_ms();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined (NO_POSIX_TIME)
|
||||||
|
// Used to store the previous time (for computing timeout)
|
||||||
|
LONGLONG counterFrequency;
|
||||||
|
LONGLONG previousTime;
|
||||||
|
#else
|
||||||
|
// Used to store the previous time (for computing timeout)
|
||||||
|
struct timeval previousTime;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // serialib_H
|
||||||
52
Editor/ssup.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <bits/stdc++.h>
|
||||||
|
#include "serialib.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
enum LANG{
|
||||||
|
ENGLISH = 0,
|
||||||
|
GERMAN = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PAGETYPE{
|
||||||
|
TEXT = 0,
|
||||||
|
IMAGE = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ssup_config {
|
||||||
|
int firmware;
|
||||||
|
int model;
|
||||||
|
int eeprom_size = 8;
|
||||||
|
int eeprom_address;
|
||||||
|
int screen_address;
|
||||||
|
int toc_size;
|
||||||
|
int threshhold;
|
||||||
|
int contrast;
|
||||||
|
bool locked;
|
||||||
|
|
||||||
|
int textx = 21;
|
||||||
|
int texty = 4;
|
||||||
|
int imagex = 128;
|
||||||
|
int imagey = 32;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct page {
|
||||||
|
PAGETYPE type;
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const string modelLookup[] = {
|
||||||
|
"SHARP EL-W531XG"
|
||||||
|
};
|
||||||
|
|
||||||
|
static serialib serial;
|
||||||
|
static ssup_config config;
|
||||||
|
static int appLang = LANG::GERMAN;
|
||||||
|
static int applicationStyle = 1;
|
||||||
|
static int currentPage = 0;
|
||||||
|
static bool connected = false;
|
||||||
|
|
||||||
|
static vector<page*> pages;
|
||||||
BIN
Presentation/Presentation.pdf
Normal file
383
Presentation/Presentation.tex
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
\documentclass[12pt,a4paper,landscape]{article}
|
||||||
|
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[none]{hyphenat}
|
||||||
|
\usepackage{setspace}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{fancyhdr}
|
||||||
|
\usepackage{ragged2e}
|
||||||
|
\usepackage{natbib}
|
||||||
|
\usepackage{xcolor}
|
||||||
|
\usepackage{xspace}
|
||||||
|
\usepackage{parskip}
|
||||||
|
\usepackage{hanging}
|
||||||
|
\usepackage{listings}
|
||||||
|
\usepackage{float}
|
||||||
|
\usepackage{caption}
|
||||||
|
\usepackage{enumitem}
|
||||||
|
\usepackage{tocloft}
|
||||||
|
\usepackage{pgffor}
|
||||||
|
\usepackage{tabularx}
|
||||||
|
\usepackage{multirow}
|
||||||
|
\usepackage{csquotes}
|
||||||
|
\usepackage{fontawesome}
|
||||||
|
\usepackage{eurosym}
|
||||||
|
|
||||||
|
\usepackage[ngerman]{babel}
|
||||||
|
%\usepackage{amsmath,amsfonts,amssymb}
|
||||||
|
%\usepackage{moresize}
|
||||||
|
%\usepackage[export]{adjustbox}
|
||||||
|
|
||||||
|
% remove in final version to get rid of the red link boxes
|
||||||
|
\usepackage[linkcolor=red]{hyperref}
|
||||||
|
|
||||||
|
|
||||||
|
% Projektarbeit Metadata:
|
||||||
|
\date {\number\day.\number\month.\number\year}
|
||||||
|
\author {Gabriel Weingardt}
|
||||||
|
\title {title}
|
||||||
|
\def\projektnr {2}
|
||||||
|
\def\betreuer {Axel Göbel}
|
||||||
|
\def\matrikelnr {G240260PI}
|
||||||
|
\def\studiengang {Praktische Informatik}
|
||||||
|
\def\kurs {PIB24}
|
||||||
|
\def\ausbildung {ITZBund}
|
||||||
|
\def\campus {Gera}
|
||||||
|
\def\bereich {Technik}
|
||||||
|
\def\ort {Köln}
|
||||||
|
\def\strichsize {30em}
|
||||||
|
\def\unterschriftsize{25em}
|
||||||
|
\def\numberwidth {1cm}
|
||||||
|
\def\totalprojs {3}
|
||||||
|
|
||||||
|
\makeatletter
|
||||||
|
|
||||||
|
% DHGE Konformheit:
|
||||||
|
\usepackage[
|
||||||
|
papersize={16.8cm, 22.1cm},
|
||||||
|
top=2cm,
|
||||||
|
bottom=2cm,
|
||||||
|
right=2cm,
|
||||||
|
left=2cm
|
||||||
|
]{geometry}
|
||||||
|
|
||||||
|
\fancypagestyle{plain}{}
|
||||||
|
\pagestyle{fancy}
|
||||||
|
\fancyhead{}
|
||||||
|
\fancyfoot{}
|
||||||
|
\sloppy
|
||||||
|
%\setlength\parskip{6pt plus 2pt minus 1pt}
|
||||||
|
\captionsetup{justification=raggedright,singlelinecheck=false,format=hang,oneside}
|
||||||
|
\setlength{\cftsecindent}{0pt}
|
||||||
|
\setlength{\cftsubsecindent}{0pt}
|
||||||
|
\setlength{\cftsubsubsecindent}{0pt}
|
||||||
|
%\renewcommand\cftchapafterpnum{\vskip0pt}
|
||||||
|
%\renewcommand\cftsecafterpnum{\vskip0pt}
|
||||||
|
\setlength\cftparskip{-2pt}
|
||||||
|
\setlength\cftbeforesecskip{0pt}
|
||||||
|
|
||||||
|
\setstretch{1.06} % the formula is: (ABSATZSIZE) / (1,2 * FONTSIZE)
|
||||||
|
\newcount\pagesave
|
||||||
|
|
||||||
|
% Wenn ihr ne andere Schriftart wollt
|
||||||
|
% \fontfamily{ptm}\selectfont
|
||||||
|
|
||||||
|
% Verdeutschung
|
||||||
|
\renewcommand\contentsname{Inhaltsverzeichnis}
|
||||||
|
\renewcommand\listfigurename{}
|
||||||
|
\renewcommand\listtablename{}
|
||||||
|
\renewcommand*\headrulewidth{0pt}
|
||||||
|
\renewcommand*\figurename{Abbildung}
|
||||||
|
\renewcommand*\tablename{Tabelle}
|
||||||
|
\renewcommand{\footrulewidth}{0.4pt}
|
||||||
|
|
||||||
|
% Custom Commands for DHGE
|
||||||
|
\newcommand\deckblattitem[2]{
|
||||||
|
\noindent\hfill#1 :\space
|
||||||
|
\underline{ \makebox[\strichsize]{ #2 \hfill } }
|
||||||
|
\hfill\newline\vskip 0.2cm
|
||||||
|
}
|
||||||
|
\newcommand\makesignfield{\@author \hfill\ort, den \@date\space\underline{\makebox[20em]{}}}
|
||||||
|
\newcommand\makeromancounter{\pagenumbering{Roman}\fancyfoot[R]{ \small{CC BY-SA 4.0} \hfill \LaTeX \hfill - \thepage\ -}}
|
||||||
|
\newcommand\descriptionitem[2]{\makebox[8em]{[#1] \hfill} #2}
|
||||||
|
\newcommand\anonsec[1]{\section*{#1}\addcontentsline{toc}{section}{\protect\numberline{}#1}}
|
||||||
|
\newcommand*\custombox[2]{\colorlet{col}{.}{\color{#1}\framebox{\color{col}#2}}}
|
||||||
|
\newcommand*\tmp[1]{\custombox{orange}{\textbf{#1}}}
|
||||||
|
\newcommand*\refbox[1]{\custombox{blue}{#1}}
|
||||||
|
\newcommand*\figref[1]{\figurename\space\ref{#1}}
|
||||||
|
\newcommand*\sourcebox[1]{ {[#1]} }
|
||||||
|
\newcommand\bolt{ $ \lightning $ }
|
||||||
|
|
||||||
|
\makeatletter
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\begin{titlepage}
|
||||||
|
\vfill
|
||||||
|
\Centering
|
||||||
|
\textbf{SSUP}
|
||||||
|
\newline
|
||||||
|
\textbf{(Super Spicker Ultra Plus)}
|
||||||
|
\vfill
|
||||||
|
Gabriel Weingardt - \underline{https://weingardt.dev/}
|
||||||
|
\vfill
|
||||||
|
\@date \newline
|
||||||
|
Made with love in \LaTeX
|
||||||
|
\thispagestyle{empty}
|
||||||
|
\end{titlepage}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
\makeromancounter
|
||||||
|
\pagenumbering{arabic}
|
||||||
|
\setcounter{page}{1}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Was ist SSUP?}
|
||||||
|
|
||||||
|
\begin{table}[pht]
|
||||||
|
\begin{tabularx}{\textwidth}{ X l }
|
||||||
|
\begin{itemize}
|
||||||
|
\item Taschenrechner
|
||||||
|
\item Spicker
|
||||||
|
\item Ein Geheimdisplay, wo der OLED sein sollte
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
&
|
||||||
|
|
||||||
|
\raisebox{-\height}[0pt][0pt]{\includegraphics[width=0.3\textwidth]{calc.jpeg}}
|
||||||
|
|
||||||
|
\\
|
||||||
|
\end{tabularx}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Specs?}
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item Arduino Nano (ATMEGA 328p)
|
||||||
|
\item 2k RAM
|
||||||
|
\item 32k Programm Speicher
|
||||||
|
\item 20MHz Taktfrequenz
|
||||||
|
\item Arduino Code in C geschrieben <3
|
||||||
|
\item 512 bytes interner EEPROM (Settings, etc...)
|
||||||
|
\item Bis zu 32k externer EEPROM für Daten
|
||||||
|
\item 128x32 oder 128x64 Monochrom OLED Display
|
||||||
|
\item USB Verbindung über TTL Konverter
|
||||||
|
\item Interne LiPo Batterie
|
||||||
|
\item Erweiterungen möglich!
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Was kann SSUP?}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item 21x4 ASCII Text Ausgabe
|
||||||
|
\item 128x32 oder 128x64 Monochrome Bilder
|
||||||
|
\item Interface über Serielle Schnittstelle
|
||||||
|
\item Bis zu 256 Seiten Inhalt
|
||||||
|
\item Ist gemacht für Folemsammlungen und Beispielrechnungen anzeigen
|
||||||
|
\item Taktische Sperrung über Taskenkombination
|
||||||
|
\item Kontrasttoggle
|
||||||
|
\item Während dem Spicken, den Taschenrechner nutzen
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Für wen ist SSUP?}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item 9 oder 10 Klässler
|
||||||
|
\item (Fach)Abiturienten
|
||||||
|
\item Schüler, die schlecht in Mathe oder Physik sind
|
||||||
|
\item Schüler, welche sich keine Formeln merken können
|
||||||
|
\item Bastler (Autisten xDDDD)?
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Was ist/kann SSUP nicht?}
|
||||||
|
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item Kein Internetzugang
|
||||||
|
\item Keine Formellösungen
|
||||||
|
\item Kein Lernersatz!!
|
||||||
|
\item Kein ChatGPT und co bruh
|
||||||
|
\item Keine Kommunikation zwischen den Taschenrechnern
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Wie bedient man SSUP?}
|
||||||
|
|
||||||
|
SSUP Editor in C++ geschrieben mit der ImGui GUI Bibliothek:
|
||||||
|
|
||||||
|
\begin{figure}[h]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=1\textwidth]{editor-plain.png}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
Zur Zeit nur Linux, in Zukunft aber auch BSD, Windos und MacOS
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Verbinden mit SSUP}
|
||||||
|
|
||||||
|
\begin{figure}[h]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=1\textwidth]{editor-connected.png}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
|
||||||
|
\begin{figure}[h]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=1\textwidth]{editor-edit.png}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Dateisystemstruktur des SSUP}
|
||||||
|
|
||||||
|
\begin{table}[pht]
|
||||||
|
\begin{tabularx}{\textwidth}{ X X }
|
||||||
|
\begin{itemize}
|
||||||
|
\item Dateisystem sebst entwickelt
|
||||||
|
\item Table of Contents (TOC) Struktur
|
||||||
|
\item Bis zu 32k Addressierbar
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
&
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item Bis zu 256 TOC Einträge (Seiten)
|
||||||
|
\item Not as bloated as FAT32 xD
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\\
|
||||||
|
\end{tabularx}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
\begin{figure}[!h]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.85\textwidth]{spicker-data.png}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Bedienung vom SSUP}
|
||||||
|
|
||||||
|
\begin{table}[pht]
|
||||||
|
\begin{tabularx}{\textwidth}{ X l }
|
||||||
|
|
||||||
|
D1 - D4 Makrotasten, welche nicht standartmäßig vom
|
||||||
|
Taschenrechner genutzt werden.
|
||||||
|
\vspace{3em}
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item D1 $\to$ Vorherige Seite
|
||||||
|
\item D2 $\to$ Command
|
||||||
|
\item D3 $\to$ Display An/Aus toggle
|
||||||
|
\item D4 $\to$ Nächste Seite
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\vspace{3em}
|
||||||
|
Multipress Commands:
|
||||||
|
\begin{itemize}
|
||||||
|
\item D2+D1 $\to$ Seite 0
|
||||||
|
\item D2+D3 $\to$ Helligkeit Toggle
|
||||||
|
\item D2+D4 $\to$ Spicker Sperren
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
&
|
||||||
|
|
||||||
|
\raisebox{-\height}[0pt][0pt]{\includegraphics[width=0.5\textwidth]{calc-buttons.jpeg}}
|
||||||
|
|
||||||
|
\\
|
||||||
|
\end{tabularx}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Serielle Commands}
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item 'g' $\to$ Print System Info
|
||||||
|
\item 'r' $\to$ Standart Konfiguration Wiederherstellen
|
||||||
|
\item 's' $\to$ Daten Transfer Modus starten
|
||||||
|
\item 'x' $\to$ Daten Transfer Modus verlassen
|
||||||
|
\item 'f' $\to$ Schnelle Löschung (TOC clear)
|
||||||
|
\item 'c' $\to$ Ganzen EEPROM löschen
|
||||||
|
\item 'p' $\to$ Seite Seriell ausgeben
|
||||||
|
\item 't' $\to$ TOC Information Seriell ausgeben
|
||||||
|
\item 'h' $\to$ Print help
|
||||||
|
\item 'u' $\to$ Spicker Entsperren
|
||||||
|
\item 'l' $\to$ Spicker Sperren
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Content Hochladen}
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Spicker in Daten Transfer Modus setzen
|
||||||
|
\item '\space [\space' senden
|
||||||
|
\item 't' für neue Text Seite\newline 'i' für neues Bild
|
||||||
|
\item ';' Semicolon senden
|
||||||
|
\newline\newline
|
||||||
|
\vspace{3em}
|
||||||
|
Text Beispiel: [t;Das ist eine Seite!]\newline
|
||||||
|
Bild Beispiel: [i;32;54;12;65;FA;F5;F1...]
|
||||||
|
\end{enumerate}
|
||||||
|
\vspace{3em}
|
||||||
|
Aber egal, das wird von der GUI Übernommen!
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Live Demo!}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Warum?}
|
||||||
|
|
||||||
|
\begin{figure}[!h]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.85\textwidth]{fuck-school.png}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
Es hat mich durch mein Fachabi Mathe gebracht (4 gewinnt ;D)
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Warum?}
|
||||||
|
|
||||||
|
\begin{figure}[!h]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=0.85\textwidth]{licence.png}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Backtracking thoughts}
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
\item Welcher Schüler wird 100+ \geneuro\space ausgeben?
|
||||||
|
\item Welche Schüler haben noch einen Computer???
|
||||||
|
\item Wie kann man SSUP verbreiten ohne, dass es Lehrer und Schulen mitbekommen?
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
\section{Disclaimer lol}
|
||||||
|
|
||||||
|
\vfill
|
||||||
|
\Huge
|
||||||
|
I am not liable for any pupils getting caught ;D
|
||||||
|
\vfill
|
||||||
|
|
||||||
|
|
||||||
|
\end{document}
|
||||||
BIN
Presentation/calc-buttons.jpeg
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
Presentation/calc.jpeg
Normal file
|
After Width: | Height: | Size: 246 KiB |
BIN
Presentation/editor-connected.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Presentation/editor-edit.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
Presentation/editor-plain.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
Presentation/fuck-school.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
Presentation/licence.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
Presentation/spicker-data.png
Normal file
|
After Width: | Height: | Size: 188 KiB |