Skip to content

Commit 127d5e0

Browse files
SpaiRclaude
andcommitted
docs: add .claude rules and refresh AGENTS.md, README, CONTRIBUTING
Introduce three companion files under .claude/ that separate concerns previously packed into AGENTS.md: - .claude/rules/guardrails.md — what not to do (golden rules, JNI contract, Java 8 compat, doclint, deps, AST drift, PR hygiene) - .claude/rules/codestyle.md — Java style summary backed by Checkstyle - .claude/docs/patterns.md — recurring binding patterns (codegen loop, struct wrappers, out-param wrappers, module boundaries) Update AGENTS.md to reference the new files and trim sections now covered there. Modernize README (LWJGL 3.4.1 versions, cleaner prose, knobs extension entry). Add AI-agent attribution guidance and Co-authored-by trailer convention to CONTRIBUTING.md. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 283becb commit 127d5e0

7 files changed

Lines changed: 777 additions & 143 deletions

File tree

.claude/docs/patterns.md

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Patterns
2+
3+
Common patterns for working in this codebase. Applies to **`imgui-binding`**, **`imgui-lwjgl3`**, **`imgui-app`** and
4+
their tests/examples. The codegen plumbing under `buildSrc/` is **not** part of these patterns — see
5+
`.claude/rules/guardrails.md` for the rationale.
6+
7+
## Working with the binding
8+
9+
### The codegen loop
10+
11+
The Java public API is materialized in two trees:
12+
13+
```
14+
imgui-binding/src/main/java/ ← hand-written, source of truth
15+
imgui-binding/src/generated/java/ ← codegen output, committed
16+
```
17+
18+
You edit the first; the generator (`buildSrc/`) writes the second. Both are checked in so downstream consumers see a
19+
normal Java project, but only the source tree is meaningful for review.
20+
21+
```
22+
# typical edit flow
23+
edit imgui-binding/src/main/java/imgui/Foo.java
24+
./gradlew :imgui-binding:generateApi
25+
./gradlew :imgui-binding:javadoc # catches doclint regressions early
26+
git add -p imgui-binding/src/main/java imgui-binding/src/generated/java
27+
git commit
28+
```
29+
30+
If you skip `generateApi`, the generated tree drifts and CI fails. If you commit only the generated tree, your change
31+
vanishes on the next regen.
32+
33+
### Annotated stubs as a vocabulary
34+
35+
The hand-written sources use annotations from `imgui.binding.annotation` to describe the wanted Java API on top of the
36+
C++ shape:
37+
38+
| Annotation | Use |
39+
|--------------------------------|-------------------------------------------------------------------------------------------------------------------------|
40+
| `@BindingSource` | Class-level: this type participates in codegen. |
41+
| `@BindingMethod` | Method-level: emit a JNI bridge for this method. `name=` overrides the Java name; `callName=` overrides the C++ symbol. |
42+
| `@BindingField` | Field-level: emit getter/setter for a struct field. |
43+
| `@BindingAstEnum` | Bind a class to a clang-AST enum dump in `buildSrc/.../api/ast/`. |
44+
| `@OptArg` | Mark a parameter as having an overload that omits it. |
45+
| `@ArgValue`, `@ArgVariant` | Argument variant hints (e.g. `ImVec2` vs `(float, float)`). |
46+
| `@ReturnValue` | Return-value hints (`isStatic` for shared instances, etc.). |
47+
| `@TypeArray`, `@TypeStdString` | Map between Java arrays/`String` and C++ container types. |
48+
| `@ExcludedSource` | Skip this source when running codegen. |
49+
50+
When adding a new method, copy the annotation pattern from a structurally similar nearby method — the generator is
51+
sensitive to placement and combinations.
52+
53+
### Wrapping a native struct
54+
55+
The recurring shape (see `ImVec2`, `ImInt`, `ImFontGlyph`, `ImColor`):
56+
57+
1. Extend `imgui.binding.ImGuiStruct` if the type wraps a native pointer; otherwise it's a value type with public
58+
mutable fields or a backing `T[] data` array.
59+
2. Constructors: no-arg, copy (`new Foo(other)`), and per-field value form.
60+
3. Fluent `set(...)` returning `this`.
61+
4. `@Override` `toString` / `equals` / `hashCode`. Add `clone` with `@SuppressWarnings("MethodDoesntCallSuperMethod")`
62+
and the copy-constructor inside.
63+
5. Annotate `@BindingSource` if it's bound from upstream; otherwise leave plain.
64+
65+
Don't invent a new layout — readers expect this one.
66+
67+
### Out-parameters via `Im*` wrappers
68+
69+
Dear ImGui's C++ API frequently takes `T*` for values the function will mutate (`bool* p_open`, `int* current_item`,
70+
`float* values`). Java can't do that with primitives, so the binding uses single-element wrappers under `imgui.type`:
71+
72+
| C++ | Java wrapper |
73+
|-------------------------|--------------|
74+
| `bool*` | `ImBoolean` |
75+
| `int*` | `ImInt` |
76+
| `short*` | `ImShort` |
77+
| `long long*` | `ImLong` |
78+
| `float*` | `ImFloat` |
79+
| `double*` | `ImDouble` |
80+
| `char*`, `std::string*` | `ImString` |
81+
82+
Pattern from a caller's perspective:
83+
84+
```java
85+
ImBoolean isOpen = new ImBoolean(true);
86+
if (ImGui.begin("Window", isOpen)) {
87+
// ...
88+
ImGui.end();
89+
}
90+
if (!isOpen.get()) {
91+
// window was closed via the title-bar X
92+
}
93+
```
94+
95+
When designing a new binding method that takes an out-parameter, mirror this — accept the wrapper, not a `boolean[]` or
96+
`AtomicReference`.
97+
98+
### `@OptArg` and overload generation
99+
100+
A C++ default argument becomes a series of Java overloads, generated automatically. In source you write the most general
101+
signature once and tag the optional tail:
102+
103+
```java
104+
@BindingMethod
105+
public static native void ShowDemoWindow(@OptArg ImBoolean pOpen);
106+
```
107+
108+
The generator emits both `showDemoWindow()` and `showDemoWindow(ImBoolean)`. You don't need to hand-write the overloads,
109+
and you shouldn't.
110+
111+
### Enums as constants on a holder class
112+
113+
Dear ImGui's enums (`ImGuiWindowFlags`, `ImGuiCond`, `ImGuiKey`, …) are surfaced as classes under `imgui.flag.*` with
114+
`public static final int` constants and a private constructor. They're driven from clang AST dumps via
115+
`@BindingAstEnum`. When upstream adds or renames an enum value, regenerate the AST, then `generateApi` propagates it to
116+
the flag class.
117+
118+
Don't hand-edit the flag classes. If a value is missing, the AST is stale.
119+
120+
## Module boundaries
121+
122+
```
123+
imgui-binding ← Dear ImGui Java API + JNI. Zero runtime deps.
124+
imgui-lwjgl3 ← GLFW + OpenGL backend. Depends on lwjgl + imgui-binding.
125+
imgui-app ← Application abstraction. Depends on lwjgl + imgui-binding + imgui-lwjgl3, ships natives in the jar.
126+
example ← Demos. Depends on imgui-app.
127+
```
128+
129+
Rules of thumb:
130+
131+
- New ImGui surface (a new function from upstream) → `imgui-binding`.
132+
- New backend wiring (alternate GL version, headless renderer) → new module sibling to `imgui-lwjgl3`. Don't add Vulkan
133+
to `imgui-lwjgl3`.
134+
- New Application convenience (an extra lifecycle hook) → `imgui-app`. Keep it minimal — it's meant as a starting point,
135+
not a framework.
136+
- Demo of a new feature → `example/src/main/java/Example*.java`, named `Example<Feature>.java`.
137+
138+
Cross-module dependencies are one-way. `imgui-binding` must not depend on lwjgl or anything else.
139+
140+
## Lifecycle of an `imgui-app` application
141+
142+
`Application` extends `Window`. The `launch(...)` entry point runs:
143+
144+
```
145+
configure(Configuration) ← override to set title/size/etc.
146+
initWindow(Configuration)
147+
initImGui(Configuration) ← override to load fonts, set styles
148+
preRun() ← override: one-shot setup
149+
loop:
150+
preProcess() ← override: per-frame pre-work
151+
process() ← override: your UI
152+
postProcess() ← override: per-frame post-work
153+
postRun() ← override: one-shot teardown
154+
disposeImGui()
155+
disposeWindow()
156+
```
157+
158+
Threading: ImGui is single-threaded by design. Heavy work goes outside `process()` (background threads + lock-free
159+
hand-off), not inside it. The `imgui.app.Application` Javadoc spells this out.
160+
161+
## Tests
162+
163+
Tests use **JUnit Jupiter (5.x)** — see `imgui-binding/build.gradle`. They run via `./gradlew :imgui-binding:test`.
164+
There is no separate "integration" suite; test what you can in pure JVM, and rely on the example app for visual smoke
165+
tests. UI behavior changes (new widget rendering, font glyph coverage, viewport handling) cannot be unit-tested — run
166+
`./gradlew :example:run -PlibPath=...` and verify by eye.
167+
168+
The `TypeName` Checkstyle rule is suppressed under `src/test/` so tests can use names like `ImGui_Test` without
169+
complaint, but otherwise tests follow the same code style as production code.
170+
171+
## Building native libs locally
172+
173+
Two flows, both documented in `README.md`:
174+
175+
1. **Recommended**: `buildSrc/scripts/build.sh <windows|linux|macos>` — runs `vendor_freetype.sh`, calls `generateLibs`,
176+
drops the binary in `/tmp/imgui/dst/`. Matches what CI does.
177+
2. **Direct**: `./gradlew imgui-binding:generateLibs -Denvs=<csv> -Dlocal` — skip when you don't need FreeType or want
178+
output under the project tree.
179+
180+
After building, point the example at the fresh binary:
181+
182+
```
183+
cp /tmp/imgui/dst/libimgui-java64.<so|dylib|dll> bin/
184+
./gradlew :example:run -PlibPath=$PWD/bin
185+
```
186+
187+
Iterate `:example:run` (instead of `:imgui-binding:generateLibs` again) for Java-only changes — the native lib only
188+
needs rebuilding when JNI signatures or vendored sources change.
189+
190+
## Submodule bumps in one paragraph
191+
192+
`AGENTS.md` is the canonical guide. The condensed flow: read upstream's changelog and header diff before touching
193+
anything; bump the submodule pointer; `./gradlew generateAst` and revert any AST changes outside your scope; update
194+
annotated sources to match upstream's renames/removals; `./gradlew :imgui-binding:generateApi`; run javadoc locally and
195+
fix doclint hits; rebuild natives. Submodule bumps go in their own commit, separate from new-feature exposure.
196+
197+
## Where to look first
198+
199+
- `imgui.ImGui` — the giant entry-point class (1.4 MB worth of generated bindings + the static lib loader).
200+
- `imgui.binding.ImGuiStruct` — the JNI handshake.
201+
- `imgui.app.Application` — the lifecycle template you'd subclass.
202+
- `imgui-lwjgl3/.../ImGuiImplGl3.java` — reference for what a full backend looks like.
203+
- `example/src/main/java/Main.java` — the smallest end-to-end runnable, plus per-extension `Example*.java` siblings.
204+
- `AGENTS.md` (repo root) — submodule-bump procedure, generator gotchas, doclint pitfalls.

.claude/rules/codestyle.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Code Style
2+
3+
Applies to **`imgui-binding/src/main/java/`**, **`imgui-lwjgl3/`**, **`imgui-app/`** and any other production module.
4+
Does **not** apply to `buildSrc/` — see `guardrails.md`.
5+
6+
The authoritative rules live in `config/checkstyle/checkstyle.xml`; this document is the human-readable summary. If the
7+
two disagree, Checkstyle wins.
8+
9+
## Formatting
10+
11+
- **Indent**: 4 spaces. Never tabs (`FileTabCharacter` enforced).
12+
- **Line length**: 160 columns max.
13+
- **Trailing whitespace**: forbidden. End every file with a single newline.
14+
- **EOL**: LF (`.editorconfig` pins this; do not introduce CRLF).
15+
- **Braces**: K&R / Java standard — opening brace on the same line, single-statement `if`/`for`/`while` still get
16+
braces (`NeedBraces`).
17+
- **Blocks**: no nested anonymous `{ ... }` blocks (`AvoidNestedBlocks`); empty blocks must have a comment explaining
18+
why (`EmptyBlock`).
19+
20+
## Naming
21+
22+
Follows standard Java conventions, enforced by Checkstyle:
23+
24+
| Element | Convention | Example |
25+
|--------------------------------|--------------------------|--------------------------------|
26+
| Package | lowercase, dot-separated | `imgui.binding.annotation` |
27+
| Class / interface / annotation | UpperCamelCase | `ImFontAtlas`, `BindingMethod` |
28+
| Method | lowerCamelCase | `getFontSize()` |
29+
| Field / parameter / local | lowerCamelCase | `fontGlyphRanges` |
30+
| Constant (`static final`) | UPPER_SNAKE_CASE | `LIB_PATH_PROP` |
31+
32+
Class names that wrap a Dear ImGui struct or enum keep the upstream prefix (`ImGuiIO`, `ImGuiStyle`, `ImGuiKey`) so Java
33+
code reads close to C++ headers. Vector wrappers drop the namespace (`ImVec2`, `ImVec4`).
34+
35+
## Imports
36+
37+
- **No star imports**, with two whitelisted exceptions for `org.lwjgl.opengl.GL32` and `org.lwjgl.glfw.GLFW` — both
38+
expose hundreds of constants and the explicit listing pattern is established (see `ImGuiImplGl3.java`).
39+
- **Sort order**: third-party imports, then `java.*` / `javax.*`, then `static` imports — a blank line between the
40+
regular and the static block. Match what's already in `ImGuiImplGl3.java`.
41+
- **No unused imports** (`UnusedImports`). Don't keep them around "just in case".
42+
- **Static imports** are fine for OpenGL constants, JUnit assertions, and similar bulk APIs. Use the same package per
43+
file (e.g. consolidate everything on `GL32` even if a symbol exists in `GL11` — keeps the file uniform).
44+
45+
## Modifiers & visibility
46+
47+
- Modifier order is JLS-canonical: `public static final ...`, never `final static`.
48+
- Redundant modifiers (`public` on interface methods, `static` on nested interface, etc.) are flagged.
49+
- **Method parameters and local variables are `final` by default** (`FinalParameters`, `FinalLocalVariable`). Only drop
50+
`final` when reassignment is genuinely needed; suppression for `ImGui.java` is intentional (it is generator-touched
51+
and not representative).
52+
- **`HideUtilityClassConstructor`**: utility classes (`ImColor`, `ImColor`-style `final class` with only static methods)
53+
must declare a `private` no-arg constructor.
54+
- **`FinalClass`**: a class with only private constructors must be declared `final`.
55+
- **`VisibilityModifier`**: fields must be `private` unless there is a documented reason to expose them. Native struct
56+
wrappers expose the `long ptr` field on purpose — that exception is established in `imgui.binding.ImGuiStruct` and the
57+
`imgui` package is whitelisted in `suppressions.xml`.
58+
- **`DesignForExtension`**: any non-final, non-private method on a non-final class must be `final`, `abstract`, or have
59+
an empty body — i.e. design extension points explicitly. The `imgui.app` package is suppressed because `Application`
60+
is meant to be subclassed; do the same only when subclass-friendly behavior is the intent.
61+
62+
## Common-coding rules
63+
64+
Enforced by Checkstyle and worth keeping in mind:
65+
66+
- `EmptyStatement` — no stray `;`.
67+
- `EqualsHashCode` — override both or neither.
68+
- `InnerAssignment` — don't assign inside conditions.
69+
- `MagicNumber` — extract numeric literals other than `-1, 0, 1, 2` into named constants. Suppressed for the `imgui.*`
70+
packages because the binding mirrors raw enum values from C++ headers; do **not** use that as a license elsewhere.
71+
- `MultipleVariableDeclarations` — one declaration per line (`int a, b;` is rejected).
72+
- `MissingSwitchDefault`, `SimplifyBooleanExpression`, `SimplifyBooleanReturn`.
73+
- `UpperEll``1L`, never `1l`.
74+
- `ArrayTypeStyle``int[] arr`, never `int arr[]`.
75+
76+
## Whitespace
77+
78+
`GenericWhitespace`, `OperatorWrap`, `ParenPad`, `WhitespaceAround` and friends are all on. In practice: standard Java
79+
spacing — space around binary operators and after commas, no space inside parens, generic angle brackets touch the type
80+
name (`Map<String, Long>`).
81+
82+
## Javadoc
83+
84+
- The binding's public API ships Javadoc copied verbatim from upstream Dear ImGui headers. Preserve those comments when
85+
editing — they round-trip through codegen.
86+
- Inline operators that look like HTML (`<`, `>`, `&`, `->`) trip JDK 17 doclint. Wrap them in `{@code ...}`. Examples:
87+
- `(flags & X)``{@code (flags & X)}`
88+
- `if threshold < 0.0f``{@code if threshold < 0.0f}`
89+
- `"Demo->Child->X"``{@code Demo->Child->X}`
90+
- `@deprecated` Javadoc must come together with `@Deprecated` annotation, and should point at the replacement (
91+
`{@link #...}`).
92+
- Don't add commentary for the sake of comments. The `ImColor`-style one-liner Javadoc on each overload is the bar —
93+
accurate, terse.
94+
95+
## Class structure (binding wrappers)
96+
97+
Recurring pattern in `imgui.*` data classes (`ImVec2`, `ImInt`, `ImFontGlyph`, …):
98+
99+
1. Public mutable fields **or** a private backing array, exposed via `get/set`.
100+
2. No-arg, copy, and value constructors.
101+
3. Fluent `set(...)` returning `this`.
102+
4. `@Override` for `toString`, `equals`, `hashCode`, `clone` (with `@SuppressWarnings("MethodDoesntCallSuperMethod")` on
103+
`clone`).
104+
5. For struct pointers — extend `imgui.binding.ImGuiStruct`; never re-implement the `long ptr` field manually.
105+
106+
When adding a new wrapper, mirror this layout — readers expect it.
107+
108+
## Annotations on binding sources
109+
110+
In `imgui-binding/src/main/java/`, hand-written sources are fed into the codegen via annotations from
111+
`imgui.binding.annotation`:
112+
113+
- `@BindingSource` — class-level marker that the type participates in codegen.
114+
- `@BindingMethod`, `@BindingField`, `@BindingAstEnum` — method/field-level metadata.
115+
- `@OptArg`, `@ArgValue`, `@ArgVariant`, `@ReturnValue`, `@TypeArray`, `@TypeStdString` — fine-grained signature hints.
116+
- `@ExcludedSource` — exclude from codegen processing.
117+
118+
Use the existing surrounding methods as the template; the generator is sensitive to annotation placement.
119+
120+
## Suppressing rules
121+
122+
- Prefer fixing the code over suppressing the rule.
123+
- If suppression is required, use `@SuppressWarnings("CheckName")` at the smallest possible scope. Class-level
124+
suppression of generic `"unused"` is reserved for `ImGui.java` and similar generator-fed entry points.
125+
- Do **not** add new entries to `config/checkstyle/suppressions.xml` casually. That file currently relaxes rules for the
126+
codegen-touched `imgui` package; adding more reduces signal across the rest of the codebase.

0 commit comments

Comments
 (0)