@@ -750,12 +750,23 @@ struct color {
750750 color () : value(0xFF000000 ) {} // default: opaque black
751751 color (unsigned int v) : value(v) {} // allows color pix = img->get(x,y)
752752
753- // These constructors call makeColor() which applies colorMode.
754753 // Defined in Processing.cpp so the colorMode globals are accessible.
754+ //
755+ // 3-arg and 4-arg int overloads were intentionally removed: they were
756+ // pure pass-throughs that cast to float and called the exact same
757+ // _makeColor() the float overloads call directly, so removing them
758+ // changes no runtime behavior -- it only removes the possibility of
759+ // ambiguous overload resolution on mixed-type calls like
760+ // color(map(...), map(...), 50).
761+ //
762+ // 1-arg and 2-arg int overloads are KEPT: color(int) would otherwise be
763+ // ambiguous between color(float) (grayscale) and color(unsigned int)
764+ // (raw packed ARGB pixel value, e.g. color pix = img->get(x,y)) -- two
765+ // different, equally-valid implicit conversions for the same int
766+ // literal. color(int gray) as an EXACT match resolves that in favor
767+ // of "grayscale", matching real Processing semantics.
755768 color (int gray);
756769 color (int gray, int a);
757- color (int r, int g, int b);
758- color (int r, int g, int b, int a);
759770 // Use explicit cast: color(0,153,204,(int)a) or color(0.f,153.f,204.f,a)
760771 color (float gray);
761772 color (float gray, float a);
@@ -1303,6 +1314,110 @@ class Table {
13031314// TYPED LISTS / DICTS -- match Processing Java's IntList, FloatDict, etc.
13041315// =============================================================================
13051316
1317+ // =============================================================================
1318+ // String -- real wrapper class with Java's String API, NOT a textual
1319+ // rename to std::string. Inherits std::string for storage/operators
1320+ // (+, ==, <<, etc. all keep working), and adds Java-named methods so
1321+ // sketch authors can transfer their Java/Processing knowledge directly:
1322+ // length(), charAt(), equals(), equalsIgnoreCase(), substring(),
1323+ // indexOf(), lastIndexOf(), toLowerCase(), toUpperCase(), trim(),
1324+ // contains(), startsWith(), endsWith(), replace(), isEmpty(), concat(),
1325+ // compareTo(). Regex-based methods (matches/replaceAll/split with regex)
1326+ // are intentionally NOT implemented -- real Processing sketches rarely
1327+ // use them, and a correct regex engine is a much bigger addition.
1328+ // =============================================================================
1329+ class String : public std ::string {
1330+ public:
1331+ String () : std::string() {}
1332+ String (const std::string& s) : std::string(s) {}
1333+ String (const char * s) : std::string(s) {}
1334+ String (char c) : std::string(1 , c) {}
1335+ String (const std::string& s, size_t pos, size_t len = npos) : std::string(s, pos, len) {}
1336+
1337+ int length () const { return (int )size (); }
1338+ bool isEmpty () const { return empty (); }
1339+
1340+ char charAt (int index) const { return at ((size_t )index); }
1341+
1342+ bool equals (const std::string& other) const { return *this == other; }
1343+ bool equalsIgnoreCase (const std::string& other) const {
1344+ if (size () != other.size ()) return false ;
1345+ for (size_t i = 0 ; i < size (); i++)
1346+ if (tolower ((unsigned char )(*this )[i]) != tolower ((unsigned char )other[i])) return false ;
1347+ return true ;
1348+ }
1349+
1350+ String substring (int beginIndex) const {
1351+ if (beginIndex < 0 ) beginIndex = 0 ;
1352+ if ((size_t )beginIndex > size ()) beginIndex = (int )size ();
1353+ return String (substr ((size_t )beginIndex));
1354+ }
1355+ String substring (int beginIndex, int endIndex) const {
1356+ if (beginIndex < 0 ) beginIndex = 0 ;
1357+ if (endIndex > (int )size ()) endIndex = (int )size ();
1358+ if (endIndex < beginIndex) endIndex = beginIndex;
1359+ return String (substr ((size_t )beginIndex, (size_t )(endIndex - beginIndex)));
1360+ }
1361+
1362+ int indexOf (const std::string& needle) const {
1363+ size_t p = find (needle);
1364+ return p == npos ? -1 : (int )p;
1365+ }
1366+ int indexOf (const std::string& needle, int fromIndex) const {
1367+ size_t p = find (needle, (size_t )std::max (0 , fromIndex));
1368+ return p == npos ? -1 : (int )p;
1369+ }
1370+ int lastIndexOf (const std::string& needle) const {
1371+ size_t p = rfind (needle);
1372+ return p == npos ? -1 : (int )p;
1373+ }
1374+
1375+ String toLowerCase () const {
1376+ std::string r = *this ;
1377+ for (auto & c : r) c = (char )tolower ((unsigned char )c);
1378+ return String (r);
1379+ }
1380+ String toUpperCase () const {
1381+ std::string r = *this ;
1382+ for (auto & c : r) c = (char )toupper ((unsigned char )c);
1383+ return String (r);
1384+ }
1385+
1386+ String trim () const {
1387+ size_t start = find_first_not_of (" \t\n\r\f\v " );
1388+ if (start == npos) return String (" " );
1389+ size_t end = find_last_not_of (" \t\n\r\f\v " );
1390+ return String (substr (start, end - start + 1 ));
1391+ }
1392+
1393+ bool contains (const std::string& needle) const { return find (needle) != npos; }
1394+ bool startsWith (const std::string& prefix) const {
1395+ return size () >= prefix.size () && compare (0 , prefix.size (), prefix) == 0 ;
1396+ }
1397+ bool endsWith (const std::string& suffix) const {
1398+ return size () >= suffix.size () && compare (size () - suffix.size (), suffix.size (), suffix) == 0 ;
1399+ }
1400+
1401+ String replace (char oldChar, char newChar) const {
1402+ std::string r = *this ;
1403+ for (auto & c : r) if (c == oldChar) c = newChar;
1404+ return String (r);
1405+ }
1406+ String replace (const std::string& oldStr, const std::string& newStr) const {
1407+ std::string r = *this ;
1408+ size_t pos = 0 ;
1409+ while ((pos = r.find (oldStr, pos)) != npos) {
1410+ r.replace (pos, oldStr.size (), newStr);
1411+ pos += newStr.size ();
1412+ }
1413+ return String (r);
1414+ }
1415+
1416+ String concat (const std::string& other) const { return String (*this + other); }
1417+
1418+ int compareTo (const std::string& other) const { return compare (other); }
1419+ };
1420+
13061421class IntList {
13071422public:
13081423 std::vector<int > data;
@@ -1374,6 +1489,32 @@ class StringList {
13741489 std::string& operator [](int i) { return data[i]; }
13751490};
13761491
1492+ // =============================================================================
1493+ // ArrayList<T> -- Java-style generic list, backed by std::vector. Real
1494+ // Processing/Java method names (add/get/remove/size/isEmpty/contains),
1495+ // NOT a textual rewrite to std::vector, since std::vector's own method
1496+ // names (push_back/operator[]/erase) don't match what sketch source
1497+ // written against Java's ArrayList API actually calls.
1498+ template <typename T>
1499+ class ArrayList {
1500+ public:
1501+ std::vector<T> data;
1502+ ArrayList () = default ;
1503+ ArrayList (std::initializer_list<T> l) : data(l) {}
1504+ void add (const T& v) { data.push_back (v); }
1505+ void add (int i, const T& v) { data.insert (data.begin ()+i, v); }
1506+ void set (int i, const T& v) { data[i]=v; }
1507+ T get (int i) const { return data[i]; }
1508+ int size () const { return (int )data.size (); }
1509+ bool isEmpty () const { return data.empty (); }
1510+ bool contains (const T& v) const { return std::find (data.begin (),data.end (),v)!=data.end (); }
1511+ void remove (int i) { data.erase (data.begin ()+i); }
1512+ void clear () { data.clear (); }
1513+ T& operator [](int i) { return data[i]; }
1514+ auto begin () { return data.begin (); }
1515+ auto end () { return data.end (); }
1516+ };
1517+
13771518// =============================================================================
13781519// PMap<K,V> -- thin std::unordered_map wrapper
13791520template <typename K, typename V>
@@ -1931,7 +2072,12 @@ struct PApplet {
19312072 bool _keyPressed = false ;
19322073 int keyCode = 0 ;
19332074 char key = 0 ;
1934- std::unordered_set<int > keys; // all currently held keycodes (FPS-style)
2075+ bool keys[349 ] = {}; // all currently held GLFW keycodes (AAA-style flat array)
2076+ bool mouseButtons[8 ] = {}; // all currently held mouse buttons (GLFW_MOUSE_BUTTON_*)
2077+ bool keysDown[256 ] = {}; // Processing-keycode-indexed, mirrors upper/lower letters
2078+ bool mouseDown[128 ] = {}; // Processing mouse-button-indexed (LEFT/RIGHT/CENTER)
2079+ bool _eventDrewSomething = false ; // set true if keyPressed()/mousePressed() drew
2080+ bool _backgroundCalledThisFrame = false ; // set true if background() was called this frame
19352081
19362082 int frameCount = 1 ;
19372083 float currentFrameRate = 60 .0f ;
@@ -2005,6 +2151,7 @@ struct PApplet {
20052151 void size (int w, int h, int renderer);
20062152 void fullScreen ();
20072153 void frameRate (int fps);
2154+ void vsync (bool on); // vsync(true)=cap to display refresh, vsync(false)=uncapped
20082155 void noLoop ();
20092156 void loop ();
20102157 void redraw ();
@@ -2538,11 +2685,17 @@ struct PApplet {
25382685 int g_textAlignY = BASELINE ;
25392686 float g_textLeading = 0 .0f ;
25402687#if PROCESSING_HAS_STB_TRUETYPE
2688+ struct TTFAtlas {
2689+ GLuint texID = 0 ;
2690+ stbtt_bakedchar chars[96 ];
2691+ };
25412692 struct TTFFont {
25422693 stbtt_fontinfo info;
25432694 std::vector<unsigned char > data;
2695+ std::unordered_map<int , TTFAtlas> atlasCache; // keyed by round(pixelSize*2)
2696+ TTFAtlas* current = nullptr ;
25442697 GLuint texID = 0 ;
2545- stbtt_bakedchar chars[ 96 ] ;
2698+ stbtt_bakedchar* chars = nullptr ;
25462699 int atlasW = 512 , atlasH = 512 ;
25472700 float bakeSize = 0 .0f ;
25482701 bool loaded = false ;
0 commit comments