KITAQ 개발 시스템
사용 설명서 2026.09

KITAQ SERIES • 참고 판본

KITAQGB 라이브러리

게임을 만드는 도구

첫 코드 한 줄부터 실행, 관찰, 재시험까지.
소스 스냅샷: 2026년 9월 14일 · 한국어판: 2026년 9월 14일

네이티브 컴파일러로 라이브러리 사용

lib/는 콘솔 ROM에 컴파일되는 C 헤더와 소스입니다. PC용 컴파일러와 보조 도구는 Rust로 구현되었으며 게임 소스, 대상 콘솔 라이브러리 및 API는 C로 사용합니다. 제공된 SOURCE_MANIFEST.json과 LIBRARY_MERGE.json은 선택한 라이브러리 소스를 기록합니다.

kitaqgb · Rust 네이티브 컴파일러와 보조 도구 · GitHub Actions

Windows, Linux, macOS ARM 및 macOS Intel에서 네이티브 빌드와 실행 검증이 성공했습니다. KITAQGB는 환경별 테스트 48개와 보조 도구 검사 395개, KITAQFC는 55개와 401개를 통과했습니다. Rust 1.85도 검증했습니다. PUBLIC_DISTRIBUTION.json은 배치한 바이너리의 해시와 검증 출처를 기록합니다. 공개 GitHub Actions는 이 소스를 독립적으로 빌드하고 검증합니다.

저장된 참조 출력으로 ROM 바이트, 진단 및 보조 도구 형식을 검사합니다. 이전 C# 에뮬레이터 검증은 원래 소스 지문에 해당하는 과거 기록입니다. 모든 Rust API, 실제 하드웨어 또는 FDS BIOS를 통한 완전한 게임 시작을 입증하지는 않습니다. 원본 PNG 변환 스크립트는 없어 사양으로 재구현했으며 원본과의 바이트 일치는 확인할 수 없습니다.

KITAQGB · SHA-256 · KITAQFC · SHA-256

2026-10-03 로컬 라이브러리 변경 사항과 검증

C:/kitaqgb_project/lib 소스를 공개 버전 2de7f4b와 비교했습니다. 수정 시각만으로 최신 버전을 판단할 수 없습니다. 로컬에는 추가 기능이 있고 공개 버전에는 별도의 추가 기능과 수정이 있습니다. 아래 설명은 저장한 로컬 소스를 대상으로 하며 기존 공개 API의 검증 기록과 구분합니다.

physics2d.c는 접촉 API를 유지하고 KQ2D_CACHE_SURFACE에서 접촉 및 속도 제한의 캐시 구현을 제공합니다. 활성화할 때 ROM 뱅크 13을 확보하세요. KQ2D_EXTERNAL_SCALE_Q8, KQ2D_EXTERNAL_REST_COMPONENT, KQ2D_EXTERNAL_SURFACE를 정의하면 해당 구현을 직접 제공해야 합니다. 아래 8,872건은 이 정의가 없는 기본 경로의 결과입니다.

KQ3D_BODY_SPHERE=0x04는 구와 상자의 접촉을 선택합니다. 반지름은 half_x입니다. kq3d_overlap_sphere_aabb(sphere, box)는 접하는 경계를 포함하며 NULL 또는 0 이하의 반지름이면 0을 반환합니다. 구끼리의 전용 해법은 없습니다. 좌표 차이, 곱과 제곱 합을 16비트 범위 안에 두세요.

KQ3D_BODY_KINEMATIC=0x02인 활성 body는 역질량이 0이어도 kq3d_step에서 X/Y 속도와 위치를 갱신합니다. Z 위치와 속도는 그대로입니다. 역질량 0인 body는 접촉으로 밀리지 않습니다. kq3d_integrate_body는 정적 body를 계속 건너뜁니다. break_speed와 KQ3D_BODY_BROKEN은 자동 파괴를 일으키지 않습니다.

로컬 bank_switch는 kq_bank_current와 주소 0x2000에 씁니다. 공개 __bankswitch 경로와 달리 컴파일러의 뱅크 추적 상태를 갱신하지 않습니다. 고정 뱅크에서 전환하고 컴파일러의 복귀 상태도 유지해야 한다면 __bankswitch를 사용하세요.

로컬 cgb_bg_color/cgb_obj_color와 단색 RGB 래퍼는 팔레트 인덱스의 자동 증가를 켜지 않습니다. CGB 실행에서 0x1234의 하위 바이트가 0x12로 덮이는 것을 확인했습니다. 공개 수정이나 colors 배열 API를 사용하세요. DMG에서는 쓰지 않습니다.

로컬 metasprite_draw는 정상 완료할 때만 사용 수를 first_id+count로 늘립니다. 40개 제한에서 조기 반환하면 갱신하지 않습니다. first_id=39, count=2에서 반환값 1, 슬롯 39 활성, 사용 수 0이었습니다. 공개 버전은 각 슬롯 처리 시 사용 수를 갱신합니다.

로컬에는 vram_get_queue_used와 vram_get_queue_free가 있지만 공개 vram_get_queue_capacity는 없습니다. 용량은 VRAM_QUEUE_MAX이며 기본값은 32입니다. 명령 하나를 등록하면 사용 1, 여유 31이었습니다.

wire3d_dmg.h의 DrawRect2D 선언은 96줄 프로필에만 있습니다. DrawBoxEdges2D는 두 프로필에, DrawIndexedEdges는 120줄 프로필에만 있습니다. 프로필에 맞는 소스를 하나 선택하세요. 이번에는 이 함수들의 화면 결과를 다시 검증하지 않았습니다. 저장한 lib 소스에는 DrawRect2D와 DrawBoxEdges2D 구현이 없습니다. 선언만 있으므로 호출하려면 별도 구현이 필요합니다.

로컬 audio_vblank에는 공개 AudioVBlank_QueueReset/QueueRefill/QueuePlay와 audio_vblank_queue.inc가 없습니다. ZX0도 공개 버전에만 있습니다. 이 기능들은 공개 추가 기능이며 검증된 로컬 기능에 포함하지 않습니다.

kq3d_overlap_sphere_aabb
u8 kq3d_overlap_sphere_aabb(const KQBody3D* sphere, const KQBody3D* box);

KQ3D_BODY_SPHERE=0x04는 구와 상자의 접촉을 선택합니다. 반지름은 half_x입니다. kq3d_overlap_sphere_aabb(sphere, box)는 접하는 경계를 포함하며 NULL 또는 0 이하의 반지름이면 0을 반환합니다. 구끼리의 전용 해법은 없습니다. 좌표 차이, 곱과 제곱 합을 16비트 범위 안에 두세요.

physics3d.c / physics3d.h

이번에 실행한 검증

2D 기본 경로: KOKURA C API의 자동 하드웨어 선택으로 8,872건 모두 통과했습니다. 속도 제한, 접촉, 부호 있는 Q8 곱셈과 충돌 시각을 확인했습니다. DMG/CGB를 명시적으로 나눈 시험은 아닙니다.

물리 경계 19건을 DMG와 CGB에서 실행하여 총 38회 모두 통과했습니다. 별도 3D 추가 기능과 스프라이트/VRAM/팔레트 재현 시험도 두 모드에서 기대값과 일치했습니다. 팔레트와 스프라이트는 결함 재현 성공이지 정상 동작의 확인이 아닙니다.

C# 컴파일러가 생성한 ROM의 에뮬레이터 검증입니다. Rust 동등성, 실제 기기, 음성, 화면이나 모든 API의 정확성을 증명하지 않습니다. 기존 이미지와 검증은 각 기록의 소스 지문에 연결된 과거 결과입니다.

소스 지문, 입력, 기대값, 실측값과 재실행 절차 · evidence.tar.gz · verify_rom_cases.py · verify_surface.py

1. 라이브러리 사용하기

이 라이브러리는 KITAQGB의 __ 내장 함수를 바탕으로 만든 재사용 가능한 C 소스 모음입니다. 화면 제어부터 물리, 3D, 통신까지 다룹니다.

c
#include "input.h"
// 起動時に一度
input_init();
// ゲームの1フレームに一度
input_update();
if (input_pressed(BTN_A)) { /* 決定処理 */ }
powershell
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\gb_input.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input.gb --profile=dev

각 API 항목에는 선언, 헤더, 구현, 사용 예가 있습니다. 인수 전달 예제는 API 호출 방법을 보여 주며, 필요한 버퍼와 오브젝트는 호출 측에서 준비해야 합니다. ROM으로 바로 빌드할 수 있는 예제는 완성 프로그램 절에 있습니다.

2. 게임의 한 프레임 구성

system_init는 프레임 관리를 초기화합니다. system_wait_vblank는 대기 후 소프트웨어 프레임 번호를 증가시킵니다. GB의 VBlank 콜백은 대기 함수가 협력 방식으로 호출합니다. 등록만으로 하드웨어 인터럽트 처리기가 설치되는 것은 아닙니다.

  1. 입력을 한 번 갱신합니다.
  2. 이동, 충돌, 게임 상태를 계산합니다.
  3. 그리기 명령과 OAM을 준비합니다.
  4. VBlank 중 갱신 내용을 적용합니다.
  5. 선택한 드라이버 구성에 맞춰 음악을 진행합니다.

vram_flush, sprite_flush_oam처럼 내부에서 기다리는 함수를 함께 쓰면 게임 갱신 한 번에 두 프레임을 기다릴 수 있습니다. 직접 대기한 뒤에는 대응하는 _now 함수를 쓸 수 있지만, 호출 측에서 시점 조건을 보장해야 합니다.

3. 입력과 반복 입력

input_down(mask)는 누르고 있는 버튼, input_pressed(mask)는 새로 누른 버튼, input_released(mask)는 놓은 버튼을 검사합니다. input_repeat(mask)는 메뉴용 반복 입력을 제공합니다. 상태는 input_update()에서 갱신됩니다. 한 프레임에 여러 번 갱신하면 누른 순간의 정보가 사라질 수 있습니다.

버튼마스크
오른쪽, 왼쪽, 위, 아래0x01 / 0x02 / 0x04 / 0x08
A, B, SELECT, START0x10 / 0x20 / 0x40 / 0x80

gb_input.c는 A를 누른 횟수를 셉니다. 길게 눌러도 계속 증가하지 않는지 확인한 다음, input_pressed를 input_down으로 바꿔 차이를 살펴보세요.

4. 배경, 문자, VRAM

vram_queue_bg_tile은 타일 하나, vram_queue_bg_rect는 사각 영역, vram_queue_bg_block은 배열 전송을 큐에 넣습니다. 반환값과 vram_get_overflowed()로 용량 초과를 확인하세요. 큐가 소스 포인터를 보관하는 경우, 적용이 끝날 때까지 내용을 바꾸지 말고 메모리와 뱅크 접근을 유지해야 합니다.

text.c, menu.c는 rpg.h에 선언된 문자, 선택지, 창 기능을 구현합니다. 문자와 타일의 대응은 VRAM에 올린 글꼴과 맞춰야 합니다. 설명서의 m_text 도우미와 자동으로 같은 대응을 쓰는 것은 아닙니다.

5. 스프라이트와 애니메이션

sprite_init, sprite_alloc, sprite_set_tile, sprite_set_pos부터 사용해 보세요. GB는 전체 40개, 한 주사선 10개까지 스프라이트를 표시하므로 총수뿐 아니라 가로로 몰리는 정도도 고려해야 합니다. sprite_warn_scanline_overflow, sprite_max_scanline_count로 배치를 점검할 수 있습니다.

MetaSpritePart는 상대 OBJ 배치, SpriteAnim은 타일 프레임과 갱신 간격을 정의합니다. metasprite_draw가 그릴 부품 수를 할당한 OBJ 슬롯과 맞추세요. gb_sprite.c의 A는 문자 타일을 스프라이트로 사용하는 예입니다.

6. 색, 스크롤, 래스터 효과, 카메라

cgb_bg_rgb, cgb_obj_rgb의 RGB 인수 범위는 0~31이며 0~255가 아닙니다. CGB_RGB15는 이를 16비트 값에 포장합니다. 고수준 CGB 팔레트 도우미는 DMG에서는 아무것도 하지 않도록 설계되었습니다.

Scroll_SetBg는 배경, Scroll_SetWindow는 윈도 위치를 정합니다. 카메라 모듈은 월드 좌표에서 화면에 보일 범위를 계산합니다. 카메라의 고정소수점 단위와 정수 화면 픽셀을 구별하세요.

raster.c는 구간별 스크롤 표와 주사선별 가로 왜곡을 만듭니다. Scroll_SplitCommit은 VBlank·STAT 벡터를 사용합니다. 음악과 스크롤의 별도 처리기가 같은 벡터를 각각 소유하게 하지 말고, 필요하면 공통 디스패처를 두세요.

7. 음악과 효과음

audio_hwregs_gb.c, audio.c, 게임 소스 순서로 컴파일합니다. 게임에서 NR10~NR52를 이미 선언한다면 중복 정의를 추가하지 마세요. Audio_Init 뒤에는 보통 프레임마다 Audio_Update를 한 번 호출합니다.

Audio_PlayMusic(bank,song)은 음악 뱅크를 명시합니다. Audio_PlaySFXBanked는 다른 뱅크의 효과음을 재생합니다. 같은 물리 채널을 쓰는 효과음은 우선순위로 조정합니다. GB의 물리 음원 채널은 CH1, CH2, CH3, CH4의 네 개입니다.

음악 스트림 명령 AUDIO_CMD_NOTE, AUDIO_CMD_SET_INST, AUDIO_CMD_STOP_CHANNEL은 일반 API와 같은 채널 ID를 사용합니다. 0=CH1, 1=CH2, 2=CH3, 3=CH4입니다. CH1은 스위프가 있는 펄스, CH2는 펄스, CH3는 파형, CH4는 노이즈 채널입니다. 헤더는 AUDIO_NOTE_MAX=67을 정의합니다.

기본 CH1 효과음 스트림은 프레임마다 음표·음량 쌍을 읽고 음표 0에서 끝납니다. CH3는 다른 표식과 형식을 사용합니다. gb_sound.c를 참고하세요. 페이드는 Audio_Update에서 진행되므로 갱신을 멈추면 페이드도 멈춥니다.

8. VBlank IRQ 음악

audio_vblank.c는 별도의 재생 형식을 사용합니다. 시간 지정 레코드는 delay, ch1_note, ch2_note, ch3_note, ch4_noise_param의 5바이트로 구성됩니다. 드라이버는 직접 주소로 접근할 수 있는 곡을 읽거나 WRAM 큐에서 데이터를 소비합니다. AudioVBlank_QueueReset으로 큐 모드를 초기화하고, AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 공급한 뒤, AudioVBlank_QueuePlay로 재생을 시작하세요. 큐 보충은 포그라운드의 단일 공급자에서 수행합니다. LOOP는 직접 스트림에서만, IMMEDIATE는 큐 모드에서만 인식됩니다. 일반 audio.c 스트림을 그대로 전달할 수는 없습니다.

powershell
# この方式を採用したROMに対してのみ行います。
.\kitaqgb\scripts\patch_gb_vblank_irq.ps1 .\out\game.gb .\out\game.map

패치는 0x0040의 VBlank 벡터와 체크섬을 갱신합니다. 이 드라이버를 쓰도록 만든 ROM에만 적용하세요. 사용자 VBlank ISR, 분할 스크롤과 벡터 소유권이 충돌하지 않는지 확인해야 합니다. 빌드 성공만으로 음악 재생이 확인되지는 않습니다. KOKURA로 녹음하여 곡이 진행하는지 들어 보세요.

9. 고정소수점, 물리, 3D

fixed.h의 Q8.8에서는 256이 1.0, 128이 0.5입니다. gb_fixed.c는 fix_from_int, fix_mul, fix_to_int를 사용합니다. 넘침을 피하려면 계산을 구현하기 전에 값의 범위를 정하세요.

physics2d는 사각형, physics2d_circle은 원, physics3d는 3D AABB를 처리합니다. 호출 측에서 world와 body 배열을 준비하고 초기화한 뒤 속도나 중력을 설정하고 step을 호출하세요. 위치와 스텝당 속도의 단위를 일관되게 사용해야 하며, 라이브러리가 자동으로 픽셀 단위로 환산하지는 않습니다. 원 예제는 위치 40과 속도 2를 사용합니다. 역질량 0은 정적 물체를 뜻합니다. 각 계수의 표현과 중간 계산 범위는 헤더를 확인하세요. 특히 kq2d_body_apply_friction은 계수를 부호 있는 8비트 값으로 변환하므로 128~255가 음수가 됩니다. 이를 일반적인 부호 없는 Q8 감쇠 계수로 사용하면 안 됩니다. 한 스텝을 실행하는 예제는 gb_circle.c입니다.

wire3d_dmg는 게임보이용 흑백 와이어프레임 렌더링 라이브러리입니다. 128×96 화면에는 wire3d_dmg_96.c, 128×120 화면에는 wire3d_dmg.c를 빌드하고 Wire3DDMG_* 함수를 사용하세요. wire3d와 dmg3d도 각각 96줄과 120줄 설정을 선택하는 진입점으로 사용할 수 있습니다. 프로그램마다 진입점은 하나만 빌드하세요. wire3d_cgb는 컬러 전용 렌더러입니다. 각 렌더러가 사용하는 RAM, VRAM, 화면 영역을 명확히 확보하세요. 두 흑백 렌더러는 깊이 범위를 가로지르는 선분을 잘라 그리지 않고 생략합니다. 장면의 가려짐도 면의 경계 사각형과 선 위의 다섯 점으로 근사하므로 픽셀별 깊이 검사가 아닙니다. CGB 경로는 배속과 DMA를 사용하며 --cgb=cgb_only가 필요합니다.

Wire3DDMG_BeginFrame (WIRE3D_DMG_HEIGHT=96)은 그리기 버퍼를 지웁니다. 반면 Wire3DDMG_BeginFrame (WIRE3D_DMG_HEIGHT=120)은 가려짐 검사 상태만 초기화하며, DMG3D의 버퍼 데이터는 VRAM에 전송할 때 지워집니다. 변경된 타일만 전송하는 모드에서는 이전 프레임의 타일도 처리하여 옛 픽셀을 없앱니다. 보조 전송은 주 버퍼의 일부를 공유하므로 독립된 버퍼가 아닙니다. 사용하는 렌더러에 맞게 프레임 처리 순서를 구성하세요.

CGB의 선 색상에는 1, 2, 3을 사용합니다. 일반 128 × 96 모드에서는 색상 비트를 겹쳐 그리므로 색상 1과 2가 겹치면 색상 3이 됩니다. 색상 0으로 선을 지울 수는 없습니다. 프레임을 지우거나 전용 지우기 함수를 사용하세요. 일반 Wire3DCGB_DrawLine2D와 모델 그리기 함수는 부분 전송 범위를 기록하지 않습니다. 선을 그리면서 범위도 기록하려면 Wire3DCGB_DrawLineClipped2D를 사용하고, 다음 부분 전송에 화면 전체를 포함하려면 Wire3DCGB_InvalidateFrameHistory를 호출하세요.

160 × 144 모드에서는 프레임당 최대 127개의 타일을 할당합니다. 고속 선 그리기 경로에서 타일 할당에 실패하거나 화면 밖 좌표를 만나면 Wire3DCGB_GetFullScreenOverflow()가 0이 아닌 값을 반환하며, 다음 프레임 초기화까지 픽셀 쓰기가 중단됩니다. 꼭짓점은 선택한 화면 영역 안에 두세요. 삼각형 마스크의 오른쪽 여유 폭은 128 × 96 모드에서 X=127, 전체 화면 모드에서 X=159까지만 확장됩니다. 특히 전체 화면과 FastMap을 사용할 때는 각 API에 명시된 WRAM 뱅크 설정을 지켜야 합니다.

10. 장면, 오브젝트 풀, 탄막

scene은 타이틀·플레이·일시정지 같은 상태를 관리하고, entity는 고정 용량 오브젝트 풀을 제공합니다. chain은 관절형 몸체 추종과 위치 이력을 제공합니다. 마디가 이어진 뱀이나 밧줄을 움직이려면 ChainBody를 사용하세요. entity_get이 반환한 포인터를 사용하기 전에 0xFF 같은 할당 실패값을 확인하세요.

danmaku는 고정소수점 탄환 풀, 방향·부채꼴 발사, 충돌, 스침을 제공합니다. CGB 배경 합성 경로는 일반 OBJ 수 제한을 피하지만 프레임 처리 시간과 배경 전송 대역폭은 여전히 제한됩니다. 탄환 수만 늘리기보다 프레임 처리 시간을 측정하세요.

11. RPG, 어드벤처, 전략, 저장

rpg.h는 난수, 플래그, 퀘스트, 압축, 문자, 메뉴, 스크립트, 맵, 저장, 길 찾기 선언을 모읍니다. 구현은 rng.c, flags.c, rle.c, text.c 등에 나뉘어 있습니다. 사전에서 필요한 구현 파일을 선택하세요.

rng_seed를 고정하면 시험에 쓸 난수열을 재현할 수 있습니다. 범위 함수가 상한을 포함하는지도 확인하세요. flag_get, flag_set은 비트 집합을 다룹니다. save.c는 MBC5 방식 SRAM 접근을 사용하므로 ROM 헤더의 RAM 용량과 실제 저장 영역을 맞춰야 합니다.

slg.h의 보드, 수 목록, 되돌리기와 slg_path.c의 길 찾기는 게임 고유의 규칙·평가와 분리하세요. 너비, 높이, 작업 배열은 개별 인수 조건뿐 아니라 라이브러리 한도에도 맞아야 합니다.

12. 통신

link.c는 시리얼 바이트 전송, link_packet.c는 선택적인 패킷 계층입니다. link_hwregs_gb.c를 먼저 링크하세요. 폴링과 인터럽트 모드는 필요한 호출이 다르며, 인터럽트 모드는 게임 측에서 0x0058 벡터를 연결해야 합니다.

논리 Link4_*와 실제 Nintendo DMG-07용 LinkDmg07_*는 별개 체계입니다. DMG-07은 외부 클록을 사용하므로 LinkDmg07_Poll을 자주, LinkDmg07_TickFrame을 프레임마다 한 번 호출하세요. 프레임당 한 번만 폴링하면 타이밍 요구를 충족하지 못할 수 있습니다. KOKURA의 pair/dmg07 작업에서 연결, 시작, 연결 해제, 재연결을 각각 시험하세요.

13. 뱅크, 리소스, 디버깅

BankPtr는 뱅크 번호와 포인터를 결합합니다. far_data_read는 다른 뱅크의 리소스를 RAM으로 읽습니다. asset 모듈은 ID와 기술자를 연결하지만 수명, 뱅크, 크기는 게임이 관리해야 합니다.

debug_trace_u8, debug_trace_u16은 값을 RAM에 기록하고 debug_assert_fail은 진단 코드를 남깁니다. PC 콘솔로 출력하는 printf가 아닙니다. 에뮬레이터의 메모리 관찰로 기록을 확인하세요. gb_debug.c는 HP=42를 기록합니다.

vram_get_queue_capacity()는 전체 명령 슬롯 수(기본값 32), vram_get_queue_free()는 빈 슬롯 수, vram_get_queue_used()는 사용 중인 슬롯 수를 반환합니다. 전송량과 관계없이 예약한 작업 하나가 슬롯 하나를 차지합니다. 이 값은 전송 큐의 용량이며, 실제 VRAM의 빈 공간을 뜻하지 않습니다.

완성된 예제 프로그램

각 프로그램과 공통 헤더, 제공된 ascii.c, 변환 리소스를 함께 실었습니다. m_으로 시작하는 이름은 설명서용 도우미입니다. 빌드 명령은 기대 결과와 검증 기록을 함께 읽으세요. 명령은 저장소들이 나란히 놓인 상위 폴더에서 실행합니다.

일괄 빌드 스크립트 / 결과와 화면

제공된 문자 집합 표시 gb_font.c

목적: 제공된 독자 제작 글꼴에 어떤 문자·숫자·문장부호가 있는지, 그리고 어떻게 그리는지 알아봅니다.

동작 원리: m_init이 표시와 글꼴을 준비합니다. m_text가 각 행을 그리고, m_put은 문자 코드 34로 큰따옴표를 그립니다.

조작 방법과 기대 결과: 대문자 26개, 소문자 26개, 숫자 10개, 문장부호 30개가 있는지 확인하세요. 모든 글자가 읽기 쉬운지 살펴보세요. 입력 조작은 필요하지 않습니다.

제공된 문자 집합 표시: 대문자 26개, 소문자 26개, 숫자 10개, 문장부호 30개가 있는지 확인하세요. 모든 글자가 읽기 쉬운지 살펴보세요. 입력 조작은 필요하지 않습니다.
표시 예: 대문자 26개, 소문자 26개, 숫자 10개, 문장부호 30개가 있는지 확인하세요. 모든 글자가 읽기 쉬운지 살펴보세요. 입력 조작은 필요하지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe  kitaq-docs/samples/gb_font.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_font.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Display the letters, digits and punctuation from the supplied ascii.c font.
// Expected: Uppercase, lowercase, numbers and all 30 supplied punctuation glyphs
#include "gb_common.h"


// Lay out every supplied character category, yielding between rows. The final
// m_put uses character code 34 to display the double quote separately.
void main() {
    m_init();
    m_text(2,3,"FONT");
    m_text(2,5,"ABCDEFGHIJKLMNOP"); m_wait();
    m_text(2,6,"QRSTUVWXYZ"); m_wait();
    m_text(2,8,"0123456789"); m_wait();
    m_text(2,10,"abcdefghijklmnop"); m_wait();
    m_text(2,11,"qrstuvwxyz"); m_wait();
    m_text(2,13,"!#$%&'()*+,-./"); m_wait();
    m_text(2,14,":;<=>?@[]^_`{}~"); m_wait();
    m_put(16,13,34); m_wait();
    while (1) { m_wait();  }
}
첫 텍스트 표시 gb_hello.c

목적: ROM을 시작하고 배경에 문자와 숫자를 그리는 기본 순서를 알아봅니다.

동작 원리: m_init 후 m_text가 인사말을 그리고 m_number가 42를 표시 형식으로 바꿉니다. 마지막 루프는 화면을 유지하며 프레임을 기다립니다.

조작 방법과 기대 결과: 화면에 HELLO WORLD와 042가 표시됩니다. 앞의 0은 십진수를 세 자리로 표시하기 위한 것입니다.

첫 텍스트 표시: 화면에 HELLO WORLD와 042가 표시됩니다. 앞의 0은 십진수를 세 자리로 표시하기 위한 것입니다.
표시 예: 화면에 HELLO WORLD와 042가 표시됩니다. 앞의 0은 십진수를 세 자리로 표시하기 위한 것입니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe  kitaq-docs/samples/gb_hello.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_hello.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Display a first message on screen.
// Expected: HELLO WORLD and 042
#include "gb_common.h"


// Initialize the display/font, write HELLO WORLD and a three-digit 042,
// then wait for frames so the result remains visible.
void main() {
    m_init();
    m_text(2,3,"HELLO");
    m_text(2,5,"HELLO WORLD");
    m_number(42);
    while (1) { m_wait();  }
}
더 넓은 타입의 중간값으로 연산 gb_arithmetic.c

목적: 8비트로 표현할 수 없는 중간 결과를 보관하는 방법을 알아봅니다.

동작 원리: (u16)200 + 100의 결과는 300입니다. 프로그램은 이를 10으로 나눈 뒤 u8로 변환해 표시합니다. 덧셈 전에 더 넓은 타입으로 캐스팅한다는 점에 주목하세요.

조작 방법과 기대 결과: 030은 계산 결과인 30을 나타냅니다.

더 넓은 타입의 중간값으로 연산: 030은 계산 결과인 30을 나타냅니다.
표시 예: 030은 계산 결과인 30을 나타냅니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe  kitaq-docs/samples/gb_arithmetic.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_arithmetic.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Variables, arithmetic and type conversion.
// Expected: 030
#include "gb_common.h"


// Widen before adding 200 + 100, divide the 16-bit sum, and display 30.
// The cast demonstrates avoiding an 8-bit intermediate result.
void main() {
    m_init();
    m_text(2,3,"ARITHMETIC");
    u16 sum;
    sum = (u16)200 + 100;
    m_number((u8)(sum / 10));
    while (1) { m_wait();  }
}
분기와 반복 gb_control.c

목적: 간단한 계산에서 for, continue, while, do/while, switch를 사용해 봅니다.

동작 원리: 0~7을 더하되 3을 건너뛰면 25가 됩니다. while 루프로 30까지, do/while로 32까지 진행한 뒤 switch의 case 32에서 42를 대입합니다.

조작 방법과 기대 결과: 042는 이 반복문과 분기의 최종 결과입니다.

분기와 반복문: 042는 이 반복문과 분기의 최종 결과입니다.
표시 예: 042는 이 반복문과 분기의 최종 결과입니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe  kitaq-docs/samples/gb_control.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_control.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Conditional branches and loops.
// Expected: 042
#include "gb_common.h"


// Exercise loop control and a final branch, then display the selected value 42.
void main() {
    m_init();
    m_text(2,3,"CONTROL");
    u8 i; u8 sum; sum=0;
    for (i=0;i<8;i++) { if (i==3) continue; sum=(u8)(sum+i); }
    while (sum<30) { sum++; }
    do { sum++; } while (sum<32);
    switch (sum) { case 32: sum=42; break; default: sum=0; break; }
    m_number(sum);
    while (1) { m_wait();  }
}
함수, 배열, 구조체, 포인터 gb_aggregate.c

목적: 값을 묶고 함수와 포인터로 접근하는 방법을 알아봅니다.

동작 원리: 프로그램은 (10,20)을 담은 Point를 복사한 뒤 포인터로 배열에 1부터 4까지 씁니다. 함수 결과 30에 배열 값 1, 2, 4와 상수 5를 더합니다.

조작 방법과 기대 결과: 합계가 042로 표시됩니다. 구조체 복사, ptr[i]에 쓰는 과정과 함수 반환값을 따라가 보세요.

함수, 배열, 구조체, 포인터: 합계가 042로 표시됩니다. 구조체 복사, ptr[i]에 쓰는 과정과 함수 반환값을 따라가 보세요.
표시 예: 합계가 042로 표시됩니다. 구조체 복사, ptr[i]에 쓰는 과정과 함수 반환값을 따라가 보세요.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe  kitaq-docs/samples/gb_aggregate.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_aggregate.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Functions, arrays, structures and pointers.
// Expected: 042
#include "gb_common.h"

typedef struct { u8 x; u8 y; } Point;
// Add two byte values and explicitly narrow the returned result to u8.
u8 add(u8 a,u8 b) { return (u8)(a+b); }
// Copy a structure, fill an array through a pointer, and combine selected values
// through add() to produce 42. Keep the final screen visible in the idle loop.
void main() {
    m_init();
    m_text(2,3,"AGGREGATE");
    Point a; Point b; u8 i; u8 data[4]; u8* ptr;
    a.x=10; a.y=20; b=a; ptr=data;
    for(i=0;i<4;i++) ptr[i]=(u8)(i+1);
    m_number((u8)(add(b.x,b.y)+ptr[0]+ptr[1]+ptr[3]+5));
    while (1) { m_wait();  }
}
비트 플래그와 버퍼 복사 gb_bits_memory.c

목적: 플래그를 한 바이트에 담고 버퍼를 별도 저장 공간에 복사합니다.

동작 원리: __memset으로 4바이트를 지웁니다. 비트 3을 설정하고 비트 1을 반전한 뒤 __memcpy로 4바이트 모두를 복사합니다.

조작 방법과 기대 결과: 복사 대상의 첫 바이트가 010으로 표시됩니다. 비트 3의 값 8과 비트 1의 값 2를 더한 결과입니다.

비트 플래그와 버퍼 복사: 복사 대상의 첫 바이트가 010으로 표시됩니다. 비트 3의 값 8과 비트 1의 값 2를 더한 결과입니다.
표시 예: 복사 대상의 첫 바이트가 010으로 표시됩니다. 비트 3의 값 8과 비트 1의 값 2를 더한 결과입니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe  kitaq-docs/samples/gb_bits_memory.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_bits_memory.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Bit operations and memory copying.
// Expected: 010
#include "gb_common.h"
void __memset(void* dst,u8 value,u16 len);
void __memcpy(void* dst,const void* src,u16 len);
void __bit_set(u8* base,u16 bit);
void __bit_toggle(u8* base,u16 bit);

// Clear the source bytes, set bits 3 and 1, copy the buffer, and display 8 + 2 = 10.
void main() {
    m_init();
    m_text(2,3,"BITS MEMORY");
    u8 data[4]; u8 copy[4];
    __memset(data,0,4); __bit_set(data,3); __bit_toggle(data,1);
    __memcpy(copy,data,4); m_number(copy[0]);
    while (1) { m_wait();  }
}
새로 누른 버튼 횟수 세기 gb_input.c

목적: 버튼을 새로 누른 경우와 계속 누르고 있는 경우를 구분합니다.

동작 원리: 매 프레임 input_update를 호출합니다. input_pressed(BTN_A)가 참일 때만 카운터가 증가합니다.

조작 방법과 기대 결과: 초기값은 000입니다. A를 누르면 001이 되며, 누르고 있어도 증가하지 않습니다. 버튼을 놓았다가 다시 누르면 002가 됩니다. 바이트 카운터는 255 다음에 000으로 돌아갑니다.

새로 누른 버튼 횟수 세기: 초기값은 000입니다. A를 누르면 001이 되며, 누르고 있어도 증가하지 않습니다. 버튼을 놓았다가 다시 누르면 002가 됩니다. 바이트 카운터는 255 다음에 000으로 돌아갑니다.
표시 예: 초기값은 000입니다. A를 누르면 001이 되며, 누르고 있어도 증가하지 않습니다. 버튼을 놓았다가 다시 누르면 002가 됩니다. 바이트 카운터는 255 다음에 000으로 돌아갑니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/input.c kitaq-docs/samples/gb_input.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_input.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Distinguish a new button press from a held button.
// Expected: 000 initially; A increments once per press
#include "gb_common.h"
#include "input.h"
u8 manual_count;
// Sample buttons once per frame and increment only on a new A press.
// Holding A does not repeatedly increment; the byte-sized counter wraps after 255.
void main() {
    m_init();
    m_text(2,3,"INPUT");
    input_init();
    m_number(0);
    while (1) { m_wait(); input_update(); if(input_pressed(BTN_A)) { manual_count++; m_number(manual_count); } }
}
Q8.8 고정소수점 값 곱하기 gb_fixed.c

목적: 정수를 Q8.8로 변환하고 곱한 다음 다시 정수로 바꾸는 방법을 알아봅니다.

동작 원리: fix_from_int가 3과 4를 Q8.8로 변환합니다. fix_mul로 곱하고 fix_to_int로 결과를 다시 정수로 바꿉니다.

조작 방법과 기대 결과: 012는 3 × 4 = 12를 뜻합니다. 256배로 저장된 내부값이 아니라 변환한 정수입니다.

Q8.8 고정소수점 값 곱하기: 012는 3 × 4 = 12를 뜻합니다. 256배로 저장된 내부값이 아니라 변환한 정수입니다.
표시 예: 012는 3 × 4 = 12를 뜻합니다. 256배로 저장된 내부값이 아니라 변환한 정수입니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/fixed.c kitaq-docs/samples/gb_fixed.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_fixed.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Calculate with signed Q8.8 fixed-point values.
// Expected: 012
#include "gb_common.h"
#include "fixed.h"

// Convert 3 and 4 to Q8.8, multiply them, convert the result back to an
// integer, and display 12.
void main() {
    m_init();
    m_text(2,3,"FIXED");
    fix8 a; fix8 b; a=fix_from_int(3); b=fix_from_int(4);
    m_number((u8)fix_to_int(fix_mul(a,b)));
    while (1) { m_wait();  }
}
고정 오브젝트 풀에서 할당 gb_entity.c

목적: 동적 할당 없이 고정 슬롯 집합에서 오브젝트를 생성합니다.

동작 원리: entity_init이 풀을 초기화합니다. entity_create가 (20,30)에 타입 1을 만들고, 프로그램은 실패 ID 0xFF가 아닌지 확인한 뒤 vx를 2로 설정합니다.

조작 방법과 기대 결과: 001은 활성 오브젝트 수이며 ID나 좌표가 아닙니다. 이 예제는 오브젝트를 갱신하거나 그리지 않으므로 움직이는 캐릭터는 나타나지 않습니다.

고정 오브젝트 풀에서 할당: 001은 활성 오브젝트 수이며 ID나 좌표가 아닙니다. 이 예제는 오브젝트를 갱신하거나 그리지 않으므로 움직이는 캐릭터는 나타나지 않습니다.
표시 예: 001은 활성 오브젝트 수이며 ID나 좌표가 아닙니다. 이 예제는 오브젝트를 갱신하거나 그리지 않으므로 움직이는 캐릭터는 나타나지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/entity.c kitaq-docs/samples/gb_entity.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_entity.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Allocate an entity from a fixed-capacity object pool.
// Expected: 001
#include "gb_common.h"
#include "entity.h"

// Create one entity and check the 0xFF allocation-failure sentinel before
// accessing its velocity. Display the pool occupancy, not the entity ID.
void main() {
    m_init();
    m_text(2,3,"ENTITY");
    u8 id; entity_init(); id=entity_create(1,20,30);
    if(id!=0xFF) entity_get(id)->vx=2; m_number(entity_count_active());
    while (1) { m_wait();  }
}
RAM에 진단 값 기록 gb_debug.c

목적: 화면 표시와 별개로 이름이 붙은 게임 값을 진단 버퍼에 보관합니다.

동작 원리: 디버깅을 초기화하고 프레임 태그를 1로 설정한 뒤 HP라는 이름으로 값 42를 기록합니다.

조작 방법과 기대 결과: 001은 추적 항목 수입니다. HP=42는 진단 버퍼에 저장되며, 화면만으로는 그 내용을 보거나 검증할 수 없습니다.

RAM에 진단 값 기록: 001은 추적 항목 수입니다. HP=42는 진단 버퍼에 저장되며, 화면만으로는 그 내용을 보거나 검증할 수 없습니다.
표시 예: 001은 추적 항목 수입니다. HP=42는 진단 버퍼에 저장되며, 화면만으로는 그 내용을 보거나 검증할 수 없습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/debug.c kitaq-docs/samples/gb_debug.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_debug.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Record diagnostic values in the debug trace.
// Expected: 001; trace log contains HP=42
#include "gb_common.h"
#include "debug.h"

// Record HP = 42 with frame tag 1 and display the number of trace entries.
// The trace buffer contains the value; the screen displays the count, not HP.
void main() {
    m_init();
    m_text(2,3,"DEBUG");
    debug_init(); debug_set_frame(1); debug_trace_u8("HP",42);
    m_number(debug_get_trace_count());
    while (1) { m_wait();  }
}
위치 이력 저장 gb_chain.c

목적: 위치 이력을 링 버퍼에 저장하는 방법을 알아봅니다.

동작 원리: chain_init은 점 4개를 담을 수 있는 배열을 연결합니다. 그다음 chain_push_head가 (20,30)을 기록합니다.

조작 방법과 기대 결과: 042는 고정된 완료 표시이며 좌표나 개수가 아닙니다. 저장된 이력은 trail과 points를 살펴보세요. 이 프로그램은 따라오는 몸체를 그리지 않습니다.

위치 이력 저장: 042는 고정된 완료 표시이며 좌표나 개수가 아닙니다. 저장된 이력은 trail과 points를 살펴보세요. 이 프로그램은 따라오는 몸체를 그리지 않습니다.
표시 예: 042는 고정된 완료 표시이며 좌표나 개수가 아닙니다. 저장된 이력은 trail과 points를 살펴보세요. 이 프로그램은 따라오는 몸체를 그리지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/chain.c kitaq-docs/samples/gb_chain.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_chain.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Store a position history in a ring buffer.
// Expected: 042; history contains (20,30)
#include "gb_common.h"
#include "chain.h"
Chain trail; ChainPoint points[4];
// Attach four history slots and record one point. The displayed 42 is a fixed
// completion marker; inspect the chain to verify the stored (20,30) point.
void main() {
    m_init();
    m_text(2,3,"CHAIN");
    chain_init(&trail,points,4); chain_push_head(&trail,20,30);
    m_number(42);
    while (1) { m_wait();  }
}
라이브러리 프레임 카운터 읽기 gb_system.c

목적: 프레임 단위 대기가 라이브러리 프레임 카운터에 미치는 영향을 확인합니다.

동작 원리: system_init 후 프로그램은 system_wait_vblank를 두 번 호출하고 system_get_frame8을 표시합니다.

조작 방법과 기대 결과: 결과는 002입니다. 대기 루프는 매뉴얼 보조 함수 m_wait를 사용하므로 표시 값이 계속 증가하지 않습니다.

라이브러리 프레임 카운터 읽기: 결과는 002입니다. 대기 루프는 매뉴얼 보조 함수 m_wait를 사용하므로 표시 값이 계속 증가하지 않습니다.
표시 예: 결과는 002입니다. 대기 루프는 매뉴얼 보조 함수 m_wait를 사용하므로 표시 값이 계속 증가하지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/system.c kitaq-docs/samples/gb_system.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_system.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Count completed frame waits.
// Expected: 002
#include "gb_common.h"
#include "system.h"

// Reset the library frame count, perform two counted waits, and display 2.
// Subsequent m_wait calls leave that library counter unchanged.
void main() {
    m_init();
    m_text(2,3,"SYSTEM");
    system_init(); system_wait_vblank(); system_wait_vblank();
    m_number(system_get_frame8());
    while (1) { m_wait();  }
}
현재 장면 ID 선택 gb_scene.c

목적: 타이틀 화면과 플레이 화면 등을 구분하는 ID를 선택하는 방법을 알아봅니다.

동작 원리: 0으로 초기화한 SceneDef 항목 두 개를 등록하고 scene_change로 ID 1을 선택합니다.

조작 방법과 기대 결과: 001은 scene_get_current가 반환한 현재 ID입니다. 이 예제에는 장면 콜백이나 전환 그리기가 등록되어 있지 않습니다.

현재 장면 ID 선택: 001은 scene_get_current가 반환한 현재 ID입니다. 이 예제에는 장면 콜백이나 전환 그리기가 등록되어 있지 않습니다.
표시 예: 001은 scene_get_current가 반환한 현재 ID입니다. 이 예제에는 장면 콜백이나 전환 그리기가 등록되어 있지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/scene.c kitaq-docs/samples/gb_scene.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_scene.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Switch the current scene ID.
// Expected: 001; no callbacks registered
#include "gb_common.h"
#include "scene.h"
SceneDef manual_scenes[2];
// Register two zero-initialized scene entries, select ID 1 and display it.
// No callbacks are registered in this example.
void main() {
    m_init();
    m_text(2,3,"SCENE");
    scene_init(manual_scenes,2); scene_change(1);
    m_number(scene_get_current());
    while (1) { m_wait();  }
}
월드 좌표를 화면 좌표로 변환 gb_camera.c

목적: 월드 위치에서 카메라 위치를 빼서 화면상 위치를 구합니다.

동작 원리: Camera_Set에 Q8.8 값 2560, 즉 X=10픽셀을 전달합니다. 그다음 Camera_WorldToScreenX가 월드 좌표 X=52를 변환합니다.

조작 방법과 기대 결과: 052에서 010을 빼면 표시된 042가 됩니다. 좌표 계산이며 배경을 스크롤하지 않습니다.

월드 좌표를 화면 좌표로 변환: 052에서 010을 빼면 화면에 042가 표시됩니다. 좌표 계산 예제이며 배경을 스크롤하지 않습니다.
표시 예: 052에서 010을 빼면 표시된 042가 됩니다. 좌표 계산이며 배경을 스크롤하지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/scroll.c kitaqgb/lib/camera.c kitaq-docs/samples/gb_camera.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_camera.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Convert world coordinates to screen coordinates.
// Expected: 042: world x=52 minus camera x=10
#include "gb_common.h"
#include "camera.h"
Camera8_8 cam;
// Set the camera X coordinate to 10 pixels in Q8.8 (10 * 256), then subtract
// it from world X = 52 to display screen X = 42.
void main() {
    m_init();
    m_text(2,3,"CAMERA");
    Camera_Init(&cam); Camera_Set(&cam,2560,0);
    m_number((u8)Camera_WorldToScreenX(&cam,52));
    while (1) { m_wait();  }
}
RLE 데이터를 RAM으로 압축 해제 gb_rle.c

목적: 반복 바이트를 횟수와 값으로 간결하게 표현해 봅니다.

동작 원리: 압축 바이트 {3,42,0}은 42를 세 번 반복한 뒤 반복 횟수 0으로 끝낸다는 뜻입니다. rle_decode는 3바이트 대상 버퍼에 씁니다.

조작 방법과 기대 결과: 마지막 바이트 out[2]가 042로 표시됩니다. 해제된 세 바이트의 값은 모두 42여야 합니다.

RLE 데이터를 RAM으로 압축 해제: 마지막 바이트 out[2]가 042로 표시됩니다. 해제된 세 바이트의 값은 모두 42여야 합니다.
표시 예: 마지막 바이트 out[2]가 042로 표시됩니다. 해제된 세 바이트의 값은 모두 42여야 합니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/rle.c kitaq-docs/samples/gb_rle.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_rle.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Decode run-length encoded data.
// Expected: 042; three bytes each equal to 42
#include "gb_common.h"
#include "rpg.h"
__prg_rom u8 packed[] = {3,42,0};
// Decode count/value pair (3,42), terminated by a zero count, into a
// three-byte buffer and display the final decoded byte.
void main() {
    m_init();
    m_text(2,3,"RLE");
    u8 out[3]; rle_decode(out,packed); m_number(out[2]);
    while (1) { m_wait();  }
}
보드 셀 읽기와 쓰기 gb_board.c

목적: 보드게임의 격자 좌표가 저장 위치에 어떻게 대응하는지 알아봅니다.

동작 원리: 16바이트 배열로 4×4 보드를 저장합니다. 프로그램은 보드를 지우고 셀 (2,1)에 42를 쓴 뒤 같은 셀을 다시 읽습니다.

조작 방법과 기대 결과: 042는 다시 읽어 온 값입니다. 프로그램은 4×4 보드 자체를 그리지 않습니다.

보드 셀 읽기와 쓰기: 042는 다시 읽어 온 값입니다. 프로그램은 4×4 보드 자체를 그리지 않습니다.
표시 예: 042는 다시 읽어 온 값입니다. 프로그램은 4×4 보드 자체를 그리지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/slg_board.c kitaq-docs/samples/gb_board.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_board.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Read and write cells in a game board.
// Expected: 042
#include "gb_common.h"
#include "slg.h"
SLGBoard board; u8 cells[16];
// Create a cleared 4-by-4 board in caller-owned storage, write 42 at (2,1),
// and display the value read back from the same cell.
void main() {
    m_init();
    m_text(2,3,"BOARD");
    slg_board_init(&board,4,4,cells); slg_board_clear(&board,0);
    slg_board_set(&board,2,1,42); m_number(slg_board_get(&board,2,1));
    while (1) { m_wait();  }
}
상자를 물리 계산 한 단계만큼 진행 gb_physics.c

목적: 월드와 상자 물체를 초기화한 다음 속도로 위치를 갱신합니다.

동작 원리: 물체는 위치 (40,40), 속도 (2,0), 중력 0으로 시작합니다. 프로그램은 kq2d_step을 한 번 호출합니다.

조작 방법과 기대 결과: 042는 계산된 X 좌표이며, 이 예제의 단위는 정수 픽셀입니다. 상자 모양이나 연속 애니메이션은 그리지 않습니다.

상자를 물리 계산 한 단계만큼 진행: 042는 계산된 X 좌표이며, 이 예제의 단위는 정수 픽셀입니다. 상자 모양이나 연속 애니메이션은 그리지 않습니다.
표시 예: 042는 계산된 X 좌표이며, 이 예제의 단위는 정수 픽셀입니다. 상자 모양이나 연속 애니메이션은 그리지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/fixed.c kitaqgb/lib/physics2d.c kitaq-docs/samples/gb_physics.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_physics.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Advance a rectangular body through one physics step.
// Expected: 042: integer pixel coordinates
#include "gb_common.h"
#include "physics2d.h"
KQWorld2D world; KQBody2D boxes[1];
// Create one box at X = 40, set horizontal velocity 2 and zero gravity,
// then display its X coordinate after a single physics step.
void main() {
    m_init();
    m_text(2,3,"PHYSICS");
    kq2d_world_init(&world,boxes,1);
    kq2d_body_init(&boxes[0],40,40,4,4);
    kq2d_body_set_velocity(&boxes[0],2,0);
    world.gravity_x=0; world.gravity_y=0;
    kq2d_step(&world); m_number((u8)boxes[0].x);
    while (1) { m_wait();  }
}
뱅크 인수로 ROM 데이터 읽기 gb_bank.c

목적: ROM 데이터를 RAM으로 복사할 때 필요한 인수를 알아봅니다.

동작 원리: far_data_read가 뱅크 인수 0과 길이 2를 사용해 바이트 7과 42를 copied로 복사합니다.

조작 방법과 기대 결과: 복사 대상의 두 번째 바이트가 042로 표시됩니다. 이 예제는 고정 ROM을 읽으며 서로 다른 전환 가능 뱅크 사이의 전송은 보여 주지 않습니다.

뱅크 인수로 ROM 데이터 읽기: 복사 대상의 두 번째 바이트가 042로 표시됩니다. 이 예제는 고정 ROM을 읽으며 서로 다른 전환 가능 뱅크 사이의 전송은 보여 주지 않습니다.
표시 예: 복사 대상의 두 번째 바이트가 042로 표시됩니다. 이 예제는 고정 ROM을 읽으며 서로 다른 전환 가능 뱅크 사이의 전송은 보여 주지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/bank.c kitaq-docs/samples/gb_bank.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_bank.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Read data using an explicit ROM bank.
// Expected: 042; explicit bank argument 0
#include "gb_common.h"
#include "bank.h"
__prg_rom u8 values[] = {7,42}; u8 copied[2];
// Copy two ROM bytes using bank argument zero and display the second byte.
// This introduces the API; it does not test switching between distinct payload banks.
void main() {
    m_init();
    m_text(2,3,"BANK");
    far_data_read(0,values,copied,2); m_number(copied[1]);
    while (1) { m_wait();  }
}
자산 ID로 데이터 불러오기 gb_asset.c

목적: 자산의 위치와 길이를 등록한 뒤 ID로 바이트 데이터를 가져옵니다.

동작 원리: 자산 0의 타입은 RAW, 뱅크는 0이며 {7,42}를 가리키는 포인터와 길이 2를 갖습니다. asset_load_raw가 이를 2바이트 RAM 버퍼에 복사합니다.

조작 방법과 기대 결과: 두 번째 바이트가 042로 표시됩니다. 자산 검색과 복사를 보여 주는 예제이며 이미지 렌더링 예제는 아닙니다.

자산 ID로 데이터 불러오기: 두 번째 바이트가 042로 표시됩니다. 자산 검색과 복사를 보여 주는 예제이며 이미지 렌더링 예제는 아닙니다.
표시 예: 두 번째 바이트가 042로 표시됩니다. 자산 검색과 복사를 보여 주는 예제이며 이미지 렌더링 예제는 아닙니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/asset.c kitaq-docs/samples/gb_asset.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_asset.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Load asset bytes into RAM by asset ID.
// Expected: 042
#include "gb_common.h"
#include "asset.h"
AssetDesc table[1]; __prg_rom u8 values[] = {7,42}; u8 copied[2];
// Register a two-byte raw asset, copy it into RAM and display its second byte.
// This example uses bank zero and a destination sized for the complete payload.
void main() {
    m_init();
    m_text(2,3,"ASSET");
    table[0].type=ASSET_TYPE_RAW; table[0].bank=0;
    table[0].ptr=values; table[0].len=2;
    asset_set_table(0,table,1); asset_load_raw(0,copied,2);
    m_number(copied[1]);
    while (1) { m_wait();  }
}
탄 하나 할당 gb_danmaku.c

목적: 탄 풀을 초기화하고 생성 후 사용 중인 슬롯 수를 확인합니다.

동작 원리: danmaku_reset 후 프로그램은 danmaku_spawn(40,40,16,0)을 호출하고 dm_count를 표시합니다.

조작 방법과 기대 결과: 001은 할당된 탄 수입니다. 탄 갱신 루프나 배경 합성기가 없으므로 움직이는 탄은 그리지 않습니다.

탄 하나 할당: 001은 할당된 탄 수입니다. 탄 갱신 루프나 배경 합성기가 없으므로 움직이는 탄은 그리지 않습니다.
표시 예: 001은 할당된 탄 수입니다. 탄 갱신 루프나 배경 합성기가 없으므로 움직이는 탄은 그리지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/danmaku.c kitaq-docs/samples/gb_danmaku.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_danmaku.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Allocate a bullet and inspect the pool count.
// Expected: 001; numeric pool example, no bullet BG compositor
#include "gb_common.h"
#include "danmaku.h"

// Reset the bullet pool, spawn one bullet and display the active count.
// This numeric example does not install the background bullet compositor.
void main() {
    m_init();
    m_text(2,3,"DANMAKU");
    danmaku_reset(); danmaku_spawn(40,40,16,0);
    m_number(dm_count);
    while (1) { m_wait();  }
}
CGB 배경 팔레트 설정 gb_cgb_palette.c

목적: Game Boy Color의 RGB 성분으로 배경색과 글자색을 선택합니다.

동작 원리: 프로그램은 VBlank 중 LCD를 끄고 팔레트 0의 색상 0을 흰색 (31,31,31), 색상 3을 보라색 (12,0,22)으로 설정한 뒤 표시를 켭니다.

조작 방법과 기대 결과: CGB 모드에서 실행하면 흰 바탕에 보라색 글자와 042가 표시됩니다. DMG의 흑백 출력으로는 이 색상을 확인할 수 없습니다.

CGB 배경 팔레트 설정: CGB 모드에서 실행하면 흰 바탕에 보라색 글자와 042가 표시됩니다. DMG의 흑백 출력으로는 이 색상을 확인할 수 없습니다.
표시 예: CGB 모드에서 실행하면 흰 바탕에 보라색 글자와 042가 표시됩니다. DMG의 흑백 출력으로는 이 색상을 확인할 수 없습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/cgb_palette.c kitaq-docs/samples/gb_cgb_palette.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_cgb_palette.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb
c
// Set Game Boy Color palette entries.
// Expected: 042 in purple on white; CGB mode
#include "gb_common.h"
#include "cgb_palette.h"

// Set palette-zero background colors to white and purple, then display 42.
// Run the ROM in CGB mode to observe the color result.
void main() {
    m_init();
    m_text(2,3,"CGB PALETTE");
    // Disable the LCD during VBlank so both palette bytes remain accessible.
    m_wait(); M_LCDC = 0;
    cgb_bg_rgb(0,0,31,31,31); cgb_bg_rgb(0,3,12,0,22);
    M_LCDC = 0x91;
    m_number(42);
    while (1) { m_wait();  }
}
배경을 가로로 스크롤 gb_scroll.c

목적: 배경 내용을 다시 그리지 않고 화면의 표시 위치를 이동합니다.

동작 원리: 매 프레임 phase를 증가시켜 Scroll_SetBg에 전달합니다. 8비트 위치 값은 255 다음에 0으로 돌아갑니다.

조작 방법과 기대 결과: SCROLL이라는 글자가 왼쪽으로 이동합니다. 시간에 따라 위치가 바뀌는지 확인하세요. 스크린샷 한 장으로는 움직임을 확인할 수 없습니다.

배경을 가로로 스크롤: SCROLL이라는 글자가 왼쪽으로 이동합니다. 시간에 따라 위치가 바뀌는지 확인하세요. 스크린샷 한 장으로는 움직임을 확인할 수 없습니다.
표시 예: SCROLL이라는 글자가 왼쪽으로 이동합니다. 시간에 따라 위치가 바뀌는지 확인하세요. 스크린샷 한 장으로는 움직임을 확인할 수 없습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/scroll.c kitaq-docs/samples/gb_scroll.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_scroll.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Scroll the background horizontally.
// Expected: title moves left as SCX increases
#include "gb_common.h"
#include "scroll.h"
u8 phase;
// Advance an 8-bit horizontal scroll position once per frame, wrapping naturally
// after 255. Background motion demonstrates the changing scroll register.
void main() {
    m_init();
    m_text(2,3,"SCROLL");
    Scroll_SetBg(0,0);
    while (1) { m_wait(); phase++; Scroll_SetBg(phase,0); }
}
타일 갱신을 큐에 등록 gb_vram_queue.c

목적: 그리기 요청과 이를 적용하는 VRAM 전송을 분리합니다.

동작 원리: vram_queue_bg_tile이 타일 좌표 (3,8)에 타일 52를 예약하고 vram_flush가 전송합니다. 제공된 글꼴에서 타일 52는 숫자 4입니다.

조작 방법과 기대 결과: 배경 타일 좌표 (3,8)에 숫자 4 하나가 표시되는지 확인하세요. 타일 갱신이며 숫자 카운터가 아닙니다.

타일 갱신을 큐에 등록: 배경 타일 좌표 (3,8)에 숫자 4 하나가 표시되는지 확인하세요. 타일 갱신이며 숫자 카운터가 아닙니다.
표시 예: 배경 타일 좌표 (3,8)에 숫자 4 하나가 표시되는지 확인하세요. 타일 갱신이며 숫자 카운터가 아닙니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/vram.c kitaq-docs/samples/gb_vram_queue.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_vram_queue.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Queue a VRAM update and flush it at VBlank.
// Expected: 4 at (3,8)
#include "gb_common.h"
#include "vram.h"

// Queue font tile 52 (the digit 4) at tile coordinate (3,8), then wait for
// VBlank and execute the queued transfer.
void main() {
    m_init();
    m_text(2,3,"VRAM QUEUE");
    vram_init();
    vram_queue_bg_tile(3,8,52); vram_flush();
    while (1) { m_wait();  }
}
OAM DMA로 스프라이트 표시 gb_sprite.c

목적: 배경과 별개로 스프라이트를 할당하고 표시합니다.

동작 원리: 초기화된 풀은 슬롯 0을 제공합니다. 프로그램은 타일 65와 위치 (70,80)를 설정하고 OBJ 표시를 켠 뒤 매 프레임 섀도 OAM을 전송합니다.

조작 방법과 기대 결과: 지정한 스프라이트 위치에 정지된 문자 A가 나타납니다. 게임에서는 반환된 ID를 쓰기 전에 할당 실패 여부를 확인하세요.

OAM DMA로 스프라이트 표시: 지정한 스프라이트 위치에 정지된 문자 A가 나타납니다. 게임에서는 반환된 ID를 사용하기 전에 할당 실패 여부를 확인하세요.
표시 예: 지정한 스프라이트 위치에 정지된 문자 A가 나타납니다. 게임에서는 반환된 ID를 쓰기 전에 할당 실패 여부를 확인하세요.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/sprite.c kitaq-docs/samples/gb_sprite.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_sprite.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Display a sprite through the OAM DMA path.
// Expected: letter A at sprite position
#include "gb_common.h"
#include "sprite.h"

// Allocate the first sprite, choose font tile 65 (A), set its position and
// enable sprite display. Flush shadow OAM after each frame wait.
void main() {
    m_init();
    m_text(2,3,"SPRITE");
    // The freshly reset pool guarantees slot zero for this first allocation.
    // In a running game, check the allocation-failure sentinel before using the returned ID.
    sprite_init(); sprite_set_tile(sprite_alloc(),65);
    sprite_set_pos(0,70,80); M_LCDC=(u8)(M_LCDC|2);
    while (1) { m_wait(); sprite_flush_oam_now(); }
}
재현 가능한 난수 생성 gb_rng.c

목적: 시드를 사용해 의사 난수열을 재현합니다.

동작 원리: rng_seed(1234)로 생성기를 초기화한 뒤 rng_range(10)을 한 번 호출합니다. 상한인 10은 결과에 포함되지 않습니다.

조작 방법과 기대 결과: 화면에 000부터 009까지의 값 하나가 표시됩니다. 같은 프로그램을 같은 시드로 다시 시작하면 같은 값이 나오며, 매 프레임 바뀌지는 않습니다.

재현 가능한 난수 생성: 화면에 000부터 009까지의 값 하나가 표시됩니다. 같은 프로그램을 같은 시드로 다시 시작하면 같은 값이 나오며, 매 프레임 바뀌지는 않습니다.
표시 예: 화면에 000부터 009까지의 값 하나가 표시됩니다. 같은 프로그램을 같은 시드로 다시 시작하면 같은 값이 나오며, 매 프레임 바뀌지는 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/rng.c kitaq-docs/samples/gb_rng.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_rng.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Generate a repeatable pseudorandom value from a seed.
// Expected: value 000 through 009; same seed repeats
#include "gb_common.h"
#include "rpg.h"

// Seed the generator with 1234 and display one value in [0,10).
// Restarting with the same seed reproduces the sequence.
void main() {
    m_init();
    m_text(2,3,"RNG");
    rng_seed(1234); m_number(rng_range(10));
    while (1) { m_wait();  }
}
게임 상태 플래그 저장 gb_flags.c

목적: 이벤트 완료 여부 같은 불리언 상태를 플래그 번호로 표현합니다.

동작 원리: 프로그램은 플래그 12를 지우고 설정한 뒤 flag_get으로 다시 읽습니다.

조작 방법과 기대 결과: 001은 플래그 12가 참임을 뜻합니다. 이 예제는 RAM의 플래그를 조작하며 전원을 껐다 켠 뒤까지 저장하지는 않습니다.

게임 상태 플래그 저장: 001은 플래그 12가 참임을 뜻합니다. 이 예제는 RAM의 플래그를 조작하며 전원을 껐다 켠 뒤까지 저장하지는 않습니다.
표시 예: 001은 플래그 12가 참임을 뜻합니다. 이 예제는 RAM의 플래그를 조작하며 전원을 껐다 켠 뒤까지 저장하지는 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/flags.c kitaq-docs/samples/gb_flags.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_flags.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Read and write RAM-backed game-state flags.
// Expected: 001
#include "gb_common.h"
#include "rpg.h"

// Clear and set flag 12, then display its Boolean value. This does not write
// a save file or demonstrate persistence across power cycles.
void main() {
    m_init();
    m_text(2,3,"FLAGS");
    flag_clear(12); flag_set(12); m_number(flag_get(12));
    while (1) { m_wait();  }
}
원을 물리 계산 한 단계만큼 진행 gb_circle.c

목적: 원형 물체를 설정하고 속도로 위치를 갱신합니다.

동작 원리: 활성 원의 반지름은 4, 위치는 (40,40), 속도는 (2,0)입니다. 중력은 0, linear_damping_q8은 255이며 kq2dc_step을 한 번 실행합니다.

조작 방법과 기대 결과: 042는 계산된 정수 X 좌표입니다. 이 예제는 원 외곽선이나 충돌 애니메이션을 그리지 않습니다.

원을 물리 계산 한 단계만큼 진행: 042는 계산된 정수 X 좌표입니다. 이 예제는 원 외곽선이나 충돌 애니메이션을 그리지 않습니다.
표시 예: 042는 계산된 정수 X 좌표입니다. 이 예제는 원 외곽선이나 충돌 애니메이션을 그리지 않습니다.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/physics2d_circle.c kitaq-docs/samples/gb_circle.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_circle.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Advance a circular body through one physics step.
// Expected: 042 after one step; this example uses integer pixels
#include "gb_common.h"
#include "physics2d_circle.h"
KQCircleBody2D balls[1]; KQCircleWorld2D world;
// Activate one circle at X = 40 with horizontal velocity 2 and zero gravity.
// Advance one step and display its resulting integer-pixel X coordinate.
void main() {
    m_init();
    m_text(2,3,"CIRCLE");
    kq2dc_world_init(&world,balls,1);
    balls[0].active=1; balls[0].x=40; balls[0].y=40;
    balls[0].radius=4; balls[0].inv_mass_q8=256;
    balls[0].vx=2; balls[0].vy=0;
    world.gravity_x=0; world.gravity_y=0; world.linear_damping_q8=255;
    kq2dc_step(&world); m_number((u8)balls[0].x);
    while (1) { m_wait();  }
}
매 프레임 효과음 처리 gb_sound.c

목적: 효과음 스트림을 시작하고 정기적인 프레임 갱신으로 진행시킵니다.

동작 원리: Audio_Init 후 Audio_PlaySFX가 채널 ID 1에서 tone을 시작합니다. 메인 루프는 프레임마다 Audio_Update를 한 번 호출합니다.

조작 방법과 기대 결과: 042가 표시된 채로 짧은 펄스 효과음이 재생됩니다. 숫자는 고정 표시이며 음량이나 재생 위치가 아닙니다. 소리는 오디오 출력이나 녹음으로 확인하세요.

매 프레임 효과음 처리: 042가 표시된 채로 짧은 펄스 효과음이 재생됩니다. 숫자는 고정 표시이며 음량이나 재생 위치가 아닙니다. 소리는 오디오 출력이나 녹음으로 확인하세요.
표시 예: 042가 표시된 채로 짧은 펄스 효과음이 재생됩니다. 숫자는 고정 표시이며 음량이나 재생 위치가 아닙니다. 소리는 오디오 출력이나 녹음으로 확인하세요.

소스 내려받기 / 검증 상태

powershell
.\kitaqgb\kitaqgb.exe kitaqgb/lib/audio_hwregs_gb.c kitaqgb/lib/audio.c kitaq-docs/samples/gb_sound.c -I kitaqgb/lib -I kitaq-docs/samples -o out/gb_sound.gb --profile=dev --rst-disable --stack-bank=fixed
c
// Play a Game Boy pulse-channel sound effect.
// Expected: 042 and a short pulse tone
#include "gb_common.h"
#include "audio.h"
__prg_rom u8 tone[] = { 24,0xF0,24,0xE0,24,0xC0,24,0xA0,24,0x80,24,0x60,0 };
// Start a pulse-channel effect and service Audio_Update once per frame
// so the effect stream advances while 42 remains on screen.
void main() {
    m_init();
    m_text(2,3,"SOUND");
    Audio_Init(); Audio_PlaySFX(tone,1); m_number(42);
    while (1) { m_wait(); Audio_Update(); }
}

라이브러리 API 사전

총 554개 항목입니다. 항목을 열면 문법, 인수, 소스 주석, 사용 예를 볼 수 있습니다. 호출 조각은 주변 코드의 초기화가 필요하며 독립적인 ROM이 아닙니다. 인수 전달 예제는 준비한 값을 API에 넘기는 방법을 보여 줄 뿐, 장치에서의 동작 검증을 뜻하지 않습니다.

zx0

ZX0 호환 자산을 RAM 또는 VRAM에 디코딩합니다. PC에서 kitaqgb-zx0.exe로 준비한 뒤 실행 중 필요한 데이터만 디코딩하세요. --format=auto는 raw, RLE, ZX0 페이로드 크기를 비교해 가장 작은 것을 선택하며, 같은 크기면 raw, RLE, ZX0 순으로 우선합니다. 9바이트 헤더를 포함한 전체 컨테이너를 65535바이트 이내로 유지하고 실제 CPU 뱅크와 RAM에 맞게 자산을 나누세요.

ZX0 형식과 원래 압축 알고리즘은 Einar Saukas가 설계했습니다. 여기의 압축기와 압축 해제기는 KITAQ의 독립 구현이며, 저작권자는 DAISUKE OBA이고 MIT 라이선스로 배포됩니다.

저장소 루트에서 다음 호스트 명령을 실행하세요. 도구는 tools/zx0/build.ps1로 빌드합니다.

.\kitaqgb-zx0.exe tiles.bin tiles.zx0
.\kitaqgb-zx0.exe tiles.bin tiles.h --header=tiles
.\kitaqgb-zx0.exe map.bin map.kqa --format=auto
.\kitaqgb-zx0.exe tiles.zx0 restored.bin --decompress
zx0_decompress

제한된 RAM 영역에 ZX0 v2 스트림을 디코딩합니다. 일치 복사는 이미 디코딩한 바이트를 참조하므로 대상은 읽기·쓰기가 모두 가능해야 합니다. CPU가 사용 전에 처리할 타일 맵이나 레벨 테이블 등에 쓰세요.

사용 형식

c
u16 zx0_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);

매개변수

dst

쓰기 가능한 대상 RAM의 시작점이며 null이면 안 됩니다. 용량은 배열 요소 수가 아닌 바이트로 지정하세요.

capacity

대상에 쓸 수 있는 바이트 수입니다. 일반 ZX0 스트림에는 최소 1바이트가 필요합니다. 빈 raw KQA1 자산은 용량 0으로도 성공할 수 있습니다.

src

현재 뱅크 매핑으로 읽을 수 있는 압축 데이터의 시작점입니다. null이면 안 됩니다.

packed_size

전체 입력의 바이트 수입니다. ZX0 스트림은 종료 마커를 포함하며 뒤에 추가 바이트가 없어야 합니다. KQA1 컨테이너는 9바이트 헤더를 포함합니다. 최대 65535바이트입니다.

반환값

성공하면 디코딩한 바이트 수, 오류면 0을 반환합니다. 항상 zx0_error도 확인하세요.

사용 조건과 제한

zx0.h를 포함하고 lib/zx0.c를 컴파일하세요. 공유 임시 영역을 사용하므로 인터럽트에서 재진입할 수 없습니다. 입력과 출력은 서로 겹치거나 CPU 주소 공간을 래핑하거나 현재 매핑된 뱅크 창을 넘어서는 안 됩니다. 라이브러리는 자산 뱅크를 전환하지 않습니다.

매 호출은 zx0_error를 갱신합니다. 0=성공, 1=유효하지 않은 인수, 2=입력 잘림, 3=잘못된 스트림, 4=출력 공간 부족, 5=화면 활성입니다. 실패하면 부분 출력이 남을 수 있으므로 사용하지 마세요. 여러 조건이 잘못되었으면 먼저 감지한 조건으로 코드를 정합니다.

순방향 ZX0 v2 스트림을 받습니다. ZX0 v1, 역방향 스트림과 외부 사전은 이 인터페이스에 포함되지 않습니다. 호스트에서 만든 자산의 디코딩 크기를 알고 충분한 공간을 제공하세요.

ZX0 형식 — Einar Saukas

사용 예

c
count=zx0_decompress(decoded_map,16,packed_map,packed_map_SIZE);
    if(count!=16||zx0_error!=ZX0_OK)failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.

zx0_decompress: DMG — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
DMG — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
zx0_decompress: CGB — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
CGB — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\zx0_decode.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/zx0.h:15

선언 주석 원문
Return decoded bytes, or zero on error (possibly after partial writes).
Source and output must not overlap or cross their current CPU bank windows.
Capacity and packed_size are byte counts. No prefix/backward/v1 streams.

kitaqgb/lib/zx0.c:52

c
u16 zx0_decompress(void* dst,u16 capacity,const void* src,u16 packed_size) {
    u8 phase; u8 low; u8* out; u8* match;
    u16 count; u16 distance; u16 used; u16 upper;
    zx0_error=ZX0_OK;
    if(!kq_zx_arguments(dst,capacity,src,packed_size)) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
    kq_zx_input=(const u8*)src; kq_zx_left=packed_size;
    kq_zx_mask=0; kq_zx_borrowed=0;
    out=(u8*)dst; used=0; distance=1; phase=0;
    // Phase 0 is literal, 1 reuses the last distance, 2 carries a new distance.
    while(1) {
        if(phase==2) {
            upper=kq_zx_number(1);
            if(zx0_error) return 0;
            if(upper==256) {
                if(kq_zx_left!=0) { zx0_error=ZX0_BAD_STREAM; return 0; }
                return used;
            }
            if(upper>255) { zx0_error=ZX0_BAD_STREAM; return 0; }
            low=kq_zx_byte();
            distance=(u16)((upper<<7)-(low>>1));
            kq_zx_borrowed=1; kq_zx_borrow_value=(u8)(low&1);
            count=kq_zx_number(0);
            if(count==65535) { zx0_error=ZX0_BAD_STREAM; return 0; }
            count++;
        } else count=kq_zx_number(0);
        if(zx0_error) return 0;
        if(count>capacity-used) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
        if(phase==0) {
            if(count>kq_zx_left) { zx0_error=ZX0_TRUNCATED; return 0; }
            kq_zx_left-=count; used+=count;
            while(count!=0) { *out++=*kq_zx_input++; count--; }
            phase=kq_zx_bit()?2:1;
        } else {
            if(distance>used) { zx0_error=ZX0_BAD_STREAM; return 0; }
            match=out-distance; used+=count;
            // Forward byte copying deliberately supports overlapping matches.
            while(count!=0) { *out++=*match++; count--; }
            phase=kq_zx_bit()?2:0;
        }
        if(zx0_error) return 0;
    }
}
asset_decompress

--format=auto로 만든 KQA1 헤더에서 코덱과 크기를 읽은 뒤 raw 바이트를 복사하거나 RLE/ZX0를 RAM에 디코딩합니다. 호출자 코드는 코덱마다 별도 분기할 필요가 없습니다.

사용 형식

c
u16 asset_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);

매개변수

dst

쓰기 가능한 대상 RAM의 시작점이며 null이면 안 됩니다. 용량은 배열 요소 수가 아닌 바이트로 지정하세요.

capacity

대상에 쓸 수 있는 바이트 수입니다. 일반 ZX0 스트림에는 최소 1바이트가 필요합니다. 빈 raw KQA1 자산은 용량 0으로도 성공할 수 있습니다.

src

현재 뱅크 매핑으로 읽을 수 있는 압축 데이터의 시작점입니다. null이면 안 됩니다.

packed_size

전체 입력의 바이트 수입니다. ZX0 스트림은 종료 마커를 포함하며 뒤에 추가 바이트가 없어야 합니다. KQA1 컨테이너는 9바이트 헤더를 포함합니다. 최대 65535바이트입니다.

반환값

성공하면 디코딩한 바이트 수, 오류면 0을 반환합니다. 항상 zx0_error도 확인하세요.

사용 조건과 제한

zx0.h를 포함하고 lib/zx0.c를 컴파일하세요. 공유 임시 영역을 사용하므로 인터럽트에서 재진입할 수 없습니다. 입력과 출력은 서로 겹치거나 CPU 주소 공간을 래핑하거나 현재 매핑된 뱅크 창을 넘어서는 안 됩니다. 라이브러리는 자산 뱅크를 전환하지 않습니다.

매 호출은 zx0_error를 갱신합니다. 0=성공, 1=유효하지 않은 인수, 2=입력 잘림, 3=잘못된 스트림, 4=출력 공간 부족, 5=화면 활성입니다. 실패하면 부분 출력이 남을 수 있으므로 사용하지 마세요. 여러 조건이 잘못되었으면 먼저 감지한 조건으로 코드를 정합니다.

KQA1은 KITAQ 자산 컨테이너입니다. 4바이트 매직 값, 1바이트 코덱(0 raw, 1 RLE, 2 ZX0), 디코딩 크기 u16, 페이로드 크기 u16, 페이로드 순서입니다. u16 필드는 리틀 엔디언입니다. RLE는 count/value 쌍을 반복하며 count는 1~255, 종료는 count 0입니다. 빈 raw 자산은 반환값 0, 오류 0으로 성공합니다.

ZX0 형식 — Einar Saukas

사용 예

c
count=asset_decompress(decoded_auto,16,packed_auto,packed_auto_SIZE);
    if(count!=16||zx0_error!=ZX0_OK)failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.

asset_decompress: DMG — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
DMG — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
asset_decompress: CGB — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
CGB — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\zx0_decode.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/zx0.h:18

선언 주석 원문
Decode a KQA1 raw/RLE/ZX0 asset produced with --format=auto.
Empty raw assets return zero with zx0_error==ZX0_OK.

kitaqgb/lib/zx0.c:95

c
u16 asset_decompress(void* dst,u16 capacity,const void* src,u16 packed_size) {
    const u8* in; u8* out; u16 raw; u16 packed; u16 used;
    u8 codec; u8 count; u8 value;
    zx0_error=ZX0_OK;
    if(packed_size<9||!kq_zx_arguments(dst,capacity,src,packed_size)) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
    in=(const u8*)src; out=(u8*)dst;
    if(in[0]!=75||in[1]!=81||in[2]!=65||in[3]!=49) { zx0_error=ZX0_BAD_STREAM; return 0; }
    codec=in[4]; raw=(u16)((u16)in[5]|((u16)in[6]<<8));
    packed=(u16)((u16)in[7]|((u16)in[8]<<8));
    if(packed!=packed_size-9||codec>2) { zx0_error=ZX0_BAD_STREAM; return 0; }
    if(raw>capacity) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
    in+=9;
    if(codec==2) {
        used=zx0_decompress(dst,raw,in,packed);
        if(zx0_error==0&&used!=raw) zx0_error=ZX0_BAD_STREAM;
        return zx0_error?0:used;
    }
    if(codec==0) {
        if(raw!=packed) { zx0_error=ZX0_BAD_STREAM; return 0; }
        used=raw; while(raw!=0) { *out++=*in++; raw--; } return used;
    }
    used=0;
    while(packed!=0) {
        count=*in++; packed--;
        if(count==0) {
            if(packed!=0||used!=raw) { zx0_error=ZX0_BAD_STREAM; return 0; }
            return used;
        }
        if(packed==0) { zx0_error=ZX0_TRUNCATED; return 0; }
        value=*in++; packed--;
        if((u16)count>raw-used) { zx0_error=ZX0_OUTPUT_FULL; return 0; }
        used+=count; while(count!=0) { *out++=value; count--; }
    }
    zx0_error=ZX0_TRUNCATED; return 0;
}
zx0_decompress_vram

LCD를 멈춘 상태에서 ZX0 타일 픽셀이나 맵 데이터를 선택한 VRAM 뱅크에 직접 디코딩합니다. VRAM 자체가 일치 복사의 이력을 제공하므로 중간 RAM 버퍼가 필요 없습니다.

사용 형식

c
u16 zx0_decompress_vram(u16 vram_addr, const void* src, u16 packed_size);

매개변수

vram_addr

VRAM 시작 주소로 0x8000..0x9FFF입니다. 출력은 VRAM 끝인 0xA000을 넘지 않습니다. CGB에서는 호출 전에 VBK를 선택하세요.

src

현재 뱅크 매핑으로 읽을 수 있는 압축 데이터의 시작점입니다. null이면 안 됩니다.

packed_size

전체 입력의 바이트 수입니다. ZX0 스트림은 종료 마커를 포함하며 뒤에 추가 바이트가 없어야 합니다. KQA1 컨테이너는 9바이트 헤더를 포함합니다. 최대 65535바이트입니다.

반환값

성공하면 디코딩한 바이트 수, 오류면 0을 반환합니다. 항상 zx0_error도 확인하세요.

사용 조건과 제한

zx0.h를 포함하고 lib/zx0.c를 컴파일하세요. 공유 임시 영역을 사용하므로 인터럽트에서 재진입할 수 없습니다. 입력과 출력은 서로 겹치거나 CPU 주소 공간을 래핑하거나 현재 매핑된 뱅크 창을 넘어서는 안 됩니다. 라이브러리는 자산 뱅크를 전환하지 않습니다.

매 호출은 zx0_error를 갱신합니다. 0=성공, 1=유효하지 않은 인수, 2=입력 잘림, 3=잘못된 스트림, 4=출력 공간 부족, 5=화면 활성입니다. 실패하면 부분 출력이 남을 수 있으므로 사용하지 마세요. 여러 조건이 잘못되었으면 먼저 감지한 조건으로 코드를 정합니다.

순방향 ZX0 v2 스트림을 받습니다. ZX0 v1, 역방향 스트림과 외부 사전은 이 인터페이스에 포함되지 않습니다. 호스트에서 만든 자산의 디코딩 크기를 알고 충분한 공간을 제공하세요.

LCD가 켜져 있으면 오류 5를 반환합니다. VBlank 중인 것만으로는 충분하지 않습니다. 표시, VBK, 인터럽트 설정은 바꾸지 않습니다. 호출자 코드가 LCD를 끄고 다시 켭니다.

ZX0 형식 — Einar Saukas

사용 예

c
count=zx0_decompress_vram(0x8800,packed_tiles,packed_tiles_SIZE);
    if(count!=48||zx0_error!=ZX0_OK)failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.

zx0_decompress_vram: DMG — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
DMG — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
zx0_decompress_vram: CGB — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.
CGB — RAM MAP 행은 정사각형·마름모·체커 타일을 반복합니다. AUTO RLE MAP은 정사각형 타일 16개로 수평 막대를 만듭니다. VRAM TILES는 픽셀을 VRAM에 디코딩한 뒤 같은 세 타일을 반복합니다. CGB와 FC에서 정사각형은 흰색, 마름모는 빨간색, 체커는 파란색이며 DMG는 회색 명암을 사용합니다. CHECKS OK는 세 호출 모두 오류 없이 예상 디코딩 크기를 반환했음을 나타냅니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\zx0_decode.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\zx0_decode.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/zx0.h:21

선언 주석 원문
Decode directly into the selected GB VRAM bank ($8000..$9FFF), with LCD off.
Preserve LCDC, VBK and interrupt state. Output must fit before $A000.

kitaqgb/lib/zx0.c:132

c
u16 zx0_decompress_vram(u16 vram_addr,const void* src,u16 packed_size) {
    zx0_error=ZX0_OK;
    if(vram_addr<0x8000||vram_addr>=0xA000) { zx0_error=ZX0_BAD_ARGUMENT; return 0; }
    if(kq_zx_lcdc&0x80) { zx0_error=ZX0_DISPLAY_ACTIVE; return 0; }
    return zx0_decompress((void*)vram_addr,(u16)(0xA000-vram_addr),src,packed_size);
}

asset.h — 리소스 ID와 데이터 기술자

소재 라이브러리는 ROM 뱅크에 저장한 소재를 8비트 ID로 찾습니다. asset.c를 포함하고, FC에서는 bank.c도 포함합니다. 패딩 없는 6바이트 AssetDesc에는 1바이트 유형, 1바이트 소재 뱅크 번호, 16비트 주소, 바이트 단위 길이가 들어갑니다. 목록과 소재 본체는 서로 다른 뱅크에 둘 수 있습니다.

조회 전에 목록을 등록하세요. 등록 정보는 공유 전역 상태이므로 조회 중에 바꾸면 안 됩니다. 라이브러리는 ID와 asset_get의 출력 포인터를 검사하지만 등록된 목록, 소재 주소, 카트리지 내용의 유효성은 검사하지 않습니다.

RAW 또는 TILES 소재를 찾아 __vram_copy로 desc.len바이트 전체를 전송합니다. 호출 전에 소재 본체의 ROM 뱅크를 선택해야 합니다. GB 함수는 desc.ptr을 직접 사용하며 전송할 때 desc.bank를 선택하지 않습니다.

asset_get

등록된 목록의 ROM 뱅크에서 AssetDesc 하나를 읽어 호출자가 준비한 공간에 복사합니다. 소재 본체가 아니라 소재의 정보를 가져옵니다.

사용 형식

c
u8 asset_get(u8 asset_id, AssetDesc* out_desc);

매개변수

asset_id

0부터 시작하는 소재 번호입니다. 등록된 목록의 항목 수가 count일 때 asset_id < count인 ID가 유효합니다.

out_desc

6바이트 설명자 하나를 저장할 수 있는 쓰기 가능한 영역입니다. 널 포인터이면 목록에 접근하기 전에 실패를 반환합니다.

반환값

설명자를 복사하면 1, 출력 포인터가 널이거나 ID가 범위를 벗어나면 0입니다. 이 실패 경로에서는 출력 공간을 변경하지 않습니다.

사용 조건과 제한

조회 전에 목록을 등록하세요. 등록 정보는 공유 전역 상태이므로 조회 중에 바꾸면 안 됩니다. 라이브러리는 ID와 asset_get의 출력 포인터를 검사하지만 등록된 목록, 소재 주소, 카트리지 내용의 유효성은 검사하지 않습니다.

예제의 호출 코드는 고정 뱅크 0에 두어 원본 뱅크를 바꿔도 실행 중인 코드가 사라지지 않도록 합니다. 전송은 동기식입니다. 전송 도중 인터럽트에서 다른 뱅크 전환 복사를 실행하지 마세요. 이 함수만으로 프로그램 전체의 인터럽트 안전성이 확보되지는 않습니다.

사용 예

c
loaded=asset_get(0,&descriptor);
expect(loaded==1,1);
expect(descriptor.type==ASSET_TYPE_TILES && descriptor.bank==2,2);
expect(descriptor.ptr==asset_shapes && descriptor.len==144,3);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

설명자 0을 읽어 TILES 유형, 뱅크 2, 소재 포인터, 144바이트 길이를 확인합니다. 범위 밖 ID와 널 출력 포인터는 실패해야 하며, 조회 실패 시 기존 출력값이 유지되는지도 확인합니다.

예상 화면의 빨간 줄은 픽셀 좌표 (16,32)에서 시작하며 72×8픽셀입니다. 8×8 삼각형, 테두리 두께 1픽셀인 8×8 사각형, 왼쪽 네 열을 채운 타일을 세 번 반복합니다. 삼각형은 왼쪽 위의 1픽셀에서 맨 아래 줄의 8픽셀까지 넓어집니다.

GB에서 (16,64)의 파란 삼각형과 테두리는 __farmemcpy 결과이며, (16,96)의 초록색 쌍은 __far_memcpy 결과입니다. 각 쌍은 16×8픽셀입니다. CGB는 이 색으로, DMG는 흰 바탕에 검은색으로 같은 모양을 표시합니다.

예상 상태 표시는 FAILED CHECKS 000과 FIRST FAILURE 00입니다. 검증은 300프레임 동안 실행한 뒤 글자, 도형 마스크, 색을 예상값과 비교합니다. 에뮬레이터 검증이며 실제 하드웨어 시험은 아닙니다.

asset_get: DMG
DMG
asset_get: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/asset.h:24

선언 주석 원문
Copy one descriptor from its ROM bank into caller storage. Return zero for a
null destination or an out-of-range ID; table validity is the caller's responsibility.

kitaqgb/lib/asset.c:18

c
u8 asset_get(u8 asset_id, AssetDesc* out_desc)
{
    if (out_desc == 0) return 0;
    if (asset_id >= asset_table_count) return 0;
    __farmemcpy(out_desc, asset_table_bank, asset_table + asset_id, sizeof(AssetDesc));
    return 1;
}
asset_get_bank

설명자에서 소재 본체의 뱅크 번호를 읽습니다. 목록이 들어 있는 뱅크 번호가 아닙니다. 반환 후에도 소재 뱅크가 선택된 상태로 남지 않습니다.

사용 형식

c
u8 asset_get_bank(u8 asset_id);

매개변수

asset_id

0부터 시작하는 소재 번호입니다. 등록된 목록의 항목 수가 count일 때 asset_id < count인 ID가 유효합니다.

반환값

설명자의 8비트 bank를 반환하며 조회 실패 시 0입니다. 유효한 뱅크도 0일 수 있으므로 성공 여부를 구분하려면 asset_get()을 사용하세요.

사용 조건과 제한

조회 전에 목록을 등록하세요. 등록 정보는 공유 전역 상태이므로 조회 중에 바꾸면 안 됩니다. 라이브러리는 ID와 asset_get의 출력 포인터를 검사하지만 등록된 목록, 소재 주소, 카트리지 내용의 유효성은 검사하지 않습니다.

각 조회 함수는 호출할 때마다 asset_get으로 설명자를 복사합니다. 뱅크, 포인터, 길이가 모두 필요하다면 asset_get을 한 번 호출하고 필드를 읽으세요.

예제의 호출 코드는 고정 뱅크 0에 두어 원본 뱅크를 바꿔도 실행 중인 코드가 사라지지 않도록 합니다. 전송은 동기식입니다. 전송 도중 인터럽트에서 다른 뱅크 전환 복사를 실행하지 마세요. 이 함수만으로 프로그램 전체의 인터럽트 안전성이 확보되지는 않습니다.

사용 예

c
payload_bank=asset_get_bank(0);
expect(payload_bank==2,17); // Payload bank, not descriptor-table bank 3.
expect(asset_get_bank(4)==0,18); // Failure sentinel; a valid descriptor may also use bank 0.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

목록이 뱅크 3에 있어도 소재 본체의 뱅크 2를 반환하는지 확인합니다. 잘못된 ID에서 0을 반환하는지도 검사합니다.

예상 화면의 빨간 줄은 픽셀 좌표 (16,32)에서 시작하며 72×8픽셀입니다. 8×8 삼각형, 테두리 두께 1픽셀인 8×8 사각형, 왼쪽 네 열을 채운 타일을 세 번 반복합니다. 삼각형은 왼쪽 위의 1픽셀에서 맨 아래 줄의 8픽셀까지 넓어집니다.

GB에서 (16,64)의 파란 삼각형과 테두리는 __farmemcpy 결과이며, (16,96)의 초록색 쌍은 __far_memcpy 결과입니다. 각 쌍은 16×8픽셀입니다. CGB는 이 색으로, DMG는 흰 바탕에 검은색으로 같은 모양을 표시합니다.

예상 상태 표시는 FAILED CHECKS 000과 FIRST FAILURE 00입니다. 검증은 300프레임 동안 실행한 뒤 글자, 도형 마스크, 색을 예상값과 비교합니다. 에뮬레이터 검증이며 실제 하드웨어 시험은 아닙니다.

asset_get_bank: DMG
DMG
asset_get_bank: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/asset.h:32

선언 주석 원문
Return the descriptor bank, or zero on lookup failure; zero can also be a valid bank.

kitaqgb/lib/asset.c:51

c
u8 asset_get_bank(u8 asset_id)
{
    AssetDesc desc;
    if (asset_get(asset_id, &desc) == 0) return 0;
    return desc.bank;
}
asset_get_len

설명자에서 소재 길이를 바이트 단위로 읽습니다. 등록된 정보를 반환할 뿐, 소재 본체를 검사하거나 타일 수, 요소 수, 프레임 수로 환산하지 않습니다.

사용 형식

c
u16 asset_get_len(u8 asset_id);

매개변수

asset_id

0부터 시작하는 소재 번호입니다. 등록된 목록의 항목 수가 count일 때 asset_id < count인 ID가 유효합니다.

반환값

바이트 단위의 16비트 len을 반환하며 조회 실패 시 0입니다. 빈 소재도 길이가 0이므로 두 경우를 구분하려면 asset_get()을 사용하세요.

사용 조건과 제한

조회 전에 목록을 등록하세요. 등록 정보는 공유 전역 상태이므로 조회 중에 바꾸면 안 됩니다. 라이브러리는 ID와 asset_get의 출력 포인터를 검사하지만 등록된 목록, 소재 주소, 카트리지 내용의 유효성은 검사하지 않습니다.

각 조회 함수는 호출할 때마다 asset_get으로 설명자를 복사합니다. 뱅크, 포인터, 길이가 모두 필요하다면 asset_get을 한 번 호출하고 필드를 읽으세요.

예제의 호출 코드는 고정 뱅크 0에 두어 원본 뱅크를 바꿔도 실행 중인 코드가 사라지지 않도록 합니다. 전송은 동기식입니다. 전송 도중 인터럽트에서 다른 뱅크 전환 복사를 실행하지 마세요. 이 함수만으로 프로그램 전체의 인터럽트 안전성이 확보되지는 않습니다.

사용 예

c
expect(asset_get_len(0)==144,21); // Bytes, not tiles.
expect(asset_get_len(3)==0 && asset_get_len(4)==0,22); // Empty asset and invalid ID both yield zero.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

9타일 소재가 타일 수 9가 아닌 바이트 수 144를 반환하는지 확인합니다. 빈 소재와 잘못된 ID는 모두 0이어야 합니다.

예상 화면의 빨간 줄은 픽셀 좌표 (16,32)에서 시작하며 72×8픽셀입니다. 8×8 삼각형, 테두리 두께 1픽셀인 8×8 사각형, 왼쪽 네 열을 채운 타일을 세 번 반복합니다. 삼각형은 왼쪽 위의 1픽셀에서 맨 아래 줄의 8픽셀까지 넓어집니다.

GB에서 (16,64)의 파란 삼각형과 테두리는 __farmemcpy 결과이며, (16,96)의 초록색 쌍은 __far_memcpy 결과입니다. 각 쌍은 16×8픽셀입니다. CGB는 이 색으로, DMG는 흰 바탕에 검은색으로 같은 모양을 표시합니다.

예상 상태 표시는 FAILED CHECKS 000과 FIRST FAILURE 00입니다. 검증은 300프레임 동안 실행한 뒤 글자, 도형 마스크, 색을 예상값과 비교합니다. 에뮬레이터 검증이며 실제 하드웨어 시험은 아닙니다.

asset_get_len: DMG
DMG
asset_get_len: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/asset.h:37

선언 주석 원문
Return the descriptor byte length, or zero if its ID cannot be resolved.

kitaqgb/lib/asset.c:68

c
u16 asset_get_len(u8 asset_id)
{
    AssetDesc desc;
    if (asset_get(asset_id, &desc) == 0) return 0;
    return desc.len;
}
asset_get_ptr

설명자에 저장된 16비트 소재 주소를 읽습니다. 반환되는 근거리 포인터에는 뱅크 번호가 없습니다. 다른 ROM 뱅크의 소재를 읽을 때는 asset_get_bank()의 결과와 함께 뱅크 간 복사 함수를 사용하세요.

사용 형식

c
const u8* asset_get_ptr(u8 asset_id);

매개변수

asset_id

0부터 시작하는 소재 번호입니다. 등록된 목록의 항목 수가 count일 때 asset_id < count인 ID가 유효합니다.

반환값

저장된 const u8*를 반환하며 조회 실패 시 널입니다. 설명자 안의 소재 포인터가 널인지 검사하지 않으므로 조회 실패를 구분하려면 asset_get()을 사용하세요.

사용 조건과 제한

조회 전에 목록을 등록하세요. 등록 정보는 공유 전역 상태이므로 조회 중에 바꾸면 안 됩니다. 라이브러리는 ID와 asset_get의 출력 포인터를 검사하지만 등록된 목록, 소재 주소, 카트리지 내용의 유효성은 검사하지 않습니다.

각 조회 함수는 호출할 때마다 asset_get으로 설명자를 복사합니다. 뱅크, 포인터, 길이가 모두 필요하다면 asset_get을 한 번 호출하고 필드를 읽으세요.

예제의 호출 코드는 고정 뱅크 0에 두어 원본 뱅크를 바꿔도 실행 중인 코드가 사라지지 않도록 합니다. 전송은 동기식입니다. 전송 도중 인터럽트에서 다른 뱅크 전환 복사를 실행하지 마세요. 이 함수만으로 프로그램 전체의 인터럽트 안전성이 확보되지는 않습니다.

사용 예

c
payload_pointer=asset_get_ptr(0);
expect(payload_pointer==asset_shapes,19);
expect(*asset_bank_marker==0xA1,20); // Getting the pointer leaves bank 1 selected.
// Use payload_bank together with payload_pointer for a far copy; do not dereference it here.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

반환된 포인터가 ROM 배치 후의 소재 주소와 같고 뱅크 1의 확인용 값도 계속 읽히는지 확인합니다. 이후 그 포인터와 소재 뱅크 2를 뱅크 간 복사 함수에 전달합니다.

예상 화면의 빨간 줄은 픽셀 좌표 (16,32)에서 시작하며 72×8픽셀입니다. 8×8 삼각형, 테두리 두께 1픽셀인 8×8 사각형, 왼쪽 네 열을 채운 타일을 세 번 반복합니다. 삼각형은 왼쪽 위의 1픽셀에서 맨 아래 줄의 8픽셀까지 넓어집니다.

GB에서 (16,64)의 파란 삼각형과 테두리는 __farmemcpy 결과이며, (16,96)의 초록색 쌍은 __far_memcpy 결과입니다. 각 쌍은 16×8픽셀입니다. CGB는 이 색으로, DMG는 흰 바탕에 검은색으로 같은 모양을 표시합니다.

예상 상태 표시는 FAILED CHECKS 000과 FIRST FAILURE 00입니다. 검증은 300프레임 동안 실행한 뒤 글자, 도형 마스크, 색을 예상값과 비교합니다. 에뮬레이터 검증이며 실제 하드웨어 시험은 아닙니다.

asset_get_ptr: DMG
DMG
asset_get_ptr: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/asset.h:35

선언 주석 원문
Return the stored address without switching banks. Use the descriptor bank
with far-data helpers before dereferencing banked assets; failure returns null.

kitaqgb/lib/asset.c:60

c
const u8* asset_get_ptr(u8 asset_id)
{
    AssetDesc desc;
    if (asset_get(asset_id, &desc) == 0) return 0;
    return desc.ptr;
}
asset_load_raw

소재를 찾아 해당 ROM 뱅크에서 쓰기 가능한 메모리로 min(desc.len, max_len)바이트를 복사합니다. 유형은 검사하지 않으며 타일, 맵, 곡 데이터도 바이트 그대로 복사합니다. 디코딩이나 압축 해제는 하지 않습니다.

사용 형식

c
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);

매개변수

asset_id

0부터 시작하는 소재 번호입니다. 등록된 목록의 항목 수가 count일 때 asset_id < count인 ID가 유효합니다.

dst

쓰기 대상 메모리입니다. 실제 복사량을 모두 담을 공간을 확보하세요. 0바이트 전송을 제외하면 널 포인터나 잘못된 대상 주소를 검사하지 않습니다.

max_len

복사할 최대 바이트 수이며 범위는 0~65535입니다. 소재 길이보다 작으면 일부만 복사합니다. 0이면 소재 바이트를 복사하지 않습니다.

반환값

조회 실패 시 0, 그 외에는 1입니다. 일부만 복사했거나 한도가 0이거나 빈 소재여도 1입니다. 반환값은 바이트 수가 아니며 전체 소재를 담았다는 보장도 아닙니다.

사용 조건과 제한

조회 전에 목록을 등록하세요. 등록 정보는 공유 전역 상태이므로 조회 중에 바꾸면 안 됩니다. 라이브러리는 ID와 asset_get의 출력 포인터를 검사하지만 등록된 목록, 소재 주소, 카트리지 내용의 유효성은 검사하지 않습니다.

원본 전체가 의도한 ROM 매핑에서 읽히고 대상 전체가 쓰기 가능한 메모리 안에 있어야 합니다. 뱅크 창 경계에서 다음 뱅크로 넘어가거나, memmove처럼 겹치는 범위를 처리하거나, VRAM 쓰기 시점을 제어하지 않습니다. VRAM에는 그래픽 전송 API를 사용하세요.

예제의 호출 코드는 고정 뱅크 0에 두어 원본 뱅크를 바꿔도 실행 중인 코드가 사라지지 않도록 합니다. 전송은 동기식입니다. 전송 도중 인터럽트에서 다른 뱅크 전환 복사를 실행하지 마세요. 이 함수만으로 프로그램 전체의 인터럽트 안전성이 확보되지는 않습니다.

사용 예

c
loaded=asset_load_raw(0,buffer,7); // Success with truncation: copy seven of 144 bytes.
expect(loaded==1 && buffer[7]==0x55,7);
for(i=0;i<7;i++) expect(buffer[(__safe_index u8)i]==expected_shape_byte(i),8);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

144바이트 소재에 한도 7을 지정해 처음 7바이트만 복사하고 다음 바이트의 0x55를 유지하면서도 성공을 반환하는지 확인합니다. 전체 복사, 한도 0, 빈 소재, MAP 소재의 원시 복사도 검사합니다.

예상 화면의 빨간 줄은 픽셀 좌표 (16,32)에서 시작하며 72×8픽셀입니다. 8×8 삼각형, 테두리 두께 1픽셀인 8×8 사각형, 왼쪽 네 열을 채운 타일을 세 번 반복합니다. 삼각형은 왼쪽 위의 1픽셀에서 맨 아래 줄의 8픽셀까지 넓어집니다.

GB에서 (16,64)의 파란 삼각형과 테두리는 __farmemcpy 결과이며, (16,96)의 초록색 쌍은 __far_memcpy 결과입니다. 각 쌍은 16×8픽셀입니다. CGB는 이 색으로, DMG는 흰 바탕에 검은색으로 같은 모양을 표시합니다.

예상 상태 표시는 FAILED CHECKS 000과 FIRST FAILURE 00입니다. 검증은 300프레임 동안 실행한 뒤 글자, 도형 마스크, 색을 예상값과 비교합니다. 에뮬레이터 검증이며 실제 하드웨어 시험은 아닙니다.

asset_load_raw: DMG
DMG
asset_load_raw: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/asset.h:27

선언 주석 원문
Copy at most max_len bytes using the asset's bank. Success means the ID was
valid, even when the payload was truncated to fit the supplied limit.

kitaqgb/lib/asset.c:28

c
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len)
{
    AssetDesc desc;
    u16 len;
    if (asset_get(asset_id, &desc) == 0) return 0;
    len = desc.len;
    if (len > max_len) len = max_len;
    __farmemcpy(dst, desc.bank, desc.ptr, len);
    return 1;
}
asset_load_tiles

RAW 또는 TILES 소재를 찾아 __vram_copy로 desc.len바이트 전체를 전송합니다. 호출 전에 소재 본체의 ROM 뱅크를 선택해야 합니다. GB 함수는 desc.ptr을 직접 사용하며 전송할 때 desc.bank를 선택하지 않습니다.

사용 형식

c
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);

매개변수

asset_id

0부터 시작하는 소재 번호입니다. 등록된 목록의 항목 수가 count일 때 asset_id < count인 ID가 유효합니다.

vram_dst

$8000~$9FFF 범위의 VRAM 바이트 주소이며 타일 번호가 아닙니다. 타일 패턴에는 16바이트 경계 주소와 16의 배수인 설명자 길이를 사용하세요. 라이브러리는 이 형식 조건을 검사하지 않습니다.

반환값

ID가 잘못되었거나 유형이 RAW/TILES가 아니면 0입니다. 허용된 전송을 마치면 1이며 길이 0인 소재도 포함합니다. 성공값이 타일 인코딩이나 VRAM 표시의 정확성을 보장하지는 않습니다.

사용 조건과 제한

조회 전에 목록을 등록하세요. 등록 정보는 공유 전역 상태이므로 조회 중에 바꾸면 안 됩니다. 라이브러리는 ID와 asset_get의 출력 포인터를 검사하지만 등록된 목록, 소재 주소, 카트리지 내용의 유효성은 검사하지 않습니다.

예제의 호출 코드는 고정 뱅크 0에 두어 원본 뱅크를 바꿔도 실행 중인 코드가 사라지지 않도록 합니다. 전송은 동기식입니다. 전송 도중 인터럽트에서 다른 뱅크 전환 복사를 실행하지 마세요. 이 함수만으로 프로그램 전체의 인터럽트 안전성이 확보되지는 않습니다.

전송은 바이트만 쓰며 맵에 타일을 배치하거나 색을 지정하거나 VRAM을 할당하지 않습니다. 타일 맵과 팔레트는 따로 설정하세요. 예제는 렌더링을 끈 상태로 전송하고 이미지가 준비된 뒤 화면을 켭니다.

GB 보조 루틴은 컴파일러가 보관하는 ROM 뱅크 상태로 복귀 뱅크를 정합니다. 이를 갱신하는 __bankswitch를 사용하세요. 매퍼에 직접 쓰면 상태가 갱신되지 않습니다. HRAM의 복귀 뱅크 저장 공간은 공유되므로 중첩 전송으로 덮어쓰면 안전하지 않습니다.

사용 예

c
__bankswitch(payload_bank); // GB tile upload expects the payload bank already visible.
loaded=asset_load_tiles(0,0x8010); // Nine tiles = 144 bytes, LCD off.
expect(loaded==1,24);
__bankswitch(1);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

타일 전송 예제는 직접 만든 8×8 패턴 9개, 총 144바이트를 사용합니다. MAP 유형과 잘못된 ID가 거부되는지도 확인합니다. FC에서는 128바이트 청크와 나머지 16바이트를 모두 검증합니다.

예상 화면의 빨간 줄은 픽셀 좌표 (16,32)에서 시작하며 72×8픽셀입니다. 8×8 삼각형, 테두리 두께 1픽셀인 8×8 사각형, 왼쪽 네 열을 채운 타일을 세 번 반복합니다. 삼각형은 왼쪽 위의 1픽셀에서 맨 아래 줄의 8픽셀까지 넓어집니다.

GB에서 (16,64)의 파란 삼각형과 테두리는 __farmemcpy 결과이며, (16,96)의 초록색 쌍은 __far_memcpy 결과입니다. 각 쌍은 16×8픽셀입니다. CGB는 이 색으로, DMG는 흰 바탕에 검은색으로 같은 모양을 표시합니다.

예상 상태 표시는 FAILED CHECKS 000과 FIRST FAILURE 00입니다. 검증은 300프레임 동안 실행한 뒤 글자, 도형 마스크, 색을 예상값과 비교합니다. 에뮬레이터 검증이며 실제 하드웨어 시험은 아닙니다.

asset_load_tiles: DMG
DMG
asset_load_tiles: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/asset.h:30

선언 주석 원문
Accept tile/raw descriptors and transfer their bytes to VRAM. This path passes
the descriptor pointer directly; callers must arrange the correct visible ROM bank.

kitaqgb/lib/asset.c:41

c
u8 asset_load_tiles(u8 asset_id, u16 vram_dst)
{
    AssetDesc desc;
    if (asset_get(asset_id, &desc) == 0) return 0;
    if (desc.type != ASSET_TYPE_TILES && desc.type != ASSET_TYPE_RAW) return 0;
    __vram_copy(vram_dst, desc.ptr, desc.len);
    return 1;
}
asset_set_table

사용할 소재 목록의 뱅크 번호, 주소, 항목 수를 등록합니다. 활성 목록은 하나뿐입니다. 이 함수는 세 값만 보관하며 목록 복사, 소재 읽기, 메모리 할당은 하지 않습니다.

사용 형식

c
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);

매개변수

bank

소재 본체가 아닌 설명자 목록이 저장된 ROM 뱅크 번호입니다. 8비트 값입니다.

table

AssetDesc 항목 count개가 연속으로 놓인 영역의 근거리 포인터입니다. 등록된 동안 해당 목록 뱅크의 count * 6바이트를 읽을 수 있어야 합니다.

count

항목 수이며 범위는 0~255입니다. 0이면 모든 ID가 무효입니다. asset_set_table(0, 0, 0)으로 빈 목록을 안전하게 등록할 수 있습니다.

반환값

없음(void).

사용 조건과 제한

조회 전에 목록을 등록하세요. 등록 정보는 공유 전역 상태이므로 조회 중에 바꾸면 안 됩니다. 라이브러리는 ID와 asset_get의 출력 포인터를 검사하지만 등록된 목록, 소재 주소, 카트리지 내용의 유효성은 검사하지 않습니다.

사용 예

c
asset_set_table(3,asset_descriptors,4); // Four descriptors in bank 3, payloads in bank 2.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 예제는 뱅크 3의 설명자 4개를 등록하고, 비어 있지 않은 소재는 뱅크 2에서 가져옵니다. 빈 목록도 등록해 주소 0을 읽지 않고 조회가 실패하는지 확인합니다.

예상 화면의 빨간 줄은 픽셀 좌표 (16,32)에서 시작하며 72×8픽셀입니다. 8×8 삼각형, 테두리 두께 1픽셀인 8×8 사각형, 왼쪽 네 열을 채운 타일을 세 번 반복합니다. 삼각형은 왼쪽 위의 1픽셀에서 맨 아래 줄의 8픽셀까지 넓어집니다.

GB에서 (16,64)의 파란 삼각형과 테두리는 __farmemcpy 결과이며, (16,96)의 초록색 쌍은 __far_memcpy 결과입니다. 각 쌍은 16×8픽셀입니다. CGB는 이 색으로, DMG는 흰 바탕에 검은색으로 같은 모양을 표시합니다.

예상 상태 표시는 FAILED CHECKS 000과 FIRST FAILURE 00입니다. 검증은 300프레임 동안 실행한 뒤 글자, 도형 마스크, 색을 예상값과 비교합니다. 에뮬레이터 검증이며 실제 하드웨어 시험은 아닙니다.

asset_set_table: DMG
DMG
asset_set_table: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\asset_banks.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\asset_banks.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/asset.h:21

선언 주석 원문
Retain the descriptor table address, bank and count; the table is not copied.

kitaqgb/lib/asset.c:9

c
void asset_set_table(u8 bank, const AssetDesc* table, u8 count)
{
    asset_table_bank = bank;
    asset_table = table;
    asset_table_count = count;
}

audio.h — 음악, 효과음, 음향 제어

네 채널 직접 제어, 뱅크 기반 음악·효과, 스테레오 라우팅, 음량 페이드, 사용자 파형을 제공합니다. 음악 스트림과 직접 API 채널 ID는 CH1=0, CH2=1, CH3=2, CH4=3입니다. CH3는 파형, CH4는 노이즈를 재생합니다.

audio.c보다 먼저 audio_hwregs_gb.c를 포함하고 시작 시 Audio_Init을 호출하세요. Audio_Update는 프레임마다 정확히 한 번, 약 59.7 Hz로 호출합니다. 스트림 읽기는 ROM 매핑을 일시적으로 바꾸므로 인터럽트에서 이 드라이버를 재진입 호출하지 마세요.

효과는 갱신마다 (note,value) 쌍 하나를 소비하며 note=0에서 끝납니다. value는 펄스 효과에서는 NR12, CH3에서는 NR32입니다. CH3 데이터 앞에는 0xFF를 붙이세요. 완료까지 저장 공간을 유지해야 합니다. 우선순위는 슬롯 안에서 경쟁하며 같은 우선순위도 현재 효과를 교체할 수 있습니다.

Audio_CancelMasterVolumeFade

현재 레벨과 레지스터를 유지하며 이후 페이드 진행을 멈춥니다.

사용 형식

c
void Audio_CancelMasterVolumeFade();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 예

c
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
    sound_begin("PAN AND VOLUME");
    Audio_SetMasterVolume(7,7);
    Audio_Ch1NoteOn(33,0xC0,2);
    Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
    sound_result[0]=NR51;
    sound_wait(30);
    // Packed low two bits are CH1: 2 means right. Other channels remain centered.
    Audio_SetPanPacked(2);
    sound_result[1]=NR51;
    sound_wait(30);
    Audio_SetPanPacked(0);
    sound_result[2]=NR51;
    Audio_FadeToMasterVolume(1,1,5);
    sound_wait(30);
    sound_result[3]=NR50;
    sound_result[4]=Audio_FadeActive;
    sound_wait(30);
    // Cancel halfway through a rise: retain volume 4 instead of reaching 7.
    Audio_FadeToMasterVolume(7,7,5);
    sound_wait(15);
    Audio_CancelMasterVolumeFade();
    sound_result[5]=NR50;
    sound_wait(30);
    sound_result[6]=NR50;
    // A zero fade interval sets the target immediately. Level zero is not mute.
    Audio_FadeToMasterVolume(0,0,0);
    sound_result[7]=NR50;
    sound_wait(30);
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(15);
    sound_end();
}

예상 결과

A4가 왼쪽, 오른쪽, 가운데로 이동합니다. 가운데에서는 레벨 7에서 1로 줄어든 뒤 4로 올라가 유지됩니다. 레벨 0도 작게 들리며 채널을 멈춰야 무음이 됩니다. 출력 경로 변경 후 필터 과도음이 감쇠하며 남을 수 있습니다.

Audio_CancelMasterVolumeFade: DMG
DMG
Audio_CancelMasterVolumeFade: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:125

선언 주석 원문
Cancel further volume steps, retaining the current cached levels and hardware output.

kitaqgb/lib/audio.c:548

c
void Audio_CancelMasterVolumeFade() {
    Audio_FadeTargetLeft = Audio_MasterLeft;
    Audio_FadeTargetRight = Audio_MasterRight;
    Audio_FadeStepFrames = 0;
    Audio_FadeCounter = 0;
    Audio_FadeActive = 0;
}
Audio_Ch1NoteOn

CH1의 스윕, 듀티, 엔벌로프, 음높이를 설정하고 펄스를 트리거합니다.

사용 형식

c
void __stackcall Audio_Ch1NoteOn(u8 note, u8 vol_env, u8 duty2);

매개변수

note

음높이 테이블 인덱스 0..67입니다. 범위 재사용과 CH3의 옥타브 차이는 주의사항을 참조하세요.

vol_env

NR12/NR22/NR42 인코딩: 상위 니블은 초기 음량, 비트 3은 증가 엔벌로프, 하위 3비트는 엔벌로프 주기입니다. 0xC0은 음량 12를 유지합니다.

duty2

펄스 듀티: 0=12.5%, 1=25%, 3=75%입니다. 나머지 값은 모두 50%를 선택합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

note는 0..67 음높이 테이블의 인덱스이며 0은 C2, 33은 A4입니다. 67 초과는 67로 제한하며, 60..67은 48..55의 주파수를 사용합니다. 같은 인덱스에서 CH3는 펄스 채널보다 한 옥타브 낮게 납니다. 음 시작 함수는 활성화·일시정지 상태를 확인하지 않고 하드웨어를 직접 트리거합니다.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_Ch1NoteOn: DMG
DMG
Audio_Ch1NoteOn: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:151

선언 주석 원문
Trigger CH1 with the cached sweep and the supplied raw envelope. Clamp the
note index; duty values 0, 1 and 3 select their encodings, and all others use 2.

kitaqgb/lib/audio.c:132

c
void __stackcall Audio_Ch1NoteOn(u8 note, u8 vol_env, u8 duty2) {
    u16 freq;
    u8 duty_reg;
    u8 hi;

    if (note > AUDIO_NOTE_MAX) note = AUDIO_NOTE_MAX;
    freq = GB_FREQ_TABLE[note];

    duty_reg = 128;
    if (duty2 == 0) duty_reg = 0;
    else if (duty2 == 1) duty_reg = 64;
    else if (duty2 == 3) duty_reg = 192;

    NR10 = Audio_Ch1Sweep;
    NR11 = duty_reg;
    NR12 = vol_env;
    NR13 = (u8)(freq & 0xFF);
    hi = (u8)((u16)freq >> 8);
    NR14 = (u8)(hi | 0x80);
}
Audio_Ch2NoteOn

CH2의 듀티, 엔벌로프, 음높이를 설정하고 펄스를 트리거합니다.

사용 형식

c
void __stackcall Audio_Ch2NoteOn(u8 note, u8 vol_env, u8 duty2);

매개변수

note

음높이 테이블 인덱스 0..67입니다. 범위 재사용과 CH3의 옥타브 차이는 주의사항을 참조하세요.

vol_env

NR12/NR22/NR42 인코딩: 상위 니블은 초기 음량, 비트 3은 증가 엔벌로프, 하위 3비트는 엔벌로프 주기입니다. 0xC0은 음량 12를 유지합니다.

duty2

펄스 듀티: 0=12.5%, 1=25%, 3=75%입니다. 나머지 값은 모두 50%를 선택합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

note는 0..67 음높이 테이블의 인덱스이며 0은 C2, 33은 A4입니다. 67 초과는 67로 제한하며, 60..67은 48..55의 주파수를 사용합니다. 같은 인덱스에서 CH3는 펄스 채널보다 한 옥타브 낮게 납니다. 음 시작 함수는 활성화·일시정지 상태를 확인하지 않고 하드웨어를 직접 트리거합니다.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_Ch2NoteOn: DMG
DMG
Audio_Ch2NoteOn: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:154

선언 주석 원문
Trigger CH2 with the supplied raw envelope and a clamped note index. Duty
values 0, 1 and 3 select their encodings; all other values use duty 2.

kitaqgb/lib/audio.c:666

c
void __stackcall Audio_Ch2NoteOn(u8 note, u8 vol_env, u8 duty2) {
    u16 freq;
    u8 duty_reg;
    u8 hi;

    if (note > AUDIO_NOTE_MAX) note = AUDIO_NOTE_MAX;
    freq = GB_FREQ_TABLE[note];

    duty_reg = 128;
    if (duty2 == 0) duty_reg = 0;
    else if (duty2 == 1) duty_reg = 64;
    else if (duty2 == 3) duty_reg = 192;

    NR21 = duty_reg;
    NR22 = vol_env;
    NR23 = (u8)(freq & 0xFF);
    hi = (u8)((u16)freq >> 8);
    NR24 = (u8)(hi | 0x80);
}
Audio_Ch3NoteOn

로드된 CH3 파형을 요청한 음높이와 NR32 레벨로 트리거합니다.

사용 형식

c
void __stackcall Audio_Ch3NoteOn(u8 note, u8 level);

매개변수

note

음높이 테이블 인덱스 0..67입니다. 범위 재사용과 CH3의 옥타브 차이는 주의사항을 참조하세요.

level

NR32 인코딩: 0x00=무음, 0x20=100%, 0x40=50%, 0x60=25%입니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

note는 0..67 음높이 테이블의 인덱스이며 0은 C2, 33은 A4입니다. 67 초과는 67로 제한하며, 60..67은 48..55의 주파수를 사용합니다. 같은 인덱스에서 CH3는 펄스 채널보다 한 옥타브 낮게 납니다. 음 시작 함수는 활성화·일시정지 상태를 확인하지 않고 하드웨어를 직접 트리거합니다.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_Ch3NoteOn: DMG
DMG
Audio_Ch3NoteOn: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:157

선언 주석 원문
Clamp the note index, program the raw NR32 output level, and trigger CH3.
Wave RAM must already contain the desired waveform; this does not load one.

kitaqgb/lib/audio.c:115

c
void __stackcall Audio_Ch3NoteOn(u8 note, u8 level) {
    u16 freq;
    u8 hi;

    if (note > AUDIO_NOTE_MAX) note = AUDIO_NOTE_MAX;
    freq = GB_FREQ_TABLE[note];

    NR30 = 128;
    NR31 = 0;
    NR32 = level;
    NR33 = (u8)(freq & 255);
    hi = (u8)((u16)freq >> 8);
    NR34 = (u8)(hi | 128);
}
Audio_Ch4NoteOn

노이즈 매개변수를 저장하고 엔벌로프·다항 카운터 레지스터를 설정한 뒤 CH4를 트리거합니다.

사용 형식

c
void __stackcall Audio_Ch4NoteOn(u8 param, u8 vol_env);

매개변수

param

원시 NR43입니다. 비트 7..4는 클록 시프트, 비트 3은 짧은 LFSR, 비트 2..0은 분주 코드입니다.

vol_env

NR12/NR22/NR42 인코딩: 상위 니블은 초기 음량, 비트 3은 증가 엔벌로프, 하위 3비트는 엔벌로프 주기입니다. 0xC0은 음량 12를 유지합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

길이 기반 자동 정지는 켜지지 않습니다. 엔벌로프나 명시적 정지로 소리를 끝내세요.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_Ch4NoteOn: DMG
DMG
Audio_Ch4NoteOn: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:160

선언 주석 원문
Cache the supplied noise parameter, program the raw envelope and polynomial
registers, then trigger CH4 with the length-enable bit clear.

kitaqgb/lib/audio.c:688

c
void __stackcall Audio_Ch4NoteOn(u8 param, u8 vol_env) {
    Audio_SetCh4Param(param);
    NR41 = 0x20;
    NR42 = vol_env;
    NR43 = Audio_Ch4Param;
    NR44 = 0x80;
}
Audio_FadeToMasterVolume

지정한 갱신 간격마다 각 출력 레벨을 목표를 향해 한 단계 이동합니다.

사용 형식

c
void __stackcall Audio_FadeToMasterVolume(u8 left, u8 right, u8 step_frames);

매개변수

left

왼쪽 마스터 레벨 0..7입니다. 더 큰 값은 7로 제한합니다. 0도 완전한 무음은 아닙니다.

right

오른쪽 마스터 레벨 0..7입니다. 더 큰 값은 7로 제한합니다.

step_frames

레벨 한 단계마다 필요한 Audio_Update 호출 수입니다. 0이면 목표값을 즉시 적용합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio.c보다 먼저 audio_hwregs_gb.c를 포함하고 시작 시 Audio_Init을 호출하세요. Audio_Update는 프레임마다 정확히 한 번, 약 59.7 Hz로 호출합니다. 스트림 읽기는 ROM 매핑을 일시적으로 바꾸므로 인터럽트에서 이 드라이버를 재진입 호출하지 마세요.

사용 예

c
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
    sound_begin("PAN AND VOLUME");
    Audio_SetMasterVolume(7,7);
    Audio_Ch1NoteOn(33,0xC0,2);
    Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
    sound_result[0]=NR51;
    sound_wait(30);
    // Packed low two bits are CH1: 2 means right. Other channels remain centered.
    Audio_SetPanPacked(2);
    sound_result[1]=NR51;
    sound_wait(30);
    Audio_SetPanPacked(0);
    sound_result[2]=NR51;
    Audio_FadeToMasterVolume(1,1,5);
    sound_wait(30);
    sound_result[3]=NR50;
    sound_result[4]=Audio_FadeActive;
    sound_wait(30);
    // Cancel halfway through a rise: retain volume 4 instead of reaching 7.
    Audio_FadeToMasterVolume(7,7,5);
    sound_wait(15);
    Audio_CancelMasterVolumeFade();
    sound_result[5]=NR50;
    sound_wait(30);
    sound_result[6]=NR50;
    // A zero fade interval sets the target immediately. Level zero is not mute.
    Audio_FadeToMasterVolume(0,0,0);
    sound_result[7]=NR50;
    sound_wait(30);
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(15);
    sound_end();
}

예상 결과

A4가 왼쪽, 오른쪽, 가운데로 이동합니다. 가운데에서는 레벨 7에서 1로 줄어든 뒤 4로 올라가 유지됩니다. 레벨 0도 작게 들리며 채널을 멈춰야 무음이 됩니다. 출력 경로 변경 후 필터 과도음이 감쇠하며 남을 수 있습니다.

Audio_FadeToMasterVolume: DMG
DMG
Audio_FadeToMasterVolume: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:123

선언 주석 원문
Move left/right volume toward clamped targets at the requested Audio_Update
call interval. An interval of zero applies the levels immediately.

kitaqgb/lib/audio.c:528

c
void __stackcall Audio_FadeToMasterVolume(u8 left, u8 right, u8 step_frames) {
    Audio_FadeTargetLeft = Audio_ClampVolume(left);
    Audio_FadeTargetRight = Audio_ClampVolume(right);

    if (step_frames == 0) {
        Audio_SetMasterVolume(Audio_FadeTargetLeft, Audio_FadeTargetRight);
        return;
    }

    Audio_FadeStepFrames = step_frames;
    Audio_FadeCounter = step_frames;
    if (Audio_MasterLeft == Audio_FadeTargetLeft && Audio_MasterRight == Audio_FadeTargetRight) {
        Audio_FadeActive = 0;
        Audio_FadeCounter = 0;
    } else {
        Audio_FadeActive = 1;
    }
}
Audio_Init

APU를 켜고 음악·효과·일시정지·믹스·파형 상태를 초기화한 뒤 모든 채널을 무음으로 둡니다.

사용 형식

c
void Audio_Init();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio.c보다 먼저 audio_hwregs_gb.c를 포함하고 시작 시 Audio_Init을 호출하세요. Audio_Update는 프레임마다 정확히 한 번, 약 59.7 Hz로 호출합니다. 스트림 읽기는 ROM 매핑을 일시적으로 바꾸므로 인터럽트에서 이 드라이버를 재진입 호출하지 마세요.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_Init: DMG
DMG
Audio_Init: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:76

선언 주석 원문
Enable the APU and reset software streams, instruments, mix and fade state.
Load the initial triangle wave, then leave every channel silent. Call at startup
before concurrent interrupt-driven audio service can access these shared fields.

kitaqgb/lib/audio.c:864

c
void Audio_Init() {
    NR52 = 0x80;
    NR51 = 0xFF;
    Audio_Pan = 0xFF;
    Audio_EffectPan = AUDIO_PAN_INHERIT;
    Audio_EffectPan3 = AUDIO_PAN_INHERIT;
    Audio_UpdateNR51();

    Audio_SetMasterVolume(AUDIO_VOLUME_MAX, AUDIO_VOLUME_MAX);
    Audio_SilenceAll();

    Audio_PlayingMusic = 0;
    Audio_Paused = 0;
    Audio_MusicEnabled = 1;
    Audio_SfxEnabled = 1;
    Audio_Delay = 0;
    Audio_MusicBank = 0;
    Audio_MusicPointer = 0;
    Audio_MusicLoopPoint = 0;

    Audio_EffectPointer = 0;
    Audio_EffectPriority = 0;
    Audio_EffectBank = 0;
    Audio_EffectPointer3 = 0;
    Audio_EffectPriority3 = 0;
    Audio_EffectBank3 = 0;
    Audio_EffectUsesCh2 = 0;
    Audio_EffectPan = AUDIO_PAN_INHERIT;
    Audio_EffectPan3 = AUDIO_PAN_INHERIT;

    Audio_LastChMask = 0;
    Audio_LastCh1Note = 0;
    Audio_LastCh2Note = 0;
    Audio_LastCh3Note = 0;
    Audio_LastCh4Param = 0;

    Audio_Ch1Duty = 2;
    Audio_Ch2Duty = 2;
    Audio_Ch1Env = 0xF1;
    Audio_Ch2Env = 0xF2;
    Audio_Ch4Env = 0xF1;
    Audio_Ch4Param = 0x00;
    Audio_Ch3Level = AUDIO_CH3_LEVEL_100;
    Audio_Ch3Wave = AUDIO_WAVE_TRIANGLE;
    Audio_Ch1Sweep = 0x00;

    Audio_SetCustomWaveTriangle();
#ifdef AUDIO_EXCLUDE_WAVE_LOAD_API
    Audio_ApplyWaveBytes(Audio_CustomWave);
#else
    Audio_LoadWave(Audio_Ch3Wave);
#endif
    Audio_Ch3Off();
}
Audio_LoadCustomWave

16바이트를 사용자 파형 캐시와 CH3 파형 RAM으로 복사합니다.

사용 형식

c
void __stackcall Audio_LoadCustomWave(const u8 *wave16);

매개변수

wave16

읽기 가능한 16바이트입니다. 상위·하위 니블이 연속 샘플을 인코딩합니다. NULL은 무시합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

복사 후 소스는 재사용할 수 있습니다. 쓰는 동안 DAC를 끄므로 호출자가 음을 다시 트리거해야 합니다.

사용 예

c
// Compare a triangle preset with an original packed 32-sample pulse waveform.
#include "gb_sound_example.h"
__prg_rom u8 custom_wave[16]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0,0,0,0,0};
void main() {
    sound_begin("WAVE PRESET CUSTOM");
    Audio_SetMasterVolume(3,3);
    Audio_LoadWave(AUDIO_WAVE_TRIANGLE);
    Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
    sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // Loading copies all sixteen bytes and enables the DAC without triggering a note.
    Audio_LoadCustomWave(custom_wave);
    sound_result[0]=Audio_CustomWave[0]; sound_result[1]=Audio_CustomWave[8];
    Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
    sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // The cache survives another preset load; select CUSTOM to reuse it.
    Audio_LoadWave(AUDIO_WAVE_SAW);
    Audio_LoadWave(AUDIO_WAVE_CUSTOM);
    sound_result[2]=WAVE0; sound_result[3]=WAVE8;
    Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
    sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    sound_end();
}

예상 결과

삼각파 프리셋, 독자 펄스 파형, 캐시에서 다시 로드한 같은 펄스 파형이 납니다. 각각 45프레임이며 사이에 15프레임 간격이 있습니다. 셋 모두 약 220 Hz이고 첫 번째만 음색이 다릅니다.

Audio_LoadCustomWave: DMG
DMG
Audio_LoadCustomWave: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:138

선언 주석 원문
Copy 16 packed sample bytes into the persistent custom cache and wave RAM.
A null pointer is ignored; the source is needed only for this call.

kitaqgb/lib/audio.c:614

c
void __stackcall Audio_LoadCustomWave(const u8 *wave16) {
    if (wave16 == 0) return;

    Audio_CustomWave[0] = wave16[0];   Audio_CustomWave[1] = wave16[1];
    Audio_CustomWave[2] = wave16[2];   Audio_CustomWave[3] = wave16[3];
    Audio_CustomWave[4] = wave16[4];   Audio_CustomWave[5] = wave16[5];
    Audio_CustomWave[6] = wave16[6];   Audio_CustomWave[7] = wave16[7];
    Audio_CustomWave[8] = wave16[8];   Audio_CustomWave[9] = wave16[9];
    Audio_CustomWave[10] = wave16[10]; Audio_CustomWave[11] = wave16[11];
    Audio_CustomWave[12] = wave16[12]; Audio_CustomWave[13] = wave16[13];
    Audio_CustomWave[14] = wave16[14]; Audio_CustomWave[15] = wave16[15];

    Audio_ApplyWaveBytes(Audio_CustomWave);
}
Audio_LoadWave

프리셋 또는 캐시된 사용자 파형을 CH3 파형 RAM에 설치합니다.

사용 형식

c
void __stackcall Audio_LoadWave(u8 wave_id);

매개변수

wave_id

AUDIO_WAVE_* ID 0..7입니다. 7은 캐시에 저장된 사용자 파형을 선택합니다. 7 초과 값은 아무 동작도 하지 않습니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

로드는 음을 시작하거나 Audio_Ch3Wave를 바꾸지 않습니다. 삼각파 프리셋은 사용자 캐시도 삼각파로 초기화합니다. 소리를 내려면 Audio_Ch3NoteOn을 호출하세요.

사용 예

c
// Compare a triangle preset with an original packed 32-sample pulse waveform.
#include "gb_sound_example.h"
__prg_rom u8 custom_wave[16]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0,0,0,0,0};
void main() {
    sound_begin("WAVE PRESET CUSTOM");
    Audio_SetMasterVolume(3,3);
    Audio_LoadWave(AUDIO_WAVE_TRIANGLE);
    Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
    sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // Loading copies all sixteen bytes and enables the DAC without triggering a note.
    Audio_LoadCustomWave(custom_wave);
    sound_result[0]=Audio_CustomWave[0]; sound_result[1]=Audio_CustomWave[8];
    Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
    sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // The cache survives another preset load; select CUSTOM to reuse it.
    Audio_LoadWave(AUDIO_WAVE_SAW);
    Audio_LoadWave(AUDIO_WAVE_CUSTOM);
    sound_result[2]=WAVE0; sound_result[3]=WAVE8;
    Audio_Ch3NoteOn(33,AUDIO_CH3_LEVEL_100);
    sound_wait(45); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    sound_end();
}

예상 결과

삼각파 프리셋, 독자 펄스 파형, 캐시에서 다시 로드한 같은 펄스 파형이 납니다. 각각 45프레임이며 사이에 15프레임 간격이 있습니다. 셋 모두 약 220 Hz이고 첫 번째만 음색이 다릅니다.

Audio_LoadWave: DMG
DMG
Audio_LoadWave: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:135

선언 주석 원문
Install a named preset or the cached custom wave. Unknown IDs are ignored.
This does not update Audio_Ch3Wave or trigger a new note.

kitaqgb/lib/audio.c:631

c
void __stackcall Audio_LoadWave(u8 wave_id) {
    if (wave_id == AUDIO_WAVE_TRIANGLE) Audio_LoadWave0();
    else if (wave_id == AUDIO_WAVE_SAW) Audio_LoadWave1();
    else if (wave_id == AUDIO_WAVE_VOWEL_A) Audio_LoadWave2();
    else if (wave_id == AUDIO_WAVE_VOWEL_I) Audio_LoadWave3();
    else if (wave_id == AUDIO_WAVE_VOWEL_U) Audio_LoadWave4();
    else if (wave_id == AUDIO_WAVE_VOWEL_E) Audio_LoadWave5();
    else if (wave_id == AUDIO_WAVE_VOWEL_O) Audio_LoadWave6();
    else if (wave_id == AUDIO_WAVE_CUSTOM) Audio_ApplyWaveBytes(Audio_CustomWave);
}
Audio_PlayMusic

지정한 뱅크의 곡을 처음부터 재생하도록 준비하고 악기, 패닝, delay를 초기화합니다.

사용 형식

c
void __stackcall Audio_PlayMusic(u8 bank, u8 *song);

매개변수

bank

스트림이 있는 ROM 뱅크이며 실제 배치와 일치해야 합니다.

song

곡 시작 주소입니다. 드라이버는 배열을 빌려 사용하므로 재생 내내 읽을 수 있어야 합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio.c보다 먼저 audio_hwregs_gb.c를 포함하고 시작 시 Audio_Init을 호출하세요. Audio_Update는 프레임마다 정확히 한 번, 약 59.7 Hz로 호출합니다. 스트림 읽기는 ROM 매핑을 일시적으로 바꾸므로 인터럽트에서 이 드라이버를 재진입 호출하지 마세요.

다음 Audio_Update에서 데이터를 읽습니다. NULL은 검사하지 않습니다. 기존 효과는 활성 상태를 유지합니다.

사용 예

c
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
    AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_LOOP
};
void main() {
    u8 delay;
    sound_begin("MUSIC PAUSE GATE");
    Audio_SetMasterVolume(3,3);
    Audio_PlayMusic(0,song);
    sound_wait(30);
    delay=Audio_Delay;
    Audio_SetPaused(1);
    sound_wait(30);
    sound_result[0]=(u8)(Audio_Delay==delay);
    sound_result[1]=Audio_Paused;
    Audio_SetPaused(0);
    sound_wait(30);
    sound_result[2]=Audio_Paused;
    // Disabling suppresses note writes; the next 30 updates still consume data.
    Audio_SetMusicEnabled(0);
    sound_wait(30);
    sound_result[3]=Audio_Delay;
    sound_result[4]=Audio_MusicEnabled;
    // Explicitly stop the sounding channel while leaving the stream running.
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(30);
    Audio_SetMusicEnabled(1);
    sound_wait(30);
    Audio_StopMusic();
    sound_result[5]=Audio_PlayingMusic;
    sound_wait(30);
    sound_end();
}

예상 결과

음 하나, 일시정지 중 무음, 재개, 음악 비활성화 중 유지되는 음, 명시적 채널 무음, 다시 활성화한 뒤 다음 음, 정지 순서입니다. RAM 검사에서도 일시정지된 30회 갱신 동안 delay가 유지되지만 비활성 게이트에서는 30까지 진행함을 확인합니다.

Audio_PlayMusic: DMG
DMG
Audio_PlayMusic: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:83

선언 주석 원문
Retain the bank and song pointer, reset legacy instruments/cursors, and arm
playback from the beginning. Supply a valid, persistent song; no bytes are copied
and null is not checked. Existing effect streams remain active.

kitaqgb/lib/audio.c:924

c
void __stackcall Audio_PlayMusic(u8 bank, u8 *song) {
    Audio_PlayingMusic = 0;
    Audio_MusicBank = bank;
    Audio_MusicPointer = song;
    Audio_MusicLoopPoint = song;
    Audio_Delay = 0;
    Audio_LastChMask = 0;

    Audio_Ch1Duty = 2;
    Audio_Ch2Duty = 2;
    Audio_Ch1Env = 0xF1;
    Audio_Ch2Env = 0xF2;
    Audio_Ch4Env = 0xF1;
    Audio_Ch4Param = 0x00;
    Audio_Ch3Level = AUDIO_CH3_LEVEL_100;
    Audio_Ch3Wave = AUDIO_WAVE_TRIANGLE;
    Audio_Ch1Sweep = 0x00;
    Audio_Pan = 0xFF;
    Audio_UpdateNR51();
    Audio_LoadWave(Audio_Ch3Wave);

    Audio_PlayingMusic = 1;
}
Audio_PlaySFX

현재 ROM 뱅크를 저장하고 기본 패닝을 상속하는 효과를 요청합니다.

사용 형식

c
void __stackcall Audio_PlaySFX(u8 *sfx, u8 priority);

매개변수

sfx

효과 바이트 스트림의 시작입니다. 펄스·CH3 형식은 주의사항을 참조하세요.

priority

우선순위 0..255입니다. 큰 값이 우선하며 같은 값도 현재 효과를 교체할 수 있습니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

효과는 갱신마다 (note,value) 쌍 하나를 소비하며 note=0에서 끝납니다. value는 펄스 효과에서는 NR12, CH3에서는 NR32입니다. CH3 데이터 앞에는 0xFF를 붙이세요. 완료까지 저장 공간을 유지해야 합니다. 우선순위는 슬롯 안에서 경쟁하며 같은 우선순위도 현재 효과를 교체할 수 있습니다.

일반 구성에서 효과 해제는 CH3를 끕니다. 음악이 정지했으면 CH1도 무음으로 만들지만, 음악 재생 중에는 이전 음악 음을 자동으로 다시 재생하지 않습니다. AUDIO_VBLANK_SFX_RESTORE를 사용하면 해제 시 ISR에 복원을 요청합니다.

사용 예

c
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
    40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
    33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
    40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
    sound_begin("BANKED SOUND EFFECT");
    Audio_SetMasterVolume(3,3);
    // Read the marker in bank 2 while restoring the caller's original mapping.
    Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
    sound_result[0]=Audio_EffectPriority;
    Audio_PlaySFXBanked(2,effect,4);
    sound_result[1]=Audio_EffectPriority;
    sound_wait(30);
    Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
    sound_result[2]=Audio_EffectPriority3;
    sound_wait(30);
    // Implicit-bank entry points capture bank 2; the service restores bank 1.
    __bankswitch(2);
    Audio_PlaySFX(effect,5);
    __bankswitch(1);
    sound_result[3]=Audio_EffectBank;
    sound_wait(30);
    __bankswitch(2);
    Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
    __bankswitch(1);
    sound_wait(6);
    Audio_StopSfx();
    sound_result[4]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    // Disabling effects releases current owners; re-enable before the next request.
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(6);
    Audio_SetSfxEnabled(0);
    sound_result[5]=Audio_SfxEnabled;
    sound_result[6]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    Audio_SetSfxEnabled(1);
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(30);
    sound_result[7]=Audio_SfxEnabled;
    sound_end();
}

예상 결과

뱅크 2 데이터가 왼쪽의 짧게 올라가는 펄스, 오른쪽의 파형 효과, 가운데 펄스를 재생합니다. 이어지는 예제는 오른쪽 펄스를 일찍 멈추고 효과를 비활성화했다가 재생을 다시 활성화합니다. 우선순위 4 요청은 5를 교체할 수 없습니다.

Audio_PlaySFX: DMG
DMG
Audio_PlaySFX: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:93

선언 주석 원문
Capture the currently mapped ROM bank and start an effect with inherited pan.
Use the explicit-bank API when the pointer belongs to another bank.

kitaqgb/lib/audio.c:1085

c
void __stackcall Audio_PlaySFX(u8 *sfx, u8 priority) {
    Audio_PlaySFXBanked(__rom_bank, sfx, priority);
}
Audio_PlaySFXBanked

명시한 소스 뱅크에서 효과 형식을 판별하고 기본 패닝을 상속해 재생을 요청합니다.

사용 형식

c
void __stackcall Audio_PlaySFXBanked(u8 bank, u8 *sfx, u8 priority);

매개변수

bank

스트림이 있는 ROM 뱅크이며 실제 배치와 일치해야 합니다.

sfx

효과 바이트 스트림의 시작입니다. 펄스·CH3 형식은 주의사항을 참조하세요.

priority

우선순위 0..255입니다. 큰 값이 우선하며 같은 값도 현재 효과를 교체할 수 있습니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

효과는 갱신마다 (note,value) 쌍 하나를 소비하며 note=0에서 끝납니다. value는 펄스 효과에서는 NR12, CH3에서는 NR32입니다. CH3 데이터 앞에는 0xFF를 붙이세요. 완료까지 저장 공간을 유지해야 합니다. 우선순위는 슬롯 안에서 경쟁하며 같은 우선순위도 현재 효과를 교체할 수 있습니다.

일반 구성에서 효과 해제는 CH3를 끕니다. 음악이 정지했으면 CH1도 무음으로 만들지만, 음악 재생 중에는 이전 음악 음을 자동으로 다시 재생하지 않습니다. AUDIO_VBLANK_SFX_RESTORE를 사용하면 해제 시 ISR에 복원을 요청합니다.

사용 예

c
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
    40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
    33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
    40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
    sound_begin("BANKED SOUND EFFECT");
    Audio_SetMasterVolume(3,3);
    // Read the marker in bank 2 while restoring the caller's original mapping.
    Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
    sound_result[0]=Audio_EffectPriority;
    Audio_PlaySFXBanked(2,effect,4);
    sound_result[1]=Audio_EffectPriority;
    sound_wait(30);
    Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
    sound_result[2]=Audio_EffectPriority3;
    sound_wait(30);
    // Implicit-bank entry points capture bank 2; the service restores bank 1.
    __bankswitch(2);
    Audio_PlaySFX(effect,5);
    __bankswitch(1);
    sound_result[3]=Audio_EffectBank;
    sound_wait(30);
    __bankswitch(2);
    Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
    __bankswitch(1);
    sound_wait(6);
    Audio_StopSfx();
    sound_result[4]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    // Disabling effects releases current owners; re-enable before the next request.
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(6);
    Audio_SetSfxEnabled(0);
    sound_result[5]=Audio_SfxEnabled;
    sound_result[6]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    Audio_SetSfxEnabled(1);
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(30);
    sound_result[7]=Audio_SfxEnabled;
    sound_end();
}

예상 결과

뱅크 2 데이터가 왼쪽의 짧게 올라가는 펄스, 오른쪽의 파형 효과, 가운데 펄스를 재생합니다. 이어지는 예제는 오른쪽 펄스를 일찍 멈추고 효과를 비활성화했다가 재생을 다시 활성화합니다. 우선순위 4 요청은 5를 교체할 수 없습니다.

Audio_PlaySFXBanked: DMG
DMG
Audio_PlaySFXBanked: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:95

선언 주석 원문
Start a banked effect with the channel's base pan, subject to priority arbitration.

kitaqgb/lib/audio.c:1078

c
void __stackcall Audio_PlaySFXBanked(u8 bank, u8 *sfx, u8 priority) {
    Audio_PlaySFXPannedBanked(bank, sfx, priority, AUDIO_PAN_INHERIT);
}
Audio_PlaySFXPanned

현재 ROM 뱅크를 저장하고 패닝을 별도 지정한 효과를 요청합니다.

사용 형식

c
void __stackcall Audio_PlaySFXPanned(u8 *sfx, u8 priority, u8 pan);

매개변수

sfx

효과 바이트 스트림의 시작입니다. 펄스·CH3 형식은 주의사항을 참조하세요.

priority

우선순위 0..255입니다. 큰 값이 우선하며 같은 값도 현재 효과를 교체할 수 있습니다.

pan

0=가운데, 1=왼쪽, 2=오른쪽, 3=무음입니다. 효과 API에서 0xFF를 포함한 3 초과 값은 기본 패닝을 상속합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

효과는 갱신마다 (note,value) 쌍 하나를 소비하며 note=0에서 끝납니다. value는 펄스 효과에서는 NR12, CH3에서는 NR32입니다. CH3 데이터 앞에는 0xFF를 붙이세요. 완료까지 저장 공간을 유지해야 합니다. 우선순위는 슬롯 안에서 경쟁하며 같은 우선순위도 현재 효과를 교체할 수 있습니다.

일반 구성에서 효과 해제는 CH3를 끕니다. 음악이 정지했으면 CH1도 무음으로 만들지만, 음악 재생 중에는 이전 음악 음을 자동으로 다시 재생하지 않습니다. AUDIO_VBLANK_SFX_RESTORE를 사용하면 해제 시 ISR에 복원을 요청합니다.

사용 예

c
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
    40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
    33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
    40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
    sound_begin("BANKED SOUND EFFECT");
    Audio_SetMasterVolume(3,3);
    // Read the marker in bank 2 while restoring the caller's original mapping.
    Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
    sound_result[0]=Audio_EffectPriority;
    Audio_PlaySFXBanked(2,effect,4);
    sound_result[1]=Audio_EffectPriority;
    sound_wait(30);
    Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
    sound_result[2]=Audio_EffectPriority3;
    sound_wait(30);
    // Implicit-bank entry points capture bank 2; the service restores bank 1.
    __bankswitch(2);
    Audio_PlaySFX(effect,5);
    __bankswitch(1);
    sound_result[3]=Audio_EffectBank;
    sound_wait(30);
    __bankswitch(2);
    Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
    __bankswitch(1);
    sound_wait(6);
    Audio_StopSfx();
    sound_result[4]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    // Disabling effects releases current owners; re-enable before the next request.
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(6);
    Audio_SetSfxEnabled(0);
    sound_result[5]=Audio_SfxEnabled;
    sound_result[6]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    Audio_SetSfxEnabled(1);
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(30);
    sound_result[7]=Audio_SfxEnabled;
    sound_end();
}

예상 결과

뱅크 2 데이터가 왼쪽의 짧게 올라가는 펄스, 오른쪽의 파형 효과, 가운데 펄스를 재생합니다. 이어지는 예제는 오른쪽 펄스를 일찍 멈추고 효과를 비활성화했다가 재생을 다시 활성화합니다. 우선순위 4 요청은 5를 교체할 수 없습니다.

Audio_PlaySFXPanned: DMG
DMG
Audio_PlaySFXPanned: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:98

선언 주석 원문
Capture the currently mapped ROM bank and request an effect with a pan override.
Use the explicit-bank API when the pointer belongs to another bank.

kitaqgb/lib/audio.c:1091

c
void __stackcall Audio_PlaySFXPanned(u8 *sfx, u8 priority, u8 pan) {
    Audio_PlaySFXPannedBanked(__rom_bank, sfx, priority, pan);
}
Audio_PlaySFXPannedBanked

뱅크, 우선순위, 패닝을 명시해 펄스 또는 CH3 효과 슬롯을 확보합니다.

사용 형식

c
void __stackcall Audio_PlaySFXPannedBanked(u8 bank, u8 *sfx, u8 priority, u8 pan);

매개변수

bank

스트림이 있는 ROM 뱅크이며 실제 배치와 일치해야 합니다.

sfx

효과 바이트 스트림의 시작입니다. 펄스·CH3 형식은 주의사항을 참조하세요.

priority

우선순위 0..255입니다. 큰 값이 우선하며 같은 값도 현재 효과를 교체할 수 있습니다.

pan

0=가운데, 1=왼쪽, 2=오른쪽, 3=무음입니다. 효과 API에서 0xFF를 포함한 3 초과 값은 기본 패닝을 상속합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

효과는 갱신마다 (note,value) 쌍 하나를 소비하며 note=0에서 끝납니다. value는 펄스 효과에서는 NR12, CH3에서는 NR32입니다. CH3 데이터 앞에는 0xFF를 붙이세요. 완료까지 저장 공간을 유지해야 합니다. 우선순위는 슬롯 안에서 경쟁하며 같은 우선순위도 현재 효과를 교체할 수 있습니다.

일반 구성에서 효과 해제는 CH3를 끕니다. 음악이 정지했으면 CH1도 무음으로 만들지만, 음악 재생 중에는 이전 음악 음을 자동으로 다시 재생하지 않습니다. AUDIO_VBLANK_SFX_RESTORE를 사용하면 해제 시 ISR에 복원을 요청합니다.

사용 예

c
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
    40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
    33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
    40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
    sound_begin("BANKED SOUND EFFECT");
    Audio_SetMasterVolume(3,3);
    // Read the marker in bank 2 while restoring the caller's original mapping.
    Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
    sound_result[0]=Audio_EffectPriority;
    Audio_PlaySFXBanked(2,effect,4);
    sound_result[1]=Audio_EffectPriority;
    sound_wait(30);
    Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
    sound_result[2]=Audio_EffectPriority3;
    sound_wait(30);
    // Implicit-bank entry points capture bank 2; the service restores bank 1.
    __bankswitch(2);
    Audio_PlaySFX(effect,5);
    __bankswitch(1);
    sound_result[3]=Audio_EffectBank;
    sound_wait(30);
    __bankswitch(2);
    Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
    __bankswitch(1);
    sound_wait(6);
    Audio_StopSfx();
    sound_result[4]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    // Disabling effects releases current owners; re-enable before the next request.
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(6);
    Audio_SetSfxEnabled(0);
    sound_result[5]=Audio_SfxEnabled;
    sound_result[6]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    Audio_SetSfxEnabled(1);
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(30);
    sound_result[7]=Audio_SfxEnabled;
    sound_end();
}

예상 결과

뱅크 2 데이터가 왼쪽의 짧게 올라가는 펄스, 오른쪽의 파형 효과, 가운데 펄스를 재생합니다. 이어지는 예제는 오른쪽 펄스를 일찍 멈추고 효과를 비활성화했다가 재생을 다시 활성화합니다. 우선순위 4 요청은 5를 교체할 수 없습니다.

Audio_PlaySFXPannedBanked: DMG
DMG
Audio_PlaySFXPannedBanked: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:103

선언 주석 원문
Retain a banked effect stream if its priority equals or exceeds the current
owner's priority, or that slot is empty. A leading CH3 marker selects the wave
slot and is skipped; other streams use the pulse slot. Paused requests are ignored.
Keep stream storage valid until completion; acceptance does not trigger a note.

kitaqgb/lib/audio.c:1041

c
void __stackcall Audio_PlaySFXPannedBanked(u8 bank, u8 *sfx, u8 priority, u8 pan) {
    u8 sfx_pan = pan;
    u8 use_ch3 = 0;
    if (sfx_pan > AUDIO_PAN_MUTE) sfx_pan = AUDIO_PAN_INHERIT;

    if (Audio_Paused != 0) return;
    if (sfx != 0) {
        use_ch3 = Audio_SfxStartsOnCh3Banked(bank, sfx);
        if (use_ch3 != 0) {
            if (Audio_EffectPointer3 == 0 || priority >= Audio_EffectPriority3) {
                Audio_EffectPointer3 = sfx + 1;
                Audio_EffectPriority3 = priority;
                Audio_EffectBank3 = bank;
                Audio_EffectPan3 = sfx_pan;
                Audio_UpdateNR51();
            }
            return;
        }
    }
    if (Audio_EffectPointer == 0 || priority >= Audio_EffectPriority) {
#ifdef AUDIO_VBLANK_SFX_AUTO_CH2
        // Choose pulse-channel ownership when accepting the effect, so its later
        // updates and deferred recovery agree on which physical channel was borrowed.
        Audio_EffectUsesCh2 = (u8)(AudioVBlank_MusicPlaying != 0 &&
                                   AudioVBlank_MusicEnabled != 0);
#else
        Audio_EffectUsesCh2 = 0;
#endif
        Audio_EffectPointer = sfx;
        Audio_EffectPriority = priority;
        Audio_EffectBank = bank;
        Audio_EffectPan = sfx_pan;
        Audio_UpdateNR51();
    }
}
Audio_SetCh1Duty

다음 CH1 음의 듀티 인덱스를 저장합니다.

사용 형식

c
void __stackcall Audio_SetCh1Duty(u8 duty);

매개변수

duty

펄스 듀티 인덱스입니다. 하위 2비트를 저장합니다. 0=12.5%, 1=25%, 2=50%, 3=75%입니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

이 호출만으로는 현재 사운드 레지스터가 바뀌지 않습니다. 적용하려면 저장한 값을 음 시작 함수에 전달하거나 대응하는 스트림을 사용하세요.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_SetCh1Duty: DMG
DMG
Audio_SetCh1Duty: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:141

선언 주석 원문
Cache the low two duty bits for the next CH1 note; do not change the active register.

kitaqgb/lib/audio.c:644

c
void __stackcall Audio_SetCh1Duty(u8 duty) {
    Audio_Ch1Duty = (u8)(duty & 3);
}
Audio_SetCh2Duty

다음 CH2 음의 듀티 인덱스를 저장합니다.

사용 형식

c
void __stackcall Audio_SetCh2Duty(u8 duty);

매개변수

duty

펄스 듀티 인덱스입니다. 하위 2비트를 저장합니다. 0=12.5%, 1=25%, 2=50%, 3=75%입니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

이 호출만으로는 현재 사운드 레지스터가 바뀌지 않습니다. 적용하려면 저장한 값을 음 시작 함수에 전달하거나 대응하는 스트림을 사용하세요.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_SetCh2Duty: DMG
DMG
Audio_SetCh2Duty: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:143

선언 주석 원문
Cache the low two duty bits for the next CH2 note; do not change the active register.

kitaqgb/lib/audio.c:649

c
void __stackcall Audio_SetCh2Duty(u8 duty) {
    Audio_Ch2Duty = (u8)(duty & 3);
}
Audio_SetCh3Level

다음 CH3 음의 NR32 출력 레벨을 저장합니다.

사용 형식

c
void __stackcall Audio_SetCh3Level(u8 level);

매개변수

level

NR32 인코딩: 0x00=무음, 0x20=100%, 0x40=50%, 0x60=25%입니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

이 호출만으로는 현재 사운드 레지스터가 바뀌지 않습니다. 적용하려면 저장한 값을 음 시작 함수에 전달하거나 대응하는 스트림을 사용하세요.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_SetCh3Level: DMG
DMG
Audio_SetCh3Level: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:145

선언 주석 원문
Cache the raw NR32 level encoding for the next CH3 note without writing hardware.

kitaqgb/lib/audio.c:654

c
void __stackcall Audio_SetCh3Level(u8 level) {
    Audio_Ch3Level = level;
}
Audio_SetCh4Param

다음 CH4 음의 NR43 노이즈 매개변수를 저장합니다.

사용 형식

c
void __stackcall Audio_SetCh4Param(u8 param);

매개변수

param

원시 NR43입니다. 비트 7..4는 클록 시프트, 비트 3은 짧은 LFSR, 비트 2..0은 분주 코드입니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

이 호출만으로는 현재 사운드 레지스터가 바뀌지 않습니다. 적용하려면 저장한 값을 음 시작 함수에 전달하거나 대응하는 스트림을 사용하세요.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_SetCh4Param: DMG
DMG
Audio_SetCh4Param: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:147

선언 주석 원문
Cache the raw noise polynomial encoding for the next CH4 note without writing hardware.

kitaqgb/lib/audio.c:659

c
void __stackcall Audio_SetCh4Param(u8 param) {
    Audio_Ch4Param = param;
}
Audio_SetMasterVolume

좌우 마스터 레벨을 0..7로 제한해 즉시 쓰고 진행 중인 페이드를 취소합니다.

사용 형식

c
void __stackcall Audio_SetMasterVolume(u8 left, u8 right);

매개변수

left

왼쪽 마스터 레벨 0..7입니다. 더 큰 값은 7로 제한합니다. 0도 완전한 무음은 아닙니다.

right

오른쪽 마스터 레벨 0..7입니다. 더 큰 값은 7로 제한합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 예

c
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
    sound_begin("PAN AND VOLUME");
    Audio_SetMasterVolume(7,7);
    Audio_Ch1NoteOn(33,0xC0,2);
    Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
    sound_result[0]=NR51;
    sound_wait(30);
    // Packed low two bits are CH1: 2 means right. Other channels remain centered.
    Audio_SetPanPacked(2);
    sound_result[1]=NR51;
    sound_wait(30);
    Audio_SetPanPacked(0);
    sound_result[2]=NR51;
    Audio_FadeToMasterVolume(1,1,5);
    sound_wait(30);
    sound_result[3]=NR50;
    sound_result[4]=Audio_FadeActive;
    sound_wait(30);
    // Cancel halfway through a rise: retain volume 4 instead of reaching 7.
    Audio_FadeToMasterVolume(7,7,5);
    sound_wait(15);
    Audio_CancelMasterVolumeFade();
    sound_result[5]=NR50;
    sound_wait(30);
    sound_result[6]=NR50;
    // A zero fade interval sets the target immediately. Level zero is not mute.
    Audio_FadeToMasterVolume(0,0,0);
    sound_result[7]=NR50;
    sound_wait(30);
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(15);
    sound_end();
}

예상 결과

A4가 왼쪽, 오른쪽, 가운데로 이동합니다. 가운데에서는 레벨 7에서 1로 줄어든 뒤 4로 올라가 유지됩니다. 레벨 0도 작게 들리며 채널을 멈춰야 무음이 됩니다. 출력 경로 변경 후 필터 과도음이 감쇠하며 남을 수 있습니다.

Audio_SetMasterVolume: DMG
DMG
Audio_SetMasterVolume: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:120

선언 주석 원문
Clamp both output levels to 0..7, cancel any fade, and write NR50 immediately.

kitaqgb/lib/audio.c:515

c
void __stackcall Audio_SetMasterVolume(u8 left, u8 right) {
    Audio_MasterLeft = Audio_ClampVolume(left);
    Audio_MasterRight = Audio_ClampVolume(right);
    Audio_FadeTargetLeft = Audio_MasterLeft;
    Audio_FadeTargetRight = Audio_MasterRight;
    Audio_FadeStepFrames = 0;
    Audio_FadeCounter = 0;
    Audio_FadeActive = 0;
    Audio_UpdateNR50();
}
Audio_SetMusicEnabled

일반 음악 디코더가 새 음을 쓰는지 제어합니다.

사용 형식

c
void __stackcall Audio_SetMusicEnabled(u8 on);

매개변수

on

0은 비활성화, 0 이외는 활성화입니다. 무음과 갱신 차단의 차이는 해당 함수 설명을 확인하세요.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

비활성화해도 스트림은 진행하고 악기·패닝 제어를 처리합니다. 현재 음은 멈추지 않습니다. 재생을 일시정지하려면 Audio_SetPaused를 사용하세요.

사용 예

c
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
    AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_LOOP
};
void main() {
    u8 delay;
    sound_begin("MUSIC PAUSE GATE");
    Audio_SetMasterVolume(3,3);
    Audio_PlayMusic(0,song);
    sound_wait(30);
    delay=Audio_Delay;
    Audio_SetPaused(1);
    sound_wait(30);
    sound_result[0]=(u8)(Audio_Delay==delay);
    sound_result[1]=Audio_Paused;
    Audio_SetPaused(0);
    sound_wait(30);
    sound_result[2]=Audio_Paused;
    // Disabling suppresses note writes; the next 30 updates still consume data.
    Audio_SetMusicEnabled(0);
    sound_wait(30);
    sound_result[3]=Audio_Delay;
    sound_result[4]=Audio_MusicEnabled;
    // Explicitly stop the sounding channel while leaving the stream running.
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(30);
    Audio_SetMusicEnabled(1);
    sound_wait(30);
    Audio_StopMusic();
    sound_result[5]=Audio_PlayingMusic;
    sound_wait(30);
    sound_end();
}

예상 결과

음 하나, 일시정지 중 무음, 재개, 음악 비활성화 중 유지되는 음, 명시적 채널 무음, 다시 활성화한 뒤 다음 음, 정지 순서입니다. RAM 검사에서도 일시정지된 30회 갱신 동안 delay가 유지되지만 비활성 게이트에서는 30까지 진행함을 확인합니다.

Audio_SetMusicEnabled: DMG
DMG
Audio_SetMusicEnabled: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:114

선언 주석 원문
Set the music-processing gate. This does not silence notes already playing
or stop the legacy stream cursor from consuming commands.

kitaqgb/lib/audio.c:498

c
void __stackcall Audio_SetMusicEnabled(u8 on) {
    if (on != 0) Audio_MusicEnabled = 1;
    else Audio_MusicEnabled = 0;
}
Audio_SetPan

물리 채널 하나의 기본 패닝을 바꾼 뒤 활성 효과의 패닝 덮어쓰기를 다시 적용합니다.

사용 형식

c
void __stackcall Audio_SetPan(u8 ch, u8 pan);

매개변수

ch

채널 ID: 0=CH1, 1=CH2, 2=CH3, 3=CH4입니다. 직접 API와 음악 스트림이 같은 ID를 사용합니다.

pan

0=가운데, 1=왼쪽, 2=오른쪽, 3=무음입니다. 효과 API에서 0xFF를 포함한 3 초과 값은 기본 패닝을 상속합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

알 수 없는 채널은 CH4를 선택합니다. 여기서 pan이 0..3 밖이면 무음이며 효과 API의 상속 설정과 다릅니다.

사용 예

c
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
    sound_begin("PAN AND VOLUME");
    Audio_SetMasterVolume(7,7);
    Audio_Ch1NoteOn(33,0xC0,2);
    Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
    sound_result[0]=NR51;
    sound_wait(30);
    // Packed low two bits are CH1: 2 means right. Other channels remain centered.
    Audio_SetPanPacked(2);
    sound_result[1]=NR51;
    sound_wait(30);
    Audio_SetPanPacked(0);
    sound_result[2]=NR51;
    Audio_FadeToMasterVolume(1,1,5);
    sound_wait(30);
    sound_result[3]=NR50;
    sound_result[4]=Audio_FadeActive;
    sound_wait(30);
    // Cancel halfway through a rise: retain volume 4 instead of reaching 7.
    Audio_FadeToMasterVolume(7,7,5);
    sound_wait(15);
    Audio_CancelMasterVolumeFade();
    sound_result[5]=NR50;
    sound_wait(30);
    sound_result[6]=NR50;
    // A zero fade interval sets the target immediately. Level zero is not mute.
    Audio_FadeToMasterVolume(0,0,0);
    sound_result[7]=NR50;
    sound_wait(30);
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(15);
    sound_end();
}

예상 결과

A4가 왼쪽, 오른쪽, 가운데로 이동합니다. 가운데에서는 레벨 7에서 1로 줄어든 뒤 4로 올라가 유지됩니다. 레벨 0도 작게 들리며 채널을 멈춰야 무음이 됩니다. 출력 경로 변경 후 필터 과도음이 감쇠하며 남을 수 있습니다.

Audio_SetPan: DMG
DMG
Audio_SetPan: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:129

선언 주석 원문
Update the base pan for a physical channel and reapply active effect overrides.
Unknown channel IDs select CH4; unsupported pan values mute the selected channel.

kitaqgb/lib/audio.c:558

c
void __stackcall Audio_SetPan(u8 ch, u8 pan) {
    u8 r_bit;
    u8 l_bit;
    u8 mask;

    if (ch == AUDIO_CHANNEL_CH1) {
        r_bit = 0x01;
        l_bit = 0x10;
    } else if (ch == AUDIO_CHANNEL_CH2) {
        r_bit = 0x02;
        l_bit = 0x20;
    } else if (ch == AUDIO_CHANNEL_CH3) {
        r_bit = 0x04;
        l_bit = 0x40;
    } else {
        r_bit = 0x08;
        l_bit = 0x80;
    }

    mask = (u8)(l_bit | r_bit);
    Audio_Pan = (u8)(Audio_Pan & (u8)~mask);

    if (pan == AUDIO_PAN_CENTER) Audio_Pan = (u8)(Audio_Pan | mask);
    else if (pan == AUDIO_PAN_LEFT) Audio_Pan = (u8)(Audio_Pan | l_bit);
    else if (pan == AUDIO_PAN_RIGHT) Audio_Pan = (u8)(Audio_Pan | r_bit);

    Audio_UpdateNR51();
}
Audio_SetPanPacked

한 바이트에서 네 기본 패닝값을 풀어 NR51을 한 번 갱신합니다.

사용 형식

c
void __stackcall Audio_SetPanPacked(u8 packed);

매개변수

packed

물리 채널당 2비트입니다. CH1은 비트 0..1, CH2는 2..3, CH3는 4..5, CH4는 6..7입니다. 각 필드는 패닝값을 사용합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 예

c
// A sustained pulse moves left, right and center, then fades to a quieter level.
#include "gb_sound_example.h"
void main() {
    sound_begin("PAN AND VOLUME");
    Audio_SetMasterVolume(7,7);
    Audio_Ch1NoteOn(33,0xC0,2);
    Audio_SetPan(AUDIO_CHANNEL_CH1,AUDIO_PAN_LEFT);
    sound_result[0]=NR51;
    sound_wait(30);
    // Packed low two bits are CH1: 2 means right. Other channels remain centered.
    Audio_SetPanPacked(2);
    sound_result[1]=NR51;
    sound_wait(30);
    Audio_SetPanPacked(0);
    sound_result[2]=NR51;
    Audio_FadeToMasterVolume(1,1,5);
    sound_wait(30);
    sound_result[3]=NR50;
    sound_result[4]=Audio_FadeActive;
    sound_wait(30);
    // Cancel halfway through a rise: retain volume 4 instead of reaching 7.
    Audio_FadeToMasterVolume(7,7,5);
    sound_wait(15);
    Audio_CancelMasterVolumeFade();
    sound_result[5]=NR50;
    sound_wait(30);
    sound_result[6]=NR50;
    // A zero fade interval sets the target immediately. Level zero is not mute.
    Audio_FadeToMasterVolume(0,0,0);
    sound_result[7]=NR50;
    sound_wait(30);
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(15);
    sound_end();
}

예상 결과

A4가 왼쪽, 오른쪽, 가운데로 이동합니다. 가운데에서는 레벨 7에서 1로 줄어든 뒤 4로 올라가 유지됩니다. 레벨 0도 작게 들리며 채널을 멈춰야 무음이 됩니다. 출력 경로 변경 후 필터 과도음이 감쇠하며 남을 수 있습니다.

Audio_SetPanPacked: DMG
DMG
Audio_SetPanPacked: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_mix.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-mix.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:132

선언 주석 원문
Two bits per channel (CH1 in bits 0-1): center, left, right, mute.
Applies all four positions with one NR51 update for sequencer automation.

kitaqgb/lib/audio.c:589

c
void __stackcall Audio_SetPanPacked(u8 packed) {
    u8 mix = 0;
    u8 pan = (u8)(packed & 3);
    if (pan == AUDIO_PAN_CENTER) mix = (u8)(mix | 0x11);
    else if (pan == AUDIO_PAN_LEFT) mix = (u8)(mix | 0x10);
    else if (pan == AUDIO_PAN_RIGHT) mix = (u8)(mix | 0x01);
    pan = (u8)((packed >> 2) & 3);
    if (pan == AUDIO_PAN_CENTER) mix = (u8)(mix | 0x22);
    else if (pan == AUDIO_PAN_LEFT) mix = (u8)(mix | 0x20);
    else if (pan == AUDIO_PAN_RIGHT) mix = (u8)(mix | 0x02);
    pan = (u8)((packed >> 4) & 3);
    if (pan == AUDIO_PAN_CENTER) mix = (u8)(mix | 0x44);
    else if (pan == AUDIO_PAN_LEFT) mix = (u8)(mix | 0x40);
    else if (pan == AUDIO_PAN_RIGHT) mix = (u8)(mix | 0x04);
    pan = (u8)((packed >> 6) & 3);
    if (pan == AUDIO_PAN_CENTER) mix = (u8)(mix | 0x88);
    else if (pan == AUDIO_PAN_LEFT) mix = (u8)(mix | 0x80);
    else if (pan == AUDIO_PAN_RIGHT) mix = (u8)(mix | 0x08);
    Audio_Pan = mix;
    Audio_UpdateNR51();
}
Audio_SetPaused

음악·효과 위치를 유지하며 일시정지 때 무음으로 만듭니다. 재개하면 재시작 가능한 CH1, CH2, CH4 음을 다시 트리거합니다.

사용 형식

c
void __stackcall Audio_SetPaused(u8 on);

매개변수

on

0은 비활성화, 0 이외는 활성화입니다. 무음과 갱신 차단의 차이는 해당 함수 설명을 확인하세요.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio.c보다 먼저 audio_hwregs_gb.c를 포함하고 시작 시 Audio_Init을 호출하세요. Audio_Update는 프레임마다 정확히 한 번, 약 59.7 Hz로 호출합니다. 스트림 읽기는 ROM 매핑을 일시적으로 바꾸므로 인터럽트에서 이 드라이버를 재진입 호출하지 마세요.

이 함수는 CH3를 다시 트리거하지 않습니다. 효과는 이후 갱신에서 계속됩니다. 직접 음 시작 호출은 일시정지 중에도 소리를 낼 수 있습니다.

사용 예

c
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
    AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_LOOP
};
void main() {
    u8 delay;
    sound_begin("MUSIC PAUSE GATE");
    Audio_SetMasterVolume(3,3);
    Audio_PlayMusic(0,song);
    sound_wait(30);
    delay=Audio_Delay;
    Audio_SetPaused(1);
    sound_wait(30);
    sound_result[0]=(u8)(Audio_Delay==delay);
    sound_result[1]=Audio_Paused;
    Audio_SetPaused(0);
    sound_wait(30);
    sound_result[2]=Audio_Paused;
    // Disabling suppresses note writes; the next 30 updates still consume data.
    Audio_SetMusicEnabled(0);
    sound_wait(30);
    sound_result[3]=Audio_Delay;
    sound_result[4]=Audio_MusicEnabled;
    // Explicitly stop the sounding channel while leaving the stream running.
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(30);
    Audio_SetMusicEnabled(1);
    sound_wait(30);
    Audio_StopMusic();
    sound_result[5]=Audio_PlayingMusic;
    sound_wait(30);
    sound_end();
}

예상 결과

음 하나, 일시정지 중 무음, 재개, 음악 비활성화 중 유지되는 음, 명시적 채널 무음, 다시 활성화한 뒤 다음 음, 정지 순서입니다. RAM 검사에서도 일시정지된 30회 갱신 동안 delay가 유지되지만 비활성 게이트에서는 30까지 진행함을 확인합니다.

Audio_SetPaused: DMG
DMG
Audio_SetPaused: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:90

선언 주석 원문
On pause entry, silence hardware while retaining cursors. On resume, retrigger
eligible legacy CH1, CH2 and CH4 notes; CH3 is not retriggered here. Updates still
advance master fades while paused, and effect playback resumes on a later update.

kitaqgb/lib/audio.c:1010

c
void __stackcall Audio_SetPaused(u8 on) {
    if (on != 0) {
        if (Audio_Paused == 0) {
            Audio_Paused = 1;
            Audio_SilenceAll();
        }
    } else {
        if (Audio_Paused != 0) {
            Audio_Paused = 0;
            if (Audio_PlayingMusic != 0 && Audio_MusicEnabled != 0) {
                if ((Audio_LastChMask & AUDIO_RESUME_CH1) != 0 && Audio_EffectPointer == 0) {
                    Audio_Ch1NoteOn(Audio_LastCh1Note, Audio_Ch1Env, Audio_Ch1Duty);
                }
                if ((Audio_LastChMask & AUDIO_RESUME_CH2) != 0) {
                    Audio_Ch2NoteOn(Audio_LastCh2Note, Audio_Ch2Env, Audio_Ch2Duty);
                }
                if ((Audio_LastChMask & AUDIO_RESUME_CH4) != 0) {
                    Audio_Ch4NoteOn(Audio_LastCh4Param, Audio_Ch4Env);
                }
            }
        }
    }
}
Audio_SetSfxEnabled

효과의 음 쓰기를 허용하거나 차단합니다. 비활성화하면 효과 슬롯도 해제합니다.

사용 형식

c
void __stackcall Audio_SetSfxEnabled(u8 on);

매개변수

on

0은 비활성화, 0 이외는 활성화입니다. 무음과 갱신 차단의 차이는 해당 함수 설명을 확인하세요.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

일반 구성에서 효과 해제는 CH3를 끕니다. 음악이 정지했으면 CH1도 무음으로 만들지만, 음악 재생 중에는 이전 음악 음을 자동으로 다시 재생하지 않습니다. AUDIO_VBLANK_SFX_RESTORE를 사용하면 해제 시 ISR에 복원을 요청합니다.

비활성 상태에서 시작해도 스트림 등록은 가능하지만 갱신 시 음 쓰기를 억제합니다. 소리가 나게 재생하려면 요청 전에 효과를 활성화하세요.

사용 예

c
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
    40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
    33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
    40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
    sound_begin("BANKED SOUND EFFECT");
    Audio_SetMasterVolume(3,3);
    // Read the marker in bank 2 while restoring the caller's original mapping.
    Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
    sound_result[0]=Audio_EffectPriority;
    Audio_PlaySFXBanked(2,effect,4);
    sound_result[1]=Audio_EffectPriority;
    sound_wait(30);
    Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
    sound_result[2]=Audio_EffectPriority3;
    sound_wait(30);
    // Implicit-bank entry points capture bank 2; the service restores bank 1.
    __bankswitch(2);
    Audio_PlaySFX(effect,5);
    __bankswitch(1);
    sound_result[3]=Audio_EffectBank;
    sound_wait(30);
    __bankswitch(2);
    Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
    __bankswitch(1);
    sound_wait(6);
    Audio_StopSfx();
    sound_result[4]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    // Disabling effects releases current owners; re-enable before the next request.
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(6);
    Audio_SetSfxEnabled(0);
    sound_result[5]=Audio_SfxEnabled;
    sound_result[6]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    Audio_SetSfxEnabled(1);
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(30);
    sound_result[7]=Audio_SfxEnabled;
    sound_end();
}

예상 결과

뱅크 2 데이터가 왼쪽의 짧게 올라가는 펄스, 오른쪽의 파형 효과, 가운데 펄스를 재생합니다. 이어지는 예제는 오른쪽 펄스를 일찍 멈추고 효과를 비활성화했다가 재생을 다시 활성화합니다. 우선순위 4 요청은 5를 교체할 수 없습니다.

Audio_SetSfxEnabled: DMG
DMG
Audio_SetSfxEnabled: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:117

선언 주석 원문
Enable effect note writes, or disable them and release both effect streams.
Disabling follows Audio_StopSfx recovery rules rather than silencing all channels.

kitaqgb/lib/audio.c:505

c
void __stackcall Audio_SetSfxEnabled(u8 on) {
    if (on != 0) {
        Audio_SfxEnabled = 1;
    } else {
        Audio_SfxEnabled = 0;
        Audio_StopSfx();
    }
}
Audio_StopChannel

물리 채널 하나를 멈추고 재개 마스크에서 그 음악 음을 제거합니다.

사용 형식

c
void __stackcall Audio_StopChannel(u8 ch);

매개변수

ch

채널 ID: 0=CH1, 1=CH2, 2=CH3, 3=CH4입니다. 직접 API와 음악 스트림이 같은 ID를 사용합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

CH1/CH3는 해당 효과 슬롯도 지웁니다. 0..3 밖의 값은 아무 동작도 하지 않습니다. VBlank가 저장한 음은 별도로 관리합니다.

사용 예

c
// Four isolated voices, each lasting 30 frames, separated by 15 silent frames.
#include "gb_sound_example.h"
void main() {
    sound_begin("FOUR SOUND CHANNELS");
    Audio_SetMasterVolume(3,3);
    // CH1: A4, 50% duty, fixed envelope volume 12.
    Audio_SetCh1Duty(2);
    sound_result[0]=Audio_Ch1Duty;
    Audio_Ch1NoteOn(33,0xC0,Audio_Ch1Duty);
    sound_result[1]=NR12;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH1); sound_wait(15);
    // CH2: A4, 25% duty. Changing the cached duty takes effect on this trigger.
    Audio_SetCh2Duty(1);
    sound_result[2]=Audio_Ch2Duty;
    Audio_Ch2NoteOn(33,0xC0,Audio_Ch2Duty);
    sound_result[3]=NR22;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH2); sound_wait(15);
    // CH3: the initialized triangle wave, at 50% digital output level.
    Audio_SetCh3Level(AUDIO_CH3_LEVEL_50);
    sound_result[4]=Audio_Ch3Level;
    Audio_Ch3NoteOn(33,Audio_Ch3Level);
    sound_result[5]=NR32;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH3); sound_wait(15);
    // CH4: a sustained noise burst; param is NR43, not a pitched note number.
    Audio_SetCh4Param(0x35);
    sound_result[6]=Audio_Ch4Param;
    Audio_Ch4NoteOn(Audio_Ch4Param,0xC0);
    sound_result[7]=NR43;
    sound_wait(30); Audio_StopChannel(AUDIO_CHANNEL_CH4); sound_wait(15);
    sound_end();
}

예상 결과

약 0.5초의 무음 후 CH1 A4, CH2 A4, CH3 A3, 노이즈가 순서대로 납니다. 각 소리는 30프레임이며 사이에 15프레임의 간격이 있습니다. SEQUENCE COMPLETE는 프로그램 완료를 나타냅니다. 소리는 녹음으로 확인하세요.

Audio_StopChannel: DMG
DMG
Audio_StopChannel: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_channels.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-channels.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:110

선언 주석 원문
Stop a physical channel and clear its legacy resume bit. CH1 also clears the
pulse effect stream; CH3 clears the wave effect stream. This is the legacy
channel API and does not clear a VBlank driver's independently latched notes.

kitaqgb/lib/audio.c:981

c
void __stackcall Audio_StopChannel(u8 ch) {
    if (ch == AUDIO_CHANNEL_CH1) {
        Audio_EffectPointer = 0;
        Audio_EffectPriority = 0;
        Audio_EffectBank = 0;
        Audio_EffectPan = AUDIO_PAN_INHERIT;
        Audio_LastChMask = (u8)(Audio_LastChMask & (u8)~AUDIO_RESUME_CH1);
        Audio_UpdateNR51();
        Audio_SilenceCh1();
    } else if (ch == AUDIO_CHANNEL_CH2) {
        Audio_LastChMask = (u8)(Audio_LastChMask & (u8)~AUDIO_RESUME_CH2);
        Audio_SilenceCh2();
    } else if (ch == AUDIO_CHANNEL_CH3) {
        Audio_EffectPointer3 = 0;
        Audio_EffectPriority3 = 0;
        Audio_EffectBank3 = 0;
        Audio_EffectPan3 = AUDIO_PAN_INHERIT;
        Audio_LastChMask = (u8)(Audio_LastChMask & (u8)~AUDIO_RESUME_CH3);
        Audio_UpdateNR51();
        Audio_Ch3Off();
    } else if (ch == AUDIO_CHANNEL_CH4) {
        Audio_LastChMask = (u8)(Audio_LastChMask & (u8)~AUDIO_RESUME_CH4);
        Audio_SilenceCh4();
    }
}
Audio_StopMusic

곡 재생과 재개 마스크를 지운 뒤 네 채널을 즉시 무음으로 만듭니다.

사용 형식

c
void Audio_StopMusic();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

효과 포인터는 남아 있으므로 나중의 Audio_Update에서 효과가 날 수 있습니다. 모두 멈추려면 Audio_StopSfx도 호출하세요.

사용 예

c
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
    AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_LOOP
};
void main() {
    u8 delay;
    sound_begin("MUSIC PAUSE GATE");
    Audio_SetMasterVolume(3,3);
    Audio_PlayMusic(0,song);
    sound_wait(30);
    delay=Audio_Delay;
    Audio_SetPaused(1);
    sound_wait(30);
    sound_result[0]=(u8)(Audio_Delay==delay);
    sound_result[1]=Audio_Paused;
    Audio_SetPaused(0);
    sound_wait(30);
    sound_result[2]=Audio_Paused;
    // Disabling suppresses note writes; the next 30 updates still consume data.
    Audio_SetMusicEnabled(0);
    sound_wait(30);
    sound_result[3]=Audio_Delay;
    sound_result[4]=Audio_MusicEnabled;
    // Explicitly stop the sounding channel while leaving the stream running.
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(30);
    Audio_SetMusicEnabled(1);
    sound_wait(30);
    Audio_StopMusic();
    sound_result[5]=Audio_PlayingMusic;
    sound_wait(30);
    sound_end();
}

예상 결과

음 하나, 일시정지 중 무음, 재개, 음악 비활성화 중 유지되는 음, 명시적 채널 무음, 다시 활성화한 뒤 다음 음, 정지 순서입니다. RAM 검사에서도 일시정지된 30회 갱신 동안 delay가 유지되지만 비활성 게이트에서는 30까지 진행함을 확인합니다.

Audio_StopMusic: DMG
DMG
Audio_StopMusic: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:86

선언 주석 원문
Stop legacy music and clear its resume mask, then silence all physical channels.
Effect pointers remain active and may produce sound on a later update.

kitaqgb/lib/audio.c:952

c
void Audio_StopMusic() {
    Audio_PlayingMusic = 0;
    Audio_LastChMask = 0;
    Audio_SilenceAll();
}
Audio_StopSfx

두 효과 스트림과 패닝 덮어쓰기를 지우고 빌린 채널을 해제합니다.

사용 형식

c
void Audio_StopSfx();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

효과는 갱신마다 (note,value) 쌍 하나를 소비하며 note=0에서 끝납니다. value는 펄스 효과에서는 NR12, CH3에서는 NR32입니다. CH3 데이터 앞에는 0xFF를 붙이세요. 완료까지 저장 공간을 유지해야 합니다. 우선순위는 슬롯 안에서 경쟁하며 같은 우선순위도 현재 효과를 교체할 수 있습니다.

일반 구성에서 효과 해제는 CH3를 끕니다. 음악이 정지했으면 CH1도 무음으로 만들지만, 음악 재생 중에는 이전 음악 음을 자동으로 다시 재생하지 않습니다. AUDIO_VBLANK_SFX_RESTORE를 사용하면 해제 시 ISR에 복원을 요청합니다.

사용 예

c
// Each pair lasts one update. Priority controls replacement within each slot.
#include "gb_sound_example.h"
#pragma bank 2
__prg_rom u8 effect[]={33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,33,0xC0,
    40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,40,0xC0,0};
__prg_rom u8 wave_effect[]={AUDIO_SFX_CH3_MARKER,
    33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,33,0x20,
    40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,40,0x20,0};
#pragma bank 0
void main() {
    sound_begin("BANKED SOUND EFFECT");
    Audio_SetMasterVolume(3,3);
    // Read the marker in bank 2 while restoring the caller's original mapping.
    Audio_PlaySFXPannedBanked(2,effect,5,AUDIO_PAN_LEFT);
    sound_result[0]=Audio_EffectPriority;
    Audio_PlaySFXBanked(2,effect,4);
    sound_result[1]=Audio_EffectPriority;
    sound_wait(30);
    Audio_PlaySFXPannedBanked(2,wave_effect,5,AUDIO_PAN_RIGHT);
    sound_result[2]=Audio_EffectPriority3;
    sound_wait(30);
    // Implicit-bank entry points capture bank 2; the service restores bank 1.
    __bankswitch(2);
    Audio_PlaySFX(effect,5);
    __bankswitch(1);
    sound_result[3]=Audio_EffectBank;
    sound_wait(30);
    __bankswitch(2);
    Audio_PlaySFXPanned(effect,5,AUDIO_PAN_RIGHT);
    __bankswitch(1);
    sound_wait(6);
    Audio_StopSfx();
    sound_result[4]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    // Disabling effects releases current owners; re-enable before the next request.
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(6);
    Audio_SetSfxEnabled(0);
    sound_result[5]=Audio_SfxEnabled;
    sound_result[6]=(u8)(Audio_EffectPointer==0);
    sound_wait(24);
    Audio_SetSfxEnabled(1);
    Audio_PlaySFXBanked(2,effect,5);
    sound_wait(30);
    sound_result[7]=Audio_SfxEnabled;
    sound_end();
}

예상 결과

뱅크 2 데이터가 왼쪽의 짧게 올라가는 펄스, 오른쪽의 파형 효과, 가운데 펄스를 재생합니다. 이어지는 예제는 오른쪽 펄스를 일찍 멈추고 효과를 비활성화했다가 재생을 다시 활성화합니다. 우선순위 4 요청은 5를 교체할 수 없습니다.

Audio_StopSfx: DMG
DMG
Audio_StopSfx: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_sfx.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-sfx.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:106

선언 주석 원문
Clear both effect streams and their pan overrides. When not paused, release
borrowed channels through the configured legacy or VBlank recovery path.

kitaqgb/lib/audio.c:960

c
void Audio_StopSfx() {
    Audio_EffectPointer = 0;
    Audio_EffectPriority = 0;
    Audio_EffectBank = 0;
    Audio_EffectPointer3 = 0;
    Audio_EffectPriority3 = 0;
    Audio_EffectBank3 = 0;
    Audio_EffectPan = AUDIO_PAN_INHERIT;
    Audio_EffectPan3 = AUDIO_PAN_INHERIT;
    Audio_UpdateNR51();

    if (Audio_Paused != 0) return;
    Audio_ReleaseCh1AfterSfx();
    Audio_RestoreCh3FromMusic();
}
Audio_Update

음량 페이드를 한 번 진행시키고, 일시정지가 아니면 효과 다음 음악을 처리합니다.

사용 형식

c
void Audio_Update();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio.c보다 먼저 audio_hwregs_gb.c를 포함하고 시작 시 Audio_Init을 호출하세요. Audio_Update는 프레임마다 정확히 한 번, 약 59.7 Hz로 호출합니다. 스트림 읽기는 ROM 매핑을 일시적으로 바꾸므로 인터럽트에서 이 드라이버를 재진입 호출하지 마세요.

일시정지 중에도 페이드는 진행합니다. WAIT n을 읽은 뒤 n회의 대기 호출이 있으므로 다음 명령은 n+1회 갱신 후 실행됩니다.

사용 예

c
// Original two-note phrase: pause preserves the cursor; the enable gate does not.
#include "gb_sound_example.h"
__prg_rom u8 song[]={
    AUDIO_CMD_SET_INST,AUDIO_STREAM_CHANNEL_CH1,2,0xC0,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,33,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_NOTE,AUDIO_STREAM_CHANNEL_CH1,40,AUDIO_CMD_WAIT,59,
    AUDIO_CMD_LOOP
};
void main() {
    u8 delay;
    sound_begin("MUSIC PAUSE GATE");
    Audio_SetMasterVolume(3,3);
    Audio_PlayMusic(0,song);
    sound_wait(30);
    delay=Audio_Delay;
    Audio_SetPaused(1);
    sound_wait(30);
    sound_result[0]=(u8)(Audio_Delay==delay);
    sound_result[1]=Audio_Paused;
    Audio_SetPaused(0);
    sound_wait(30);
    sound_result[2]=Audio_Paused;
    // Disabling suppresses note writes; the next 30 updates still consume data.
    Audio_SetMusicEnabled(0);
    sound_wait(30);
    sound_result[3]=Audio_Delay;
    sound_result[4]=Audio_MusicEnabled;
    // Explicitly stop the sounding channel while leaving the stream running.
    Audio_StopChannel(AUDIO_CHANNEL_CH1);
    sound_wait(30);
    Audio_SetMusicEnabled(1);
    sound_wait(30);
    Audio_StopMusic();
    sound_result[5]=Audio_PlayingMusic;
    sound_wait(30);
    sound_end();
}

예상 결과

음 하나, 일시정지 중 무음, 재개, 음악 비활성화 중 유지되는 음, 명시적 채널 무음, 다시 활성화한 뒤 다음 음, 정지 순서입니다. RAM 검사에서도 일시정지된 30회 갱신 동안 delay가 유지되지만 비활성 게이트에서는 30까지 진행함을 확인합니다.

Audio_Update: DMG
DMG
Audio_Update: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_music.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-music.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio.h:79

선언 주석 원문
Advance the master fade first. Unless paused, service both effect streams
then the optional legacy music decoder. Call once per frame for frame-based timing.

kitaqgb/lib/audio.c:849

c
void Audio_Update() {
    Audio_UpdateFade();
    if (Audio_Paused != 0) return;

    Audio_ServiceSfx();
#ifndef AUDIO_EXCLUDE_LEGACY_MUSIC_SERVICE
    Audio_ServiceMusic();
#endif
}

audio_vblank.h — VBlank IRQ를 통한 음악 재생

VBlank에서 음악을 처리하고 효과의 채널 사용권을 조정하며 프레임 훅을 제공합니다. 같은 곡을 일반 음악 디코더로도 진행시키지 마세요.

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

AudioVBlank_DisableIrq

IE의 VBlank 비트만 지우며 다른 인터럽트 소스와 소리는 유지합니다.

사용 형식

c
void AudioVBlank_DisableIrq();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

사용 예

c
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
    u8 before;
    sound_begin("VBLANK MUSIC GATES");
    Audio_NoiseEffectActive=0;
    AudioVBlank_Init();
    sound_result[0]=AudioVBlank_MusicPlaying;
    AudioVBlank_Ch1Envelope=0xC0;
    Audio_SetMasterVolume(3,3);
    hook_count=0; AudioVBlank_FrameHook=frame_hook;
    AudioVBlank_SetMusic(irq_song);
    AudioVBlank_Play();
    AudioVBlank_EnableIrq();
    sound_wait(45);
    // Disable music processing while the hook and current note remain active.
    __asm { DI }
    AudioVBlank_SetEnabled(0); before=hook_count;
    __asm { EI }
    sound_wait(30);
    sound_result[1]=(u8)(hook_count!=before);
    __asm { DI }
    AudioVBlank_Stop();
    __asm { EI }
    sound_wait(30);
    __asm { DI }
    AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
    __asm { EI }
    sound_wait(45);
    AudioVBlank_DisableIrq();
    before=hook_count;
    sound_wait(30);
    sound_result[2]=(u8)(hook_count==before);
    sound_result[3]=(u8)(AudioVBlank_IE&1);
    AudioVBlank_Stop(); sound_wait(30);
    sound_end();
}

예상 결과

ISR이 두 음으로 된 곡을 재생합니다. 음악 갱신 차단은 현재 소리를 유지하고 Stop은 무음으로 만듭니다. 재시작 후 IRQ 차단도 소리를 유지하므로 서로 비교하세요. RAM은 음악 비활성화 중 훅이 실행되고 IRQ 비활성화 때 멈추는 것을 확인합니다.

AudioVBlank_DisableIrq: DMG
DMG
AudioVBlank_DisableIrq: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:118

선언 주석 원문
Clear only the VBlank bit in IE. Other interrupt sources and current sound remain unchanged.

kitaqgb/lib/audio_vblank_control.inc:129

c
void AudioVBlank_DisableIrq()
{
    AudioVBlank_IE = (u8)(AudioVBlank_IE & 0xFE);
}
AudioVBlank_EnableIrq

IE의 VBlank 비트를 설정하고 EI를 실행해 CPU 인터럽트를 전역 활성화합니다.

사용 형식

c
void AudioVBlank_EnableIrq();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

사용 예

c
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
    u8 before;
    sound_begin("VBLANK MUSIC GATES");
    Audio_NoiseEffectActive=0;
    AudioVBlank_Init();
    sound_result[0]=AudioVBlank_MusicPlaying;
    AudioVBlank_Ch1Envelope=0xC0;
    Audio_SetMasterVolume(3,3);
    hook_count=0; AudioVBlank_FrameHook=frame_hook;
    AudioVBlank_SetMusic(irq_song);
    AudioVBlank_Play();
    AudioVBlank_EnableIrq();
    sound_wait(45);
    // Disable music processing while the hook and current note remain active.
    __asm { DI }
    AudioVBlank_SetEnabled(0); before=hook_count;
    __asm { EI }
    sound_wait(30);
    sound_result[1]=(u8)(hook_count!=before);
    __asm { DI }
    AudioVBlank_Stop();
    __asm { EI }
    sound_wait(30);
    __asm { DI }
    AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
    __asm { EI }
    sound_wait(45);
    AudioVBlank_DisableIrq();
    before=hook_count;
    sound_wait(30);
    sound_result[2]=(u8)(hook_count==before);
    sound_result[3]=(u8)(AudioVBlank_IE&1);
    AudioVBlank_Stop(); sound_wait(30);
    sound_end();
}

예상 결과

ISR이 두 음으로 된 곡을 재생합니다. 음악 갱신 차단은 현재 소리를 유지하고 Stop은 무음으로 만듭니다. 재시작 후 IRQ 차단도 소리를 유지하므로 서로 비교하세요. RAM은 음악 비활성화 중 훅이 실행되고 IRQ 비활성화 때 멈추는 것을 확인합니다.

AudioVBlank_EnableIrq: DMG
DMG
AudioVBlank_EnableIrq: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:116

선언 주석 원문
Enable the VBlank source in IE and execute EI, enabling CPU interrupts globally.
Install the correct interrupt vector and initialize driver state first.

kitaqgb/lib/audio_vblank_control.inc:122

c
void AudioVBlank_EnableIrq()
{
    AudioVBlank_IE = (u8)(AudioVBlank_IE | 0x01);
    __asm { EI }
}
AudioVBlank_Init

VBlank 음악 상태, 큐, 악기, 훅을 초기화합니다. APU 초기화나 인터럽트 차단은 하지 않습니다.

사용 형식

c
void AudioVBlank_Init();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

사용 예

c
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
    u8 before;
    sound_begin("VBLANK MUSIC GATES");
    Audio_NoiseEffectActive=0;
    AudioVBlank_Init();
    sound_result[0]=AudioVBlank_MusicPlaying;
    AudioVBlank_Ch1Envelope=0xC0;
    Audio_SetMasterVolume(3,3);
    hook_count=0; AudioVBlank_FrameHook=frame_hook;
    AudioVBlank_SetMusic(irq_song);
    AudioVBlank_Play();
    AudioVBlank_EnableIrq();
    sound_wait(45);
    // Disable music processing while the hook and current note remain active.
    __asm { DI }
    AudioVBlank_SetEnabled(0); before=hook_count;
    __asm { EI }
    sound_wait(30);
    sound_result[1]=(u8)(hook_count!=before);
    __asm { DI }
    AudioVBlank_Stop();
    __asm { EI }
    sound_wait(30);
    __asm { DI }
    AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
    __asm { EI }
    sound_wait(45);
    AudioVBlank_DisableIrq();
    before=hook_count;
    sound_wait(30);
    sound_result[2]=(u8)(hook_count==before);
    sound_result[3]=(u8)(AudioVBlank_IE&1);
    AudioVBlank_Stop(); sound_wait(30);
    sound_end();
}

예상 결과

ISR이 두 음으로 된 곡을 재생합니다. 음악 갱신 차단은 현재 소리를 유지하고 Stop은 무음으로 만듭니다. 재시작 후 IRQ 차단도 소리를 유지하므로 서로 비교하세요. RAM은 음악 비활성화 중 훅이 실행되고 IRQ 비활성화 때 멈추는 것을 확인합니다.

AudioVBlank_Init: DMG
DMG
AudioVBlank_Init: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:85

선언 주석 원문
Reset software playback state, queue counters, instruments and the frame hook.
Call before enabling this ISR; the routine does not mask interrupts or
initialize the APU registers and cannot synchronize with an active handler.

kitaqgb/lib/audio_vblank_control.inc:6

c
void AudioVBlank_Init()
{
    AudioVBlank_MusicEnabled = 1;
    AudioVBlank_MusicPlaying = 0;
    AudioVBlank_MusicDelay = 0;
    AudioVBlank_MusicStart = 0;
    AudioVBlank_MusicPointer = 0;
    AudioVBlank_MusicLoopPoint = 0;
    AudioVBlank_Step = 0;
    AudioVBlank_Ch2Note = AUDIO_VBLANK_REST;
    AudioVBlank_Ch1Note = AUDIO_VBLANK_REST;
    AudioVBlank_Ch3Note = AUDIO_VBLANK_REST;
    AudioVBlank_Ch2LatchedNote = AUDIO_VBLANK_STOP;
    AudioVBlank_Ch1LatchedNote = AUDIO_VBLANK_STOP;
    AudioVBlank_Ch3LatchedNote = AUDIO_VBLANK_STOP;
    AudioVBlank_RestoreCh1Pending = 0;
    AudioVBlank_RestoreCh3Pending = 0;
    AudioVBlank_Ch4Param = AUDIO_VBLANK_REST;
    AudioVBlank_Ch1Envelope = 0xF1;
    AudioVBlank_Ch2Envelope = 0xF2;
    AudioVBlank_Ch4Envelope = 0xF1;
    AudioVBlank_Ch1Duty = 0x80;
    AudioVBlank_Ch2Duty = 0x80;
    AudioVBlank_Ch1Sweep = 0x00;
    AudioVBlank_Ch3Level = 0x20;
    AudioVBlank_ControlCommand = 0;
    AudioVBlank_ControlArg0 = 0;
    AudioVBlank_ControlArg1 = 0;
    AudioVBlank_ControlArg2 = 0;
    AudioVBlank_QueueMode = 0;
    AudioVBlank_QueueReadIndex = 0;
    AudioVBlank_QueueWriteIndex = 0;
    AudioVBlank_QueueCount = 0;
    AudioVBlank_QueueUnderruns = 0;
    AudioVBlank_FrameHook = 0;
}
AudioVBlank_Play

선택한 곡을 처음부터 재시작하고 큐 모드를 해제합니다. 곡이 NULL이면 재생을 멈춥니다.

사용 형식

c
void AudioVBlank_Play();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

사용 예

c
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
    u8 before;
    sound_begin("VBLANK MUSIC GATES");
    Audio_NoiseEffectActive=0;
    AudioVBlank_Init();
    sound_result[0]=AudioVBlank_MusicPlaying;
    AudioVBlank_Ch1Envelope=0xC0;
    Audio_SetMasterVolume(3,3);
    hook_count=0; AudioVBlank_FrameHook=frame_hook;
    AudioVBlank_SetMusic(irq_song);
    AudioVBlank_Play();
    AudioVBlank_EnableIrq();
    sound_wait(45);
    // Disable music processing while the hook and current note remain active.
    __asm { DI }
    AudioVBlank_SetEnabled(0); before=hook_count;
    __asm { EI }
    sound_wait(30);
    sound_result[1]=(u8)(hook_count!=before);
    __asm { DI }
    AudioVBlank_Stop();
    __asm { EI }
    sound_wait(30);
    __asm { DI }
    AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
    __asm { EI }
    sound_wait(45);
    AudioVBlank_DisableIrq();
    before=hook_count;
    sound_wait(30);
    sound_result[2]=(u8)(hook_count==before);
    sound_result[3]=(u8)(AudioVBlank_IE&1);
    AudioVBlank_Stop(); sound_wait(30);
    sound_end();
}

예상 결과

ISR이 두 음으로 된 곡을 재생합니다. 음악 갱신 차단은 현재 소리를 유지하고 Stop은 무음으로 만듭니다. 재시작 후 IRQ 차단도 소리를 유지하므로 서로 비교하세요. RAM은 음악 비활성화 중 훅이 실행되고 IRQ 비활성화 때 멈추는 것을 확인합니다.

AudioVBlank_Play: DMG
DMG
AudioVBlank_Play: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:103

선언 주석 원문
Restart the selected direct song at its beginning, leaving queue mode.
A null song invokes Stop; this does not enable the music or IRQ gates.

kitaqgb/lib/audio_vblank_control.inc:58

c
void AudioVBlank_Play()
{
    if (AudioVBlank_MusicStart == 0) {
        AudioVBlank_Stop();
        return;
    }
    AudioVBlank_MusicPointer = AudioVBlank_MusicStart;
    AudioVBlank_MusicLoopPoint = AudioVBlank_MusicStart;
    AudioVBlank_MusicDelay = 0;
    AudioVBlank_Step = 0;
    AudioVBlank_QueueMode = 0;
    AudioVBlank_MusicPlaying = 1;
}
AudioVBlank_PlayMusic

직접 읽는 곡을 선택하고 처음부터 재생하도록 준비합니다.

사용 형식

c
void __stackcall AudioVBlank_PlayMusic(u8 *song);

매개변수

song

곡 시작 주소입니다. 드라이버는 배열을 빌려 사용하므로 재생 내내 읽을 수 있어야 합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

사용 예

c
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
    u8 before;
    sound_begin("VBLANK MUSIC GATES");
    Audio_NoiseEffectActive=0;
    AudioVBlank_Init();
    sound_result[0]=AudioVBlank_MusicPlaying;
    AudioVBlank_Ch1Envelope=0xC0;
    Audio_SetMasterVolume(3,3);
    hook_count=0; AudioVBlank_FrameHook=frame_hook;
    AudioVBlank_SetMusic(irq_song);
    AudioVBlank_Play();
    AudioVBlank_EnableIrq();
    sound_wait(45);
    // Disable music processing while the hook and current note remain active.
    __asm { DI }
    AudioVBlank_SetEnabled(0); before=hook_count;
    __asm { EI }
    sound_wait(30);
    sound_result[1]=(u8)(hook_count!=before);
    __asm { DI }
    AudioVBlank_Stop();
    __asm { EI }
    sound_wait(30);
    __asm { DI }
    AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
    __asm { EI }
    sound_wait(45);
    AudioVBlank_DisableIrq();
    before=hook_count;
    sound_wait(30);
    sound_result[2]=(u8)(hook_count==before);
    sound_result[3]=(u8)(AudioVBlank_IE&1);
    AudioVBlank_Stop(); sound_wait(30);
    sound_end();
}

예상 결과

ISR이 두 음으로 된 곡을 재생합니다. 음악 갱신 차단은 현재 소리를 유지하고 Stop은 무음으로 만듭니다. 재시작 후 IRQ 차단도 소리를 유지하므로 서로 비교하세요. RAM은 음악 비활성화 중 훅이 실행되고 IRQ 비활성화 때 멈추는 것을 확인합니다.

AudioVBlank_PlayMusic: DMG
DMG
AudioVBlank_PlayMusic: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:105

선언 주석 원문
Select and restart a directly addressed song. This is not the banked WRAM-queue path.

kitaqgb/lib/audio_vblank_control.inc:73

c
void __stackcall AudioVBlank_PlayMusic(u8 *song)
{
    AudioVBlank_SetMusic(song);
    AudioVBlank_Play();
}
AudioVBlank_QueuePlay

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

큐 모드가 활성화되어 있고 레코드가 하나 이상 있으면 재생을 활성화합니다. 커서, 지연값, 음악 활성화 및 일시정지 상태는 유지합니다. 새 스트림을 시작하기 전에 큐를 초기화하고 미리 채우세요.

사용 형식

c
u8 AudioVBlank_QueuePlay();

반환값

요청이 수락되면 1, 큐가 비어 있거나 큐 모드가 아니면 0을 반환합니다. 레코드를 소비하려면 ISR이 실행 중이어야 하고, 음악이 활성화되어 있으며 드라이버가 일시정지 상태가 아니어야 합니다.

사용 조건과 제한

AudioVBlank_Init 다음에 QueueReset, QueueRefill, QueuePlay를 차례로 호출합니다. 일반 audio_vblank.c를 빌드에 포함하세요. AUDIO_VBLANK_CORE_ONLY를 정의하면 C로 작성된 큐 공급 함수가 제외됩니다. 메인 코드가 5바이트 레코드 16개를 담는 큐를 채우고, VBlank ISR이 이를 소비합니다.

큐를 채우는 코드는 메인 실행 흐름의 한 곳으로 제한하세요. 재귀 호출하거나 ISR 또는 FrameHook에서 호출하면 안 됩니다. 각 레코드를 공개하는 짧은 구간에서는 IE를 저장하고 인터럽트 소스를 차단한 뒤 IE와 SVBK를 복원합니다. IME는 바꾸지 않습니다. 호출 측에서 소스 ROM/RAM 뱅크를 선택하고 유지해야 합니다.

시간 정보를 가진 레코드는 delay, ch1_note, ch2_note, ch3_note, ch4_noise_param 순서입니다. END도 완전한 5바이트 레코드로 제공하세요. LOOP는 공급 코드에서 필요한 레코드를 다시 제출하는 방식으로 처리합니다. 가변 길이의 직접 재생 명령 스트림을 변환 없이 넘기면 안 됩니다.

사용 예

c
if(AudioVBlank_QueuePlay()==0) sound_result[0]++;
    AudioVBlank_EnableIrq();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

직접 만든 8음 프레이즈를 여섯 번 재생한 뒤 멈춥니다. 음표 48개와 END를 합친 49개 레코드를 16슬롯 큐로 전달합니다. 49개 레코드의 수락, 언더런 0회, 재생 종료, 빈 큐·가득 찬 큐·NULL·개수 0인 경우, CGB WRAM 뱅크 복원, IME 보존, 재생 중 출력과 종료 후 무음을 검사합니다.

AudioVBlank_QueuePlay: DMG
DMG
AudioVBlank_QueuePlay: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\audio_vblank_queue.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\audio_vblank_queue.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:96

선언 주석 원문
Start/resume queued playback; return 1 on success, 0 for an empty/nonqueue mode.
Does not enable the interrupt, music gate or clear pause. Queue before starting.

kitaqgb/lib/audio_vblank_queue.inc:112

c
u8 AudioVBlank_QueuePlay()
{
    u8 saved_ie;
    u8 started;
    saved_ie = AudioVBlank_IE;
    AudioVBlank_IE = 0;
    started = 0;
    if (AudioVBlank_QueueMode != 0 && AudioVBlank_QueueCount != 0) {
        AudioVBlank_MusicPlaying = 1;
        started = 1;
    }
    AudioVBlank_IE = saved_ie;
    return started;
}
AudioVBlank_QueueRefill

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

완전한 5바이트 레코드를 빈 큐 슬롯에 복사하고, 각 복사가 끝난 뒤에만 소비 측에 공개합니다. 한 번에 최대 16개 레코드를 받습니다.

사용 형식

c
u8 __stackcall AudioVBlank_QueueRefill(const u8 *records, u8 count);

매개변수

records

현재 읽을 수 있는 뱅크에 놓인 레코드 배열입니다. 수락되는 레코드마다 읽을 수 있는 5바이트가 필요합니다. NULL 포인터이면 0을 반환합니다.

count

제출할 레코드 수이며 바이트 수가 아닙니다. 16보다 큰 값은 16으로 제한하고, 0이면 아무 작업도 하지 않습니다.

반환값

실제로 수락한 레코드 수인 0~16을 반환합니다. 큐가 가득 찼거나 입력이 NULL이거나 개수가 0이거나 큐 모드가 아니면 0입니다. 소스 포인터는 반환값의 다섯 배만큼 전진시키세요. 호출 중 ISR이 슬롯을 비울 수 있으므로 반환값은 호출 시작 시의 빈 슬롯 수와 다를 수 있습니다.

사용 조건과 제한

AudioVBlank_Init 다음에 QueueReset, QueueRefill, QueuePlay를 차례로 호출합니다. 일반 audio_vblank.c를 빌드에 포함하세요. AUDIO_VBLANK_CORE_ONLY를 정의하면 C로 작성된 큐 공급 함수가 제외됩니다. 메인 코드가 5바이트 레코드 16개를 담는 큐를 채우고, VBlank ISR이 이를 소비합니다.

큐를 채우는 코드는 메인 실행 흐름의 한 곳으로 제한하세요. 재귀 호출하거나 ISR 또는 FrameHook에서 호출하면 안 됩니다. 각 레코드를 공개하는 짧은 구간에서는 IE를 저장하고 인터럽트 소스를 차단한 뒤 IE와 SVBK를 복원합니다. IME는 바꾸지 않습니다. 호출 측에서 소스 ROM/RAM 뱅크를 선택하고 유지해야 합니다.

시간 정보를 가진 레코드는 delay, ch1_note, ch2_note, ch3_note, ch4_noise_param 순서입니다. END도 완전한 5바이트 레코드로 제공하세요. LOOP는 공급 코드에서 필요한 레코드를 다시 제출하는 방식으로 처리합니다. 가변 길이의 직접 재생 명령 스트림을 변환 없이 넘기면 안 됩니다.

사용 예

c
next=AudioVBlank_QueueRefill(queue_song,16);
    // next counts records; each record occupies five source bytes.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

직접 만든 8음 프레이즈를 여섯 번 재생한 뒤 멈춥니다. 음표 48개와 END를 합친 49개 레코드를 16슬롯 큐로 전달합니다. 49개 레코드의 수락, 언더런 0회, 재생 종료, 빈 큐·가득 찬 큐·NULL·개수 0인 경우, CGB WRAM 뱅크 복원, IME 보존, 재생 중 출력과 종료 후 무음을 검사합니다.

AudioVBlank_QueueRefill: DMG
DMG
AudioVBlank_QueueRefill: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\audio_vblank_queue.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\audio_vblank_queue.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:93

선언 주석 원문
Copy complete records from the currently mapped source; return records accepted.
Each call attempts at most 16 records and stops when full. Null/zero returns 0.
Supports ROM and RAM sources, restores SVBK and IE, and never changes IME.
Single foreground producer only: do not call from an ISR or frame hook.
LOOP must be expanded by the producer. END occupies a full five-byte record.

kitaqgb/lib/audio_vblank_queue.inc:93

c
u8 __stackcall AudioVBlank_QueueRefill(const u8 *records, u8 count)
{
    u8 accepted;
    u8 i;
    if (records == 0 || count == 0 || AudioVBlank_QueueMode == 0) return 0;
    if (count > AUDIO_VBLANK_QUEUE_RECORDS) count = AUDIO_VBLANK_QUEUE_RECORDS;
    accepted = 0;
    while (accepted < count) {
        if (AudioVBlank_QueueCount >= AUDIO_VBLANK_QUEUE_RECORDS) break;
        for (i = 0; i < 5; i++) AudioVBlank_QueueStaging[i] = records[i];
        if (AudioVBlank_QueuePublish() == 0) break;
        records += 5;
        accepted++;
    }
    return accepted;
}
AudioVBlank_QueueReset

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

재생을 멈추고 출력을 끈 다음 큐 모드로 전환합니다. 읽기·쓰기 위치, 레코드 수, 언더런 횟수를 0으로 초기화합니다. 대기 중인 레코드를 버려 새 스트림을 준비합니다.

사용 형식

c
void AudioVBlank_QueueReset();

반환값

반환값은 없습니다. 음악 활성화 설정과 일시정지 설정은 유지됩니다.

사용 조건과 제한

AudioVBlank_Init 다음에 QueueReset, QueueRefill, QueuePlay를 차례로 호출합니다. 일반 audio_vblank.c를 빌드에 포함하세요. AUDIO_VBLANK_CORE_ONLY를 정의하면 C로 작성된 큐 공급 함수가 제외됩니다. 메인 코드가 5바이트 레코드 16개를 담는 큐를 채우고, VBlank ISR이 이를 소비합니다.

큐를 채우는 코드는 메인 실행 흐름의 한 곳으로 제한하세요. 재귀 호출하거나 ISR 또는 FrameHook에서 호출하면 안 됩니다. 각 레코드를 공개하는 짧은 구간에서는 IE를 저장하고 인터럽트 소스를 차단한 뒤 IE와 SVBK를 복원합니다. IME는 바꾸지 않습니다. 호출 측에서 소스 ROM/RAM 뱅크를 선택하고 유지해야 합니다.

시간 정보를 가진 레코드는 delay, ch1_note, ch2_note, ch3_note, ch4_noise_param 순서입니다. END도 완전한 5바이트 레코드로 제공하세요. LOOP는 공급 코드에서 필요한 레코드를 다시 제출하는 방식으로 처리합니다. 가변 길이의 직접 재생 명령 스트림을 변환 없이 넘기면 안 됩니다.

사용 예

c
AudioVBlank_QueueReset(); // Silence playback and discard any queued records.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

직접 만든 8음 프레이즈를 여섯 번 재생한 뒤 멈춥니다. 음표 48개와 END를 합친 49개 레코드를 16슬롯 큐로 전달합니다. 49개 레코드의 수락, 언더런 0회, 재생 종료, 빈 큐·가득 찬 큐·NULL·개수 0인 경우, CGB WRAM 뱅크 복원, IME 보존, 재생 중 출력과 종료 후 무음을 검사합니다.

AudioVBlank_QueueReset: DMG
DMG
AudioVBlank_QueueReset: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\audio_vblank_queue.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\audio_vblank_queue.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:87

선언 주석 원문
Stop music and select an empty WRAM queue; preserve IE, IME and enable/pause gates.

kitaqgb/lib/audio_vblank_queue.inc:76

c
void AudioVBlank_QueueReset()
{
    u8 saved_ie;
    saved_ie = AudioVBlank_IE;
    AudioVBlank_IE = 0;
    AudioVBlank_Stop();
    AudioVBlank_QueueMode = 1;
    AudioVBlank_QueueReadIndex = 0;
    AudioVBlank_QueueWriteIndex = 0;
    AudioVBlank_QueueCount = 0;
    AudioVBlank_QueueUnderruns = 0;
    AudioVBlank_IE = saved_ie;
}
AudioVBlank_RequestRestoreCh1

대기 요청이 없으면 펄스 해제 전용 요청 2를 설정하며 기존 복원 요청 1은 보존합니다.

사용 형식

c
void AudioVBlank_RequestRestoreCh1();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

복원 함수를 직접 호출할 때는 효과가 채널을 해제했는지 호출자가 확인하고 이후 대기 플래그를 지워야 합니다. 요청 함수만으로는 사운드 레지스터를 쓰지 않습니다.

사용 예

c
// Exercise the recovery API with IRQ disabled and explicit effect ownership.
#define SOUND_VBLANK
#include "gb_sound_example.h"
void main() {
    sound_begin("EFFECT RECOVERY");
    Audio_NoiseEffectActive=0; AudioVBlank_Init();
    Audio_SetMasterVolume(3,3);
    AudioVBlank_MusicPlaying=1;
    AudioVBlank_Ch1Envelope=0xC0; AudioVBlank_Ch1LatchedNote=33;
    AudioVBlank_Ch3LatchedNote=33;
    // Value 1 represents a suppressed BGM event and survives a release request.
    AudioVBlank_RestoreCh1Pending=1;
    AudioVBlank_RequestRestoreCh1();
    sound_result[0]=AudioVBlank_RestoreCh1Pending;
    AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
    sound_wait(30);
    // Without a pending event, RequestRestore creates release-only value 2.
    AudioVBlank_RequestRestoreCh1();
    sound_result[1]=AudioVBlank_RestoreCh1Pending;
    AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
    sound_wait(30);
    AudioVBlank_RestoreCh3Pending=1;
    AudioVBlank_RequestRestoreCh3();
    sound_result[2]=AudioVBlank_RestoreCh3Pending;
    AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
    sound_wait(30);
    AudioVBlank_RequestRestoreCh3();
    sound_result[3]=AudioVBlank_RestoreCh3Pending;
    AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
    sound_wait(30);
    AudioVBlank_Stop();
    sound_end();
}

예상 결과

펄스 복원, 무음, 파형 복원, 무음을 각각 30프레임씩 들을 수 있습니다. 해제 요청은 대기값 1을 보존하며, 대기 이벤트가 없을 때 요청하면 해제 전용값 2가 됩니다. 여기서는 IRQ를 끄고 호출자가 채널 사용권을 직접 관리합니다.

AudioVBlank_RequestRestoreCh1: DMG
DMG
AudioVBlank_RequestRestoreCh1: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_recovery.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-recovery.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:129

선언 주석 원문
Request deferred pulse-channel release only when no recovery is pending.
Preserve value 1, which records a music event suppressed while an effect owned it.

kitaqgb/lib/audio_vblank.c:908

c
void AudioVBlank_RequestRestoreCh1()
{
    if (AudioVBlank_RestoreCh1Pending == 0)
        AudioVBlank_RestoreCh1Pending = 2;
}
AudioVBlank_RequestRestoreCh3

대기 요청이 없으면 파형 해제 전용 요청 2를 설정하며 기존 복원 요청 1은 보존합니다.

사용 형식

c
void AudioVBlank_RequestRestoreCh3();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

복원 함수를 직접 호출할 때는 효과가 채널을 해제했는지 호출자가 확인하고 이후 대기 플래그를 지워야 합니다. 요청 함수만으로는 사운드 레지스터를 쓰지 않습니다.

사용 예

c
// Exercise the recovery API with IRQ disabled and explicit effect ownership.
#define SOUND_VBLANK
#include "gb_sound_example.h"
void main() {
    sound_begin("EFFECT RECOVERY");
    Audio_NoiseEffectActive=0; AudioVBlank_Init();
    Audio_SetMasterVolume(3,3);
    AudioVBlank_MusicPlaying=1;
    AudioVBlank_Ch1Envelope=0xC0; AudioVBlank_Ch1LatchedNote=33;
    AudioVBlank_Ch3LatchedNote=33;
    // Value 1 represents a suppressed BGM event and survives a release request.
    AudioVBlank_RestoreCh1Pending=1;
    AudioVBlank_RequestRestoreCh1();
    sound_result[0]=AudioVBlank_RestoreCh1Pending;
    AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
    sound_wait(30);
    // Without a pending event, RequestRestore creates release-only value 2.
    AudioVBlank_RequestRestoreCh1();
    sound_result[1]=AudioVBlank_RestoreCh1Pending;
    AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
    sound_wait(30);
    AudioVBlank_RestoreCh3Pending=1;
    AudioVBlank_RequestRestoreCh3();
    sound_result[2]=AudioVBlank_RestoreCh3Pending;
    AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
    sound_wait(30);
    AudioVBlank_RequestRestoreCh3();
    sound_result[3]=AudioVBlank_RestoreCh3Pending;
    AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
    sound_wait(30);
    AudioVBlank_Stop();
    sound_end();
}

예상 결과

펄스 복원, 무음, 파형 복원, 무음을 각각 30프레임씩 들을 수 있습니다. 해제 요청은 대기값 1을 보존하며, 대기 이벤트가 없을 때 요청하면 해제 전용값 2가 됩니다. 여기서는 IRQ를 끄고 호출자가 채널 사용권을 직접 관리합니다.

AudioVBlank_RequestRestoreCh3: DMG
DMG
AudioVBlank_RequestRestoreCh3: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_recovery.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-recovery.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:132

선언 주석 원문
Request a deferred wave-channel release only if no recovery is pending.
Preserve value 1, which records a new music event suppressed by the effect.

kitaqgb/lib/audio_vblank.c:916

c
void AudioVBlank_RequestRestoreCh3()
{
    if (AudioVBlank_RestoreCh3Pending == 0)
        AudioVBlank_RestoreCh3Pending = 2;
}
AudioVBlank_RestoreCh1

효과가 빌린 펄스 채널(CH1 또는 CH2)에 저장된 음악 음을 복원하거나 무음으로 해제합니다.

사용 형식

c
void AudioVBlank_RestoreCh1();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

복원 함수를 직접 호출할 때는 효과가 채널을 해제했는지 호출자가 확인하고 이후 대기 플래그를 지워야 합니다. 요청 함수만으로는 사운드 레지스터를 쓰지 않습니다.

사용 예

c
// Exercise the recovery API with IRQ disabled and explicit effect ownership.
#define SOUND_VBLANK
#include "gb_sound_example.h"
void main() {
    sound_begin("EFFECT RECOVERY");
    Audio_NoiseEffectActive=0; AudioVBlank_Init();
    Audio_SetMasterVolume(3,3);
    AudioVBlank_MusicPlaying=1;
    AudioVBlank_Ch1Envelope=0xC0; AudioVBlank_Ch1LatchedNote=33;
    AudioVBlank_Ch3LatchedNote=33;
    // Value 1 represents a suppressed BGM event and survives a release request.
    AudioVBlank_RestoreCh1Pending=1;
    AudioVBlank_RequestRestoreCh1();
    sound_result[0]=AudioVBlank_RestoreCh1Pending;
    AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
    sound_wait(30);
    // Without a pending event, RequestRestore creates release-only value 2.
    AudioVBlank_RequestRestoreCh1();
    sound_result[1]=AudioVBlank_RestoreCh1Pending;
    AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
    sound_wait(30);
    AudioVBlank_RestoreCh3Pending=1;
    AudioVBlank_RequestRestoreCh3();
    sound_result[2]=AudioVBlank_RestoreCh3Pending;
    AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
    sound_wait(30);
    AudioVBlank_RequestRestoreCh3();
    sound_result[3]=AudioVBlank_RestoreCh3Pending;
    AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
    sound_wait(30);
    AudioVBlank_Stop();
    sound_end();
}

예상 결과

펄스 복원, 무음, 파형 복원, 무음을 각각 30프레임씩 들을 수 있습니다. 해제 요청은 대기값 1을 보존하며, 대기 이벤트가 없을 때 요청하면 해제 전용값 2가 됩니다. 여기서는 IRQ를 끄고 호출자가 채널 사용권을 직접 관리합니다.

AudioVBlank_RestoreCh1: DMG
DMG
AudioVBlank_RestoreCh1: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_recovery.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-recovery.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:122

선언 주석 원문
Recover the borrowed pulse channel (CH1 or CH2) from its latched music event.
Pending value 2, disabled music, or a non-note latch silences it instead.
The caller must first establish that the effect has released the channel.

kitaqgb/lib/audio_vblank.c:769

c
void AudioVBlank_RestoreCh1()
{
    __asm {
        LD_A_MEM Audio_EffectUsesCh2
        OR_A
        JR_NZ audiovb_restore_ch2
        LD_A_MEM AudioVBlank_RestoreCh1Pending
        CP_IMM 2
        JR_Z audiovb_restore_ch1_off
        LD_A_MEM AudioVBlank_MusicPlaying
        OR_A
        JR_Z audiovb_restore_ch1_off
        LD_A_MEM AudioVBlank_MusicEnabled
        OR_A
        JR_Z audiovb_restore_ch1_off
        LD_A_MEM Audio_MusicEnabled
        OR_A
        JR_Z audiovb_restore_ch1_off
        LD_A_MEM AudioVBlank_Ch1LatchedNote
        CP_IMM 0x44
        JR_NC audiovb_restore_ch1_off
        LD_C_A
        LD_A_MEM AudioVBlank_Ch1Sweep
        LDH_MEM_A 0x10
        LD_A_MEM AudioVBlank_Ch1Duty
        LDH_MEM_A 0x11
        LD_A_MEM AudioVBlank_Ch1Envelope
        LDH_MEM_A 0x12
        LD_A_C
        LD_E_A
        LD_D_IMM 0
        LD_HL_IMM AudioVBlank_FreqLo
        ADD_HL_DE
        LD_A_HL
        LDH_MEM_A 0x13
        LD_HL_IMM AudioVBlank_FreqHi
        ADD_HL_DE
        LD_A_HL
        OR_IMM 0x80
        LDH_MEM_A 0x14
        JR audiovb_restore_ch1_done
audiovb_restore_ch1_off:
        XOR_A
        LDH_MEM_A 0x12
audiovb_restore_ch1_done:
        JR audiovb_restore_square_done

audiovb_restore_ch2:
        LD_A_MEM AudioVBlank_RestoreCh1Pending
        CP_IMM 2
        JR_Z audiovb_restore_ch2_off
        LD_A_MEM AudioVBlank_MusicPlaying
        OR_A
        JR_Z audiovb_restore_ch2_off
        LD_A_MEM AudioVBlank_MusicEnabled
        OR_A
        JR_Z audiovb_restore_ch2_off
        LD_A_MEM Audio_MusicEnabled
        OR_A
        JR_Z audiovb_restore_ch2_off
        LD_A_MEM AudioVBlank_Ch2LatchedNote
        CP_IMM 0x44
        JR_NC audiovb_restore_ch2_off
        LD_C_A
        LD_A_MEM AudioVBlank_Ch2Duty
        LDH_MEM_A 0x16
        LD_A_MEM AudioVBlank_Ch2Envelope
        LDH_MEM_A 0x17
        LD_A_C
        LD_E_A
        LD_D_IMM 0
        LD_HL_IMM AudioVBlank_FreqLo
        ADD_HL_DE
        LD_A_HL
        LDH_MEM_A 0x18
        LD_HL_IMM AudioVBlank_FreqHi
        ADD_HL_DE
        LD_A_HL
        OR_IMM 0x80
        LDH_MEM_A 0x19
        JR audiovb_restore_square_done
audiovb_restore_ch2_off:
        XOR_A
        LDH_MEM_A 0x17
audiovb_restore_square_done:
    }
}
AudioVBlank_RestoreCh3

효과 해제 후 CH3의 저장된 음을 복원하거나 DAC를 끕니다.

사용 형식

c
void AudioVBlank_RestoreCh3();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

복원 함수를 직접 호출할 때는 효과가 채널을 해제했는지 호출자가 확인하고 이후 대기 플래그를 지워야 합니다. 요청 함수만으로는 사운드 레지스터를 쓰지 않습니다.

사용 예

c
// Exercise the recovery API with IRQ disabled and explicit effect ownership.
#define SOUND_VBLANK
#include "gb_sound_example.h"
void main() {
    sound_begin("EFFECT RECOVERY");
    Audio_NoiseEffectActive=0; AudioVBlank_Init();
    Audio_SetMasterVolume(3,3);
    AudioVBlank_MusicPlaying=1;
    AudioVBlank_Ch1Envelope=0xC0; AudioVBlank_Ch1LatchedNote=33;
    AudioVBlank_Ch3LatchedNote=33;
    // Value 1 represents a suppressed BGM event and survives a release request.
    AudioVBlank_RestoreCh1Pending=1;
    AudioVBlank_RequestRestoreCh1();
    sound_result[0]=AudioVBlank_RestoreCh1Pending;
    AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
    sound_wait(30);
    // Without a pending event, RequestRestore creates release-only value 2.
    AudioVBlank_RequestRestoreCh1();
    sound_result[1]=AudioVBlank_RestoreCh1Pending;
    AudioVBlank_RestoreCh1(); AudioVBlank_RestoreCh1Pending=0;
    sound_wait(30);
    AudioVBlank_RestoreCh3Pending=1;
    AudioVBlank_RequestRestoreCh3();
    sound_result[2]=AudioVBlank_RestoreCh3Pending;
    AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
    sound_wait(30);
    AudioVBlank_RequestRestoreCh3();
    sound_result[3]=AudioVBlank_RestoreCh3Pending;
    AudioVBlank_RestoreCh3(); AudioVBlank_RestoreCh3Pending=0;
    sound_wait(30);
    AudioVBlank_Stop();
    sound_end();
}

예상 결과

펄스 복원, 무음, 파형 복원, 무음을 각각 30프레임씩 들을 수 있습니다. 해제 요청은 대기값 1을 보존하며, 대기 이벤트가 없을 때 요청하면 해제 전용값 2가 됩니다. 여기서는 IRQ를 끄고 호출자가 채널 사용권을 직접 관리합니다.

AudioVBlank_RestoreCh3: DMG
DMG
AudioVBlank_RestoreCh3: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_recovery.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-recovery.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:126

선언 주석 원문
Recover a latched wave-channel music event after effect release, or disable
the DAC for a release-only request, disabled music, or a non-note latch.
The caller owns effect arbitration and clearing the pending flag.

kitaqgb/lib/audio_vblank.c:860

c
void AudioVBlank_RestoreCh3()
{
    __asm {
        LD_A_MEM AudioVBlank_RestoreCh3Pending
        CP_IMM 2
        JR_Z audiovb_restore_ch3_off
        LD_A_MEM AudioVBlank_MusicPlaying
        OR_A
        JR_Z audiovb_restore_ch3_off
        LD_A_MEM AudioVBlank_MusicEnabled
        OR_A
        JR_Z audiovb_restore_ch3_off
        LD_A_MEM Audio_MusicEnabled
        OR_A
        JR_Z audiovb_restore_ch3_off
        LD_A_MEM AudioVBlank_Ch3LatchedNote
        CP_IMM 0x44
        JR_NC audiovb_restore_ch3_off
        LD_C_A
        LD_A_IMM 0x80
        LDH_MEM_A 0x1A
        XOR_A
        LDH_MEM_A 0x1B
        LD_A_MEM AudioVBlank_Ch3Level
        LDH_MEM_A 0x1C
        LD_A_C
        LD_E_A
        LD_D_IMM 0
        LD_HL_IMM AudioVBlank_FreqLo
        ADD_HL_DE
        LD_A_HL
        LDH_MEM_A 0x1D
        LD_HL_IMM AudioVBlank_FreqHi
        ADD_HL_DE
        LD_A_HL
        OR_IMM 0x80
        LDH_MEM_A 0x1E
        JR audiovb_restore_ch3_done
audiovb_restore_ch3_off:
        XOR_A
        LDH_MEM_A 0x1A
audiovb_restore_ch3_done:
    }
}
AudioVBlank_SetEnabled

VBlank 음악 처리를 허용하거나 차단하며 비활성화 시 복원 요청을 지웁니다. 현재 소리와 IRQ는 바뀌지 않습니다.

사용 형식

c
void __stackcall AudioVBlank_SetEnabled(u8 on);

매개변수

on

0은 비활성화, 0 이외는 활성화입니다. 무음과 갱신 차단의 차이는 해당 함수 설명을 확인하세요.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

사용 예

c
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
    u8 before;
    sound_begin("VBLANK MUSIC GATES");
    Audio_NoiseEffectActive=0;
    AudioVBlank_Init();
    sound_result[0]=AudioVBlank_MusicPlaying;
    AudioVBlank_Ch1Envelope=0xC0;
    Audio_SetMasterVolume(3,3);
    hook_count=0; AudioVBlank_FrameHook=frame_hook;
    AudioVBlank_SetMusic(irq_song);
    AudioVBlank_Play();
    AudioVBlank_EnableIrq();
    sound_wait(45);
    // Disable music processing while the hook and current note remain active.
    __asm { DI }
    AudioVBlank_SetEnabled(0); before=hook_count;
    __asm { EI }
    sound_wait(30);
    sound_result[1]=(u8)(hook_count!=before);
    __asm { DI }
    AudioVBlank_Stop();
    __asm { EI }
    sound_wait(30);
    __asm { DI }
    AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
    __asm { EI }
    sound_wait(45);
    AudioVBlank_DisableIrq();
    before=hook_count;
    sound_wait(30);
    sound_result[2]=(u8)(hook_count==before);
    sound_result[3]=(u8)(AudioVBlank_IE&1);
    AudioVBlank_Stop(); sound_wait(30);
    sound_end();
}

예상 결과

ISR이 두 음으로 된 곡을 재생합니다. 음악 갱신 차단은 현재 소리를 유지하고 Stop은 무음으로 만듭니다. 재시작 후 IRQ 차단도 소리를 유지하므로 서로 비교하세요. RAM은 음악 비활성화 중 훅이 실행되고 IRQ 비활성화 때 멈추는 것을 확인합니다.

AudioVBlank_SetEnabled: DMG
DMG
AudioVBlank_SetEnabled: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:113

선언 주석 원문
Gate music processing and clear pending CH1/CH3 recovery on disable.
No audio register is written here: disabling does not itself silence a note
already playing or disable the VBlank interrupt.

kitaqgb/lib/audio_vblank_control.inc:109

c
void __stackcall AudioVBlank_SetEnabled(u8 on)
{
    if (on != 0) AudioVBlank_MusicEnabled = 1;
    else {
        AudioVBlank_MusicEnabled = 0;
        // Do not carry a stale SFX-recovery request into a later song.
        AudioVBlank_RestoreCh1Pending = 0;
        AudioVBlank_RestoreCh3Pending = 0;
    }
}
AudioVBlank_SetMusic

직접 읽는 곡을 선택하고 커서를 초기화합니다. 재생 플래그는 바꾸지 않습니다.

사용 형식

c
void __stackcall AudioVBlank_SetMusic(u8 *song);

매개변수

song

곡 시작 주소입니다. 드라이버는 배열을 빌려 사용하므로 재생 내내 읽을 수 있어야 합니다.

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

사용 예

c
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
    u8 before;
    sound_begin("VBLANK MUSIC GATES");
    Audio_NoiseEffectActive=0;
    AudioVBlank_Init();
    sound_result[0]=AudioVBlank_MusicPlaying;
    AudioVBlank_Ch1Envelope=0xC0;
    Audio_SetMasterVolume(3,3);
    hook_count=0; AudioVBlank_FrameHook=frame_hook;
    AudioVBlank_SetMusic(irq_song);
    AudioVBlank_Play();
    AudioVBlank_EnableIrq();
    sound_wait(45);
    // Disable music processing while the hook and current note remain active.
    __asm { DI }
    AudioVBlank_SetEnabled(0); before=hook_count;
    __asm { EI }
    sound_wait(30);
    sound_result[1]=(u8)(hook_count!=before);
    __asm { DI }
    AudioVBlank_Stop();
    __asm { EI }
    sound_wait(30);
    __asm { DI }
    AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
    __asm { EI }
    sound_wait(45);
    AudioVBlank_DisableIrq();
    before=hook_count;
    sound_wait(30);
    sound_result[2]=(u8)(hook_count==before);
    sound_result[3]=(u8)(AudioVBlank_IE&1);
    AudioVBlank_Stop(); sound_wait(30);
    sound_end();
}

예상 결과

ISR이 두 음으로 된 곡을 재생합니다. 음악 갱신 차단은 현재 소리를 유지하고 Stop은 무음으로 만듭니다. 재시작 후 IRQ 차단도 소리를 유지하므로 서로 비교하세요. RAM은 음악 비활성화 중 훅이 실행되고 IRQ 비활성화 때 멈추는 것을 확인합니다.

AudioVBlank_SetMusic: DMG
DMG
AudioVBlank_SetMusic: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:100

선언 주석 원문
Select a directly addressed song and reset its cursors, leaving the playing
flag unchanged. Song storage must remain accessible to the fixed-bank ISR;
coordinate this multi-field update with interrupt execution.

kitaqgb/lib/audio_vblank_control.inc:46

c
void __stackcall AudioVBlank_SetMusic(u8 *song)
{
    AudioVBlank_MusicStart = song;
    AudioVBlank_MusicPointer = song;
    AudioVBlank_MusicLoopPoint = song;
    AudioVBlank_MusicDelay = 0;
    AudioVBlank_Step = 0;
    AudioVBlank_QueueMode = 0;
}
AudioVBlank_Stop

재생·delay·복원 상태를 지우고 펄스·노이즈·파형 채널을 즉시 무음으로 만듭니다. IRQ는 활성 상태를 유지합니다.

사용 형식

c
void AudioVBlank_Stop();

반환값

반환값은 없습니다. 사운드 레지스터나 드라이버 상태를 변경합니다.

사용 조건과 제한

audio_vblank.c는 __kq_vblank_vector를 구현하므로 다른 VBlank 벡터를 함께 설치하지 마세요. 샘플은 Audio_NoiseEffectActive를 정의하고 일반 음악 디코더를 제외하며 Audio_Update는 효과와 페이드에만 사용합니다. 곡 포인터나 공유 상태를 바꿀 때는 인터럽트를 차단하세요.

직접 읽는 곡 데이터는 고정 ROM 등 ISR에서 항상 보이는 영역에 두세요. 레코드는 delay, CH1, CH2, CH3, CH4의 5바이트입니다. 음 필드의 0xFF는 현재 소리를 유지하고 0xFD는 멈춥니다. delay의 0xFF는 재생 종료, 0xFE는 반복입니다. 이는 레코드 배치이며 채널 ID 번호가 아닙니다. WRAM 큐 재생은 별도 모드이며 AudioVBlank_QueueRefill로 완전한 5바이트 레코드를 제출합니다.

사용 예

c
// Direct fixed-bank music with an actual VBlank ISR and a counting frame hook.
#define SOUND_VBLANK
#include "gb_sound_example.h"
__wram u8 hook_count;
__prg_rom u8 irq_song[]={30,33,0xFF,0xFF,0xFF,30,40,0xFF,0xFF,0xFF,0xFE};
void frame_hook() { hook_count++; }
void main() {
    u8 before;
    sound_begin("VBLANK MUSIC GATES");
    Audio_NoiseEffectActive=0;
    AudioVBlank_Init();
    sound_result[0]=AudioVBlank_MusicPlaying;
    AudioVBlank_Ch1Envelope=0xC0;
    Audio_SetMasterVolume(3,3);
    hook_count=0; AudioVBlank_FrameHook=frame_hook;
    AudioVBlank_SetMusic(irq_song);
    AudioVBlank_Play();
    AudioVBlank_EnableIrq();
    sound_wait(45);
    // Disable music processing while the hook and current note remain active.
    __asm { DI }
    AudioVBlank_SetEnabled(0); before=hook_count;
    __asm { EI }
    sound_wait(30);
    sound_result[1]=(u8)(hook_count!=before);
    __asm { DI }
    AudioVBlank_Stop();
    __asm { EI }
    sound_wait(30);
    __asm { DI }
    AudioVBlank_SetEnabled(1); AudioVBlank_PlayMusic(irq_song);
    __asm { EI }
    sound_wait(45);
    AudioVBlank_DisableIrq();
    before=hook_count;
    sound_wait(30);
    sound_result[2]=(u8)(hook_count==before);
    sound_result[3]=(u8)(AudioVBlank_IE&1);
    AudioVBlank_Stop(); sound_wait(30);
    sound_end();
}

예상 결과

ISR이 두 음으로 된 곡을 재생합니다. 음악 갱신 차단은 현재 소리를 유지하고 Stop은 무음으로 만듭니다. 재시작 후 IRQ 차단도 소리를 유지하므로 서로 비교하세요. RAM은 음악 비활성화 중 훅이 실행되고 IRQ 비활성화 때 멈추는 것을 확인합니다.

AudioVBlank_Stop: DMG
DMG
AudioVBlank_Stop: CGB
CGB
DMG — 녹음된 오디오
CGB — 녹음된 오디오

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sound_vblank.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\gb-vblank.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/audio_vblank.h:109

선언 주석 원문
Stop software playback and silence pulse/noise envelopes and the wave DAC.
Song pointers and the IRQ enable remain unchanged; the routine writes the
physical channels directly, so coordinate ownership with sound effects.

kitaqgb/lib/audio_vblank_control.inc:82

c
void AudioVBlank_Stop()
{
    AudioVBlank_MusicPlaying = 0;
    AudioVBlank_MusicDelay = 0;
    AudioVBlank_Step = 0;
    AudioVBlank_Ch2Note = AUDIO_VBLANK_REST;
    AudioVBlank_Ch1Note = AUDIO_VBLANK_REST;
    AudioVBlank_Ch3Note = AUDIO_VBLANK_REST;
    AudioVBlank_Ch2LatchedNote = AUDIO_VBLANK_STOP;
    AudioVBlank_Ch1LatchedNote = AUDIO_VBLANK_STOP;
    AudioVBlank_Ch3LatchedNote = AUDIO_VBLANK_STOP;
    AudioVBlank_RestoreCh1Pending = 0;
    AudioVBlank_RestoreCh3Pending = 0;
    AudioVBlank_Ch4Param = AUDIO_VBLANK_REST;
    __asm {
        XOR_A
        LDH_MEM_A 0x12
        LDH_MEM_A 0x17
        LDH_MEM_A 0x1C
        LDH_MEM_A 0x1A
        LDH_MEM_A 0x21
    }
}

bank.h — 뱅크를 고려한 코드·데이터 접근

ROM 뱅크는 카트리지 저장 공간을 CPU 주소 공간에 매핑하는 단위입니다. 서로 다른 뱅크가 같은 CPU 주소에 나타날 수 있으므로 16비트 포인터만으로는 뱅크가 있는 데이터를 식별할 수 없습니다. BankPtr은 1바이트 뱅크 번호와 2바이트 포인터를 담은 패딩 없는 3바이트 설명자입니다. farptr_make로 만들고 farptr_read8, farptr_read16 또는 farptr_read로 데이터에 접근합니다.

GB 예제는 MBC5 카트리지를 사용합니다. 고정 뱅크 0의 코드는 $0000–$3FFF에서 계속 접근할 수 있고, $4000–$7FFF에는 뱅크 1·2·3을 선택합니다. bank_switch와 호출 후 실행할 코드는 고정 ROM에 배치하세요. 라이브러리의 뱅크 번호를 조회하기 전에 bank_switch로 기록을 초기화하세요. GB의 far_call은 콜백 포인터를 받으며, __farcall에는 함수 이름을 전달합니다.

bank_get_current

bank_switch가 마지막으로 기록한 뱅크 번호를 반환합니다. 카트리지 레지스터가 아니라 소프트웨어의 기록을 읽습니다.

사용 형식

c
u8 bank_get_current();

반환값

bank_switch가 마지막으로 저장한 u8 값입니다. 초기화 전에는 0입니다.

사용 조건과 제한

라이브러리 기록은 0으로 시작하며 카트리지의 시작 매핑을 알아내지 않습니다. bank_switch로 초기화하세요. 내장 함수나 매퍼에 대한 직접 쓰기는 이 별도 기록을 갱신하지 않으므로 bank_get_current로 실제 하드웨어 매핑을 검증할 수는 없습니다.

사용 예

c
starting_bank=bank_get_current(); // Last value recorded by bank_switch.
bank_expect(starting_bank==2,1);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

처음 bank_switch(2)는 뱅크 2를 기록하고 선택합니다. 이후 직접 전환으로 뱅크 1을 선택해 home1에서 A1을 읽어도 bank_get_current는 여전히 2입니다. 복귀하면 home2에서 다시 B2를 읽습니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

bank_get_current: DMG
DMG
bank_get_current: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:21

선언 주석 원문
Return the last bank recorded by bank_switch; this does not read cartridge hardware.

kitaqgb/lib/bank.c:15

c
u8 bank_get_current()
{
    return kq_bank_current;
}
bank_switch

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

ROM 뱅크를 선택하고 bank 라이브러리와 컴파일러의 뱅크 상태에 번호를 기록합니다. 원거리 읽기와 호출은 컴파일러의 기록을 사용해 이전 뱅크로 복귀합니다.

사용 형식

c
void bank_switch(u8 bank);

매개변수

bank

부호 없는 8비트 ROM 뱅크 번호입니다. 호출 시에는 함수 배치와 일치해야 하고, 읽기 시에는 원본 매핑을 지정합니다. 대상 카트리지에서 유효한 범위를 사용하세요.

반환값

없음(void).

사용 조건과 제한

지속되는 뱅크 변경으로 실행 중인 코드나 반환 주소가 사라져서는 안 됩니다. 예제처럼 호출 위치, 사용하는 bank_switch 본체, 이후 실행할 코드를 공통·고정 뱅크 0에 두세요.

라이브러리 기록은 0으로 시작하며 카트리지의 시작 매핑을 알아내지 않습니다. bank_switch로 초기화하세요. 내장 함수나 매퍼에 대한 직접 쓰기는 이 별도 기록을 갱신하지 않으므로 bank_get_current로 실제 하드웨어 매핑을 검증할 수는 없습니다.

이 GB 뱅크 API는 8비트 번호를 다루며 MBC5의 아홉 번째 뱅크 비트는 설정하지 않습니다. 뱅크 0 처리 등 카트리지별 규칙도 적용됩니다. 예제는 MBC5 뱅크 1~3을 명시적으로 사용합니다. 상태에 반영되지 않는 매퍼 직접 쓰기와 섞지 마세요.

사용 예

c
bank_switch(2); // Select the payload window and update library bookkeeping.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

처음 bank_switch(2)는 뱅크 2를 기록하고 선택합니다. 이후 직접 전환으로 뱅크 1을 선택해 home1에서 A1을 읽어도 bank_get_current는 여전히 2입니다. 복귀하면 home2에서 다시 B2를 읽습니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

bank_switch: DMG
DMG
bank_switch: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:19

선언 주석 원문
Update both the library bank record and the compiler shadow used by far
reads and calls. Invoke this permanent bank change from fixed-bank code.

kitaqgb/lib/bank.c:8

c
void bank_switch(u8 bank)
{
    kq_bank_current = bank;
    __bankswitch(bank);
}
far_call

뱅크 번호와 콜백 포인터를 __farcall_ptr에 전달합니다. 인수 없는 콜백을 실행하고 호출자의 뱅크를 복원한 뒤 반환하는 라이브러리 함수입니다.

사용 형식

c
void far_call(u8 bank, const void* func);

매개변수

bank

부호 없는 8비트 ROM 뱅크 번호입니다. 호출 시에는 함수 배치와 일치해야 하고, 읽기 시에는 원본 매핑을 지정합니다. 대상 카트리지에서 유효한 범위를 사용하세요.

func

매개변수가 없는 콜백의 유효한 실행 주소입니다. 함수 이름이나 실행 시점 포인터로 지정할 수 있습니다. 널 포인터와 잘못된 뱅크·주소 조합은 실행 중 검사하지 않습니다.

반환값

없음(void).

사용 조건과 제한

이 호출은 사용자 인수를 전달하거나 콜백의 인터럽트 재진입성을 보장하지 않습니다. 콜백 자체의 데이터, 스택, 인터럽트 사용을 올바르게 관리하세요. 뱅크 복귀는 중첩 및 반복 호출로 검사했지만 실제 하드웨어와 임의의 인터럽트 타이밍은 이 예제의 검증 범위가 아닙니다.

이 GB 뱅크 API는 8비트 번호를 다루며 MBC5의 아홉 번째 뱅크 비트는 설정하지 않습니다. 뱅크 0 처리 등 카트리지별 규칙도 적용됩니다. 예제는 MBC5 뱅크 1~3을 명시적으로 사용합니다. 상태에 반영되지 않는 매퍼 직접 쓰기와 섞지 마세요.

사용 예

c
far_call(3,callback); // No arguments; callback reads payload[0] in bank 3.
bank_expect(callback_count==1 && callback_byte==0xD3,15);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램의 이 지점에서 far_call는 callback_count를 1으로 만듭니다. 콜백은 뱅크 3에서 D3을 읽습니다. 이후 home2를 근거리로 읽어 B2인지 검사함으로써 뱅크 2가 매핑된 상태로 복귀했는지 확인합니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

far_call: DMG
DMG
far_call: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:30

선언 주석 원문
Invoke a no-argument callback in its ROM bank, then restore the caller
bank. The pointer must identify executable code; no arguments are forwarded.

kitaqgb/lib/bank.c:40

c
void far_call(u8 bank, const void* func)
{
    __farcall_ptr(bank, func);
}
far_data_read

원거리 메모리 복사 내장 함수를 사용해 지정한 ROM 뱅크에서 호출자가 제공한 RAM으로 len바이트를 복사합니다. 반환 전에 이전 뱅크를 복원합니다.

사용 형식

c
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);

매개변수

bank

부호 없는 8비트 ROM 뱅크 번호입니다. 호출 시에는 함수 배치와 일치해야 하고, 읽기 시에는 원본 매핑을 지정합니다. 대상 카트리지에서 유효한 범위를 사용하세요.

addr

선택한 ROM 뱅크에서 읽을 수 있는 바이트열을 가리키는 근거리 포인터입니다. 포인터 자체에는 뱅크 번호가 없습니다.

dst

쓰기 대상 메모리입니다. 실제 복사량을 모두 담을 공간을 확보하세요. 0바이트 전송을 제외하면 널 포인터나 잘못된 대상 주소를 검사하지 않습니다.

len

바이트 수이며 범위는 0~65535입니다. 0이면 메모리를 복사하지 않지만 뱅크 선택과 복구 과정은 실행합니다.

반환값

없음(void).

사용 조건과 제한

원본 전체가 의도한 ROM 매핑에서 읽히고 대상 전체가 쓰기 가능한 메모리 안에 있어야 합니다. 뱅크 창 경계에서 다음 뱅크로 넘어가거나, memmove처럼 겹치는 범위를 처리하거나, VRAM 쓰기 시점을 제어하지 않습니다. VRAM에는 그래픽 전송 API를 사용하세요.

원거리 읽기와 복사는 동기식이며 컴파일러의 공유 작업 공간을 사용합니다. 처리 중 인터럽트에서 다른 뱅크 전송을 실행해 같은 공간을 덮어쓰지 마세요. GB 복사 보조 코드는 복귀 뱅크에도 공유 HRAM 슬롯 하나를 씁니다. 예제는 경쟁하는 전송 인터럽트 없이 고정 코드에서 실행합니다.

이 GB 뱅크 API는 8비트 번호를 다루며 MBC5의 아홉 번째 뱅크 비트는 설정하지 않습니다. 뱅크 0 처리 등 카트리지별 규칙도 적용됩니다. 예제는 MBC5 뱅크 1~3을 명시적으로 사용합니다. 상태에 반영되지 않는 매퍼 직접 쓰기와 섞지 마세요.

사용 예

c
far_data_read(3,payload,buffer,4); // Copy into four writable RAM bytes.
bank_expect(buffer[0]==0xD3 && buffer[1]==0x7A && buffer[2]==0x5C && buffer[3]==0x96,7);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 코드 조각은 far_data_read로 4바이트를 복사하고 버퍼를 D3 7A 5C 96와 비교합니다. 호출자의 원본 설명자나 포인터는 유지됩니다. 완성 프로그램은 길이 0 복사와 뱅크 복원도 별도로 확인합니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

far_data_read: DMG
DMG
far_data_read: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:27

선언 주석 원문
Copy len bytes from banked ROM into caller-owned writable storage.

kitaqgb/lib/bank.c:33

c
void far_data_read(u8 bank, const void* addr, void* dst, u16 len)
{
    __farmemcpy(dst, bank, addr, len);
}
far_data_read16

__farpeek16으로 연속된 두 바이트를 읽어 리틀 엔디언 워드로 반환합니다. 첫 번째 바이트가 하위 8비트입니다.

사용 형식

c
u16 far_data_read16(u8 bank, const void* addr);

매개변수

bank

부호 없는 8비트 ROM 뱅크 번호입니다. 호출 시에는 함수 배치와 일치해야 하고, 읽기 시에는 원본 매핑을 지정합니다. 대상 카트리지에서 유효한 범위를 사용하세요.

addr

선택한 ROM 뱅크에서 읽을 수 있는 바이트열을 가리키는 근거리 포인터입니다. 포인터 자체에는 뱅크 번호가 없습니다.

반환값

읽은 리틀 엔디언 워드를 u16(0~65535)으로 반환합니다.

사용 조건과 제한

선택한 CPU 매핑에서 바이트 또는 워드 전체를 읽을 수 있어야 합니다. 포인터 검사, 주소 잘라내기, 창 경계에서 다음 ROM 뱅크로의 자동 전환은 수행하지 않습니다. 워드 읽기에는 연속된 유효한 두 바이트가 필요합니다.

원거리 읽기와 복사는 동기식이며 컴파일러의 공유 작업 공간을 사용합니다. 처리 중 인터럽트에서 다른 뱅크 전송을 실행해 같은 공간을 덮어쓰지 마세요. GB 복사 보조 코드는 복귀 뱅크에도 공유 HRAM 슬롯 하나를 씁니다. 예제는 경쟁하는 전송 인터럽트 없이 고정 코드에서 실행합니다.

이 GB 뱅크 API는 8비트 번호를 다루며 MBC5의 아홉 번째 뱅크 비트는 설정하지 않습니다. 뱅크 0 처리 등 카트리지별 규칙도 적용됩니다. 예제는 MBC5 뱅크 1~3을 명시적으로 사용합니다. 상태에 반영되지 않는 매퍼 직접 쓰기와 섞지 마세요.

사용 예

c
word_value=far_data_read16(3,payload+1); // Little-endian 7A 5C -> 0x5C7A.
bank_expect(word_value==0x5C7A,6);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 코드 조각은 far_data_read16로 뱅크 3의 payload+1를 읽고 5C7A를 확인합니다. 완성 프로그램은 home2의 근거리 읽기로 뱅크 2 매핑이 복원되었는지도 확인합니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

far_data_read16: DMG
DMG
far_data_read16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:25

선언 주석 원문
Read a 16-bit value from the supplied bank and address through the far-read intrinsic.

kitaqgb/lib/bank.c:27

c
u16 far_data_read16(u8 bank, const void* addr)
{
    return __farpeek16(bank, addr);
}
far_data_read8

지정한 ROM 뱅크와 주소에서 __farpeek8로 한 바이트를 읽고, 이전 뱅크를 복원한 뒤 값을 반환합니다.

사용 형식

c
u8 far_data_read8(u8 bank, const void* addr);

매개변수

bank

부호 없는 8비트 ROM 뱅크 번호입니다. 호출 시에는 함수 배치와 일치해야 하고, 읽기 시에는 원본 매핑을 지정합니다. 대상 카트리지에서 유효한 범위를 사용하세요.

addr

선택한 ROM 뱅크에서 읽을 수 있는 바이트열을 가리키는 근거리 포인터입니다. 포인터 자체에는 뱅크 번호가 없습니다.

반환값

읽은 바이트를 u8(0~255)로 반환합니다.

사용 조건과 제한

선택한 CPU 매핑에서 바이트 또는 워드 전체를 읽을 수 있어야 합니다. 포인터 검사, 주소 잘라내기, 창 경계에서 다음 ROM 뱅크로의 자동 전환은 수행하지 않습니다. 워드 읽기에는 연속된 유효한 두 바이트가 필요합니다.

원거리 읽기와 복사는 동기식이며 컴파일러의 공유 작업 공간을 사용합니다. 처리 중 인터럽트에서 다른 뱅크 전송을 실행해 같은 공간을 덮어쓰지 마세요. GB 복사 보조 코드는 복귀 뱅크에도 공유 HRAM 슬롯 하나를 씁니다. 예제는 경쟁하는 전송 인터럽트 없이 고정 코드에서 실행합니다.

이 GB 뱅크 API는 8비트 번호를 다루며 MBC5의 아홉 번째 뱅크 비트는 설정하지 않습니다. 뱅크 0 처리 등 카트리지별 규칙도 적용됩니다. 예제는 MBC5 뱅크 1~3을 명시적으로 사용합니다. 상태에 반영되지 않는 매퍼 직접 쓰기와 섞지 마세요.

사용 예

c
byte_value=far_data_read8(3,payload); // One byte: 0xD3.
bank_expect(byte_value==0xD3,5);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 코드 조각은 far_data_read8로 뱅크 3의 payload를 읽고 D3를 확인합니다. 완성 프로그램은 home2의 근거리 읽기로 뱅크 2 매핑이 복원되었는지도 확인합니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

far_data_read8: DMG
DMG
far_data_read8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:23

선언 주석 원문
Read one byte through the compiler intrinsic that accepts an explicit ROM bank.

kitaqgb/lib/bank.c:21

c
u8 far_data_read8(u8 bank, const void* addr)
{
    return __farpeek8(bank, addr);
}
farptr_make

뱅크 번호 한 바이트와 CPU 주소 공간의 포인터를 호출자의 BankPtr에 저장합니다. 설명자를 만들 뿐, 뱅크를 전환하거나 가리키는 데이터를 읽지 않습니다.

사용 형식

c
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);

매개변수

out

3바이트 BankPtr 하나를 저장할 수 있는 쓰기 가능한 영역의 포인터입니다. out이 널이면 아무것도 쓰지 않습니다.

bank

부호 없는 8비트 ROM 뱅크 번호입니다. 호출 시에는 함수 배치와 일치해야 하고, 읽기 시에는 원본 매핑을 지정합니다. 대상 카트리지에서 유효한 범위를 사용하세요.

ptr

설명자에 저장할 CPU 주소 공간의 16비트 주소입니다. 그대로 저장하며 선택한 뱅크에서 유효한 주소인지 검사하지 않습니다.

반환값

없음(void).

사용 예

c
farptr_make(&pointer,3,payload+1); // Store a bank and address; do not read ROM.
bank_expect(pointer.bank==3 && pointer.ptr==payload+1,8);
farptr_make(0,1,home1); // A null destination is ignored.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

설명자를 뱅크 3과 payload+1로 설정합니다. 읽기 함수들은 7A, 5C7A, 세 바이트 7A 5C 96을 얻습니다. 출력 포인터가 널인 호출은 상태를 바꾸지 않아야 합니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

farptr_make: DMG
DMG
farptr_make: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:32

선언 주석 원문
Store a bank/address pair without accessing ROM; a null output pointer is ignored.

kitaqgb/lib/bank.c:46

c
void farptr_make(BankPtr* out, u8 bank, const u8* ptr)
{
    if (out == 0) return;
    out->bank = bank;
    out->ptr = ptr;
}
farptr_read

BankPtr이 가리키는 곳에서 쓰기 가능한 RAM으로 len바이트를 복사합니다. 설명자는 값으로 전달되므로 호출자의 포인터는 계속 원본 시작점을 가리킵니다.

사용 형식

c
void farptr_read(BankPtr ptr, void* dst, u16 len);

매개변수

ptr

bank와 ptr을 담은 BankPtr 값입니다. 주소가 아니라 설명자 자체를 전달합니다. 호출자의 설명자는 변경되지 않습니다.

dst

쓰기 대상 메모리입니다. 실제 복사량을 모두 담을 공간을 확보하세요. 0바이트 전송을 제외하면 널 포인터나 잘못된 대상 주소를 검사하지 않습니다.

len

바이트 수이며 범위는 0~65535입니다. 0이면 메모리를 복사하지 않지만 뱅크 선택과 복구 과정은 실행합니다.

반환값

없음(void).

사용 조건과 제한

원본 전체가 의도한 ROM 매핑에서 읽히고 대상 전체가 쓰기 가능한 메모리 안에 있어야 합니다. 뱅크 창 경계에서 다음 뱅크로 넘어가거나, memmove처럼 겹치는 범위를 처리하거나, VRAM 쓰기 시점을 제어하지 않습니다. VRAM에는 그래픽 전송 API를 사용하세요.

원거리 읽기와 복사는 동기식이며 컴파일러의 공유 작업 공간을 사용합니다. 처리 중 인터럽트에서 다른 뱅크 전송을 실행해 같은 공간을 덮어쓰지 마세요. GB 복사 보조 코드는 복귀 뱅크에도 공유 HRAM 슬롯 하나를 씁니다. 예제는 경쟁하는 전송 인터럽트 없이 고정 코드에서 실행합니다.

이 GB 뱅크 API는 8비트 번호를 다루며 MBC5의 아홉 번째 뱅크 비트는 설정하지 않습니다. 뱅크 0 처리 등 카트리지별 규칙도 적용됩니다. 예제는 MBC5 뱅크 1~3을 명시적으로 사용합니다. 상태에 반영되지 않는 매퍼 직접 쓰기와 섞지 마세요.

사용 예

c
farptr_read(pointer,buffer,3);
bank_expect(buffer[0]==0x7A && buffer[1]==0x5C && buffer[2]==0x96,11);
bank_expect(pointer.bank==3 && pointer.ptr==payload+1,23);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 코드 조각은 farptr_read로 3바이트를 복사하고 버퍼를 7A 5C 96와 비교합니다. 호출자의 원본 설명자나 포인터는 유지됩니다. 완성 프로그램은 길이 0 복사와 뱅크 복원도 별도로 확인합니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

farptr_read: DMG
DMG
farptr_read: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:38

선언 주석 원문
Copy len bytes from a bank-qualified pointer; dst must have room for the full copy.

kitaqgb/lib/bank.c:66

c
void farptr_read(BankPtr ptr, void* dst, u16 len)
{
    __farmemcpy(dst, ptr.bank, ptr.ptr, len);
}
farptr_read16

BankPtr에 저장된 뱅크와 주소에서 리틀 엔디언 워드를 읽습니다. 설명자는 값으로 전달되며 포인터는 증가하지 않습니다.

사용 형식

c
u16 farptr_read16(BankPtr ptr);

매개변수

ptr

bank와 ptr을 담은 BankPtr 값입니다. 주소가 아니라 설명자 자체를 전달합니다. 호출자의 설명자는 변경되지 않습니다.

반환값

읽은 리틀 엔디언 워드를 u16(0~65535)으로 반환합니다.

사용 조건과 제한

선택한 CPU 매핑에서 바이트 또는 워드 전체를 읽을 수 있어야 합니다. 포인터 검사, 주소 잘라내기, 창 경계에서 다음 ROM 뱅크로의 자동 전환은 수행하지 않습니다. 워드 읽기에는 연속된 유효한 두 바이트가 필요합니다.

원거리 읽기와 복사는 동기식이며 컴파일러의 공유 작업 공간을 사용합니다. 처리 중 인터럽트에서 다른 뱅크 전송을 실행해 같은 공간을 덮어쓰지 마세요. GB 복사 보조 코드는 복귀 뱅크에도 공유 HRAM 슬롯 하나를 씁니다. 예제는 경쟁하는 전송 인터럽트 없이 고정 코드에서 실행합니다.

이 GB 뱅크 API는 8비트 번호를 다루며 MBC5의 아홉 번째 뱅크 비트는 설정하지 않습니다. 뱅크 0 처리 등 카트리지별 규칙도 적용됩니다. 예제는 MBC5 뱅크 1~3을 명시적으로 사용합니다. 상태에 반영되지 않는 매퍼 직접 쓰기와 섞지 마세요.

사용 예

c
bank_expect(farptr_read16(pointer)==0x5C7A,10);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 코드 조각은 farptr_read16로 뱅크 3의 pointer.ptr를 읽고 5C7A를 확인합니다. 완성 프로그램은 home2의 근거리 읽기로 뱅크 2 매핑이 복원되었는지도 확인합니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

farptr_read16: DMG
DMG
farptr_read16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:36

선언 주석 원문
Read a 16-bit value using both components of the bank-qualified pointer.

kitaqgb/lib/bank.c:60

c
u16 farptr_read16(BankPtr ptr)
{
    return __farpeek16(ptr.bank, ptr.ptr);
}
farptr_read8

값으로 전달된 BankPtr의 두 필드를 사용해 한 바이트를 읽습니다. 일반 근거리 포인터에 없는 뱅크 번호를 설명자에서 가져옵니다.

사용 형식

c
u8 farptr_read8(BankPtr ptr);

매개변수

ptr

bank와 ptr을 담은 BankPtr 값입니다. 주소가 아니라 설명자 자체를 전달합니다. 호출자의 설명자는 변경되지 않습니다.

반환값

읽은 바이트를 u8(0~255)로 반환합니다.

사용 조건과 제한

선택한 CPU 매핑에서 바이트 또는 워드 전체를 읽을 수 있어야 합니다. 포인터 검사, 주소 잘라내기, 창 경계에서 다음 ROM 뱅크로의 자동 전환은 수행하지 않습니다. 워드 읽기에는 연속된 유효한 두 바이트가 필요합니다.

원거리 읽기와 복사는 동기식이며 컴파일러의 공유 작업 공간을 사용합니다. 처리 중 인터럽트에서 다른 뱅크 전송을 실행해 같은 공간을 덮어쓰지 마세요. GB 복사 보조 코드는 복귀 뱅크에도 공유 HRAM 슬롯 하나를 씁니다. 예제는 경쟁하는 전송 인터럽트 없이 고정 코드에서 실행합니다.

이 GB 뱅크 API는 8비트 번호를 다루며 MBC5의 아홉 번째 뱅크 비트는 설정하지 않습니다. 뱅크 0 처리 등 카트리지별 규칙도 적용됩니다. 예제는 MBC5 뱅크 1~3을 명시적으로 사용합니다. 상태에 반영되지 않는 매퍼 직접 쓰기와 섞지 마세요.

사용 예

c
bank_expect(farptr_read8(pointer)==0x7A,9);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 코드 조각은 farptr_read8로 뱅크 3의 pointer.ptr를 읽고 7A를 확인합니다. 완성 프로그램은 home2의 근거리 읽기로 뱅크 2 매핑이 복원되었는지도 확인합니다.

완성 프로그램은 뱅크 번호와 근거리 주소로 데이터를 지정하는 방법, 뱅크를 넘는 콜백, 라이브러리 기록과 실제 매핑의 구별을 보여 줍니다. 모든 표시 숫자는 16진수입니다. BANK IN과 BANK OUT은 02, BYTE HEX는 D3, WORD HEX는 5C7A, FAILED CHECKS와 FIRST FAILURE는 모두 00이어야 합니다. CGB와 FC는 파란 글자, DMG는 검은 글자를 표시합니다.

CALL COUNT는 03입니다. far_call, __farcall, __farcall_ptr이 각각 콜백을 한 번 호출합니다.

farptr_read8: DMG
DMG
farptr_read8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\banked_data_calls.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\banked_data_calls.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/bank.h:34

선언 주석 원문
Read one byte using both components of the bank-qualified pointer.

kitaqgb/lib/bank.c:54

c
u8 farptr_read8(BankPtr ptr)
{
    return __farpeek8(ptr.bank, ptr.ptr);
}

camera.h — 월드 좌표와 가시 영역

Q8.8 카메라 위치, 목표, 경계를 관리하고 월드·화면 좌표를 변환합니다. 호출자 소유의 Camera8_8 객체 또는 카메라 하나를 공유하는 소문자 API를 선택할 수 있습니다.

Camera_Add

현재 위치에 Q8.8 변위를 더한 뒤, 활성화된 범위 제한을 적용합니다.

사용 형식

c
void Camera_Add(Camera8_8* cam, s16 dfx, s16 dfy);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

dfx

부호 있는 Q8.8 변위입니다. 256은 1픽셀 이동입니다.

dfy

부호 있는 Q8.8 변위입니다. 256은 1픽셀 이동입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
Camera_Add(&cam,256,512);result[13]=cam.fx;result[14]=cam.fy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_Add: DMG
DMG
Camera_Add: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_Add: DMG
DMG
Camera_Add: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:34

선언 주석 원문
Add Q8.8 deltas and clamp afterward. Keep the intermediate sums within s16;
clamping cannot repair arithmetic that already overflowed.

kitaqgb/lib/camera.c:79

c
void Camera_Add(Camera8_8* cam, s16 dfx, s16 dfy)
{
    cam->fx += dfx;
    cam->fy += dfy;
    Camera_ApplyBounds(cam);
}
camera_apply

공유 카메라의 현재 위치를 배경 스크롤에 즉시 적용합니다.

사용 형식

c
void camera_apply();

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

VBlank를 기다리지 않습니다. 프레임 도중의 변경을 원하지 않으면 호출자가 동기화하세요. 음수 소수도 아래쪽으로 내림하므로 −1/256은 −1픽셀, 즉 레지스터 값 255가 됩니다.

사용 예

c
camera_apply();result[31]=M_SCX;result[32]=M_SCY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

camera_apply: DMG
DMG
camera_apply: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

camera_apply: DMG
DMG
camera_apply: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:64

선언 주석 원문
Write the shared camera's current integer position to background scroll registers.

kitaqgb/lib/camera.c:179

c
void camera_apply()
{
    Camera_ApplyBg(&camera_default);
}
Camera_ApplyBg

카메라 위치를 정수 픽셀로 내림하고, 하위 8비트를 배경 스크롤에 즉시 기록합니다.

사용 형식

c
void Camera_ApplyBg(const Camera8_8* cam);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

VBlank를 기다리지 않습니다. 프레임 도중의 변경을 원하지 않으면 호출자가 동기화하세요. 음수 소수도 아래쪽으로 내림하므로 −1/256은 −1픽셀, 즉 레지스터 값 255가 됩니다.

사용 예

c
Camera_ApplyBg(&cam);result[21]=M_SCX;result[22]=M_SCY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_ApplyBg: DMG
DMG
Camera_ApplyBg: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_ApplyBg: DMG
DMG
Camera_ApplyBg: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:40

선언 주석 원문
Discard fractional bits and write the low eight integer bits to background scroll registers.

kitaqgb/lib/camera.c:109

c
void Camera_ApplyBg(const Camera8_8* cam)
{
    __scroll_bg_set((u8)(cam->fx >> 8), (u8)(cam->fy >> 8));
}
Camera_ApplyBgBuffered

카메라 위치를 정수 픽셀로 내림하여 다음에 반영할 배경 스크롤 값으로 저장합니다.

사용 형식

c
void Camera_ApplyBgBuffered(const Camera8_8* cam);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

Scroll_Flush 또는 __scroll_flush를 호출하기 전까지 하드웨어와 추적 중인 현재값은 바뀌지 않습니다. 이 호출은 VBlank를 기다리지 않습니다.

사용 예

c
Camera_Set(&cam,2048,4096);Camera_ApplyBgBuffered(&cam);result[23]=M_SCX;Scroll_Flush();result[24]=M_SCX;result[25]=M_SCY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_ApplyBgBuffered: DMG
DMG
Camera_ApplyBgBuffered: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_ApplyBgBuffered: DMG
DMG
Camera_ApplyBgBuffered: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:42

선언 주석 원문
Convert the Q8.8 position to byte scroll values and stage them for a later flush.

kitaqgb/lib/camera.c:115

c
void Camera_ApplyBgBuffered(const Camera8_8* cam)
{
    __scroll_bg_set_buffered((u8)(cam->fx >> 8), (u8)(cam->fy >> 8));
}
camera_clamp

월드 크기에서 화면 크기를 뺀 범위를 공유 카메라에 적용합니다.

사용 형식

c
void camera_clamp(u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);

매개변수

world_w_px

정수 픽셀 단위의 월드 크기입니다. 화면보다 큰 만큼의 차이는 0~127 안에 유지하세요.

world_h_px

정수 픽셀 단위의 월드 크기입니다. 화면보다 큰 만큼의 차이는 0~127 안에 유지하세요.

screen_w_px

정수 픽셀 단위의 뷰포트 크기입니다. 월드 크기 이상이면 해당 축의 이동 범위는 0입니다.

screen_h_px

정수 픽셀 단위의 뷰포트 크기입니다. 월드 크기 이상이면 해당 축의 이동 범위는 0입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

월드가 뷰포트보다 작으면 이동 범위는 0입니다. 양의 차이가 128 이상이면 변환 시 부호 있는 Q8.8 범위를 넘습니다. 매개변수가 u16이라고 해서 임의로 큰 월드 전체를 카메라가 이동할 수 있는 것은 아닙니다. 이 호출들은 카메라 하나를 공유합니다. 독립된 카메라 객체에는 대문자로 시작하는 API를 사용하세요. 정수 픽셀에서 Q8.8로 변환할 위치는 −128~127 범위여야 합니다.

사용 예

c
camera_clamp(176,160,160,144);result[29]=camera_world_to_screen_x(100);result[30]=camera_world_to_screen_y(90);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

camera_clamp: DMG
DMG
camera_clamp: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

camera_clamp: DMG
DMG
camera_clamp: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:62

선언 주석 원문
Derive and apply world/screen bounds to the shared convenience camera.

kitaqgb/lib/camera.c:173

c
void camera_clamp(u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px)
{
    Camera_ClampToSize(&camera_default, world_w_px, world_h_px, screen_w_px, screen_h_px);
}
Camera_ClampToSize

월드 크기에서 화면 크기를 빼고, 결과를 음수가 아닌 카메라 이동 범위로 설정합니다.

사용 형식

c
void Camera_ClampToSize(Camera8_8* cam, u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

world_w_px

정수 픽셀 단위의 월드 크기입니다. 화면보다 큰 만큼의 차이는 0~127 안에 유지하세요.

world_h_px

정수 픽셀 단위의 월드 크기입니다. 화면보다 큰 만큼의 차이는 0~127 안에 유지하세요.

screen_w_px

정수 픽셀 단위의 뷰포트 크기입니다. 월드 크기 이상이면 해당 축의 이동 범위는 0입니다.

screen_h_px

정수 픽셀 단위의 뷰포트 크기입니다. 월드 크기 이상이면 해당 축의 이동 범위는 0입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

월드가 뷰포트보다 작으면 이동 범위는 0입니다. 양의 차이가 128 이상이면 변환 시 부호 있는 Q8.8 범위를 넘습니다. 매개변수가 u16이라고 해서 임의로 큰 월드 전체를 카메라가 이동할 수 있는 것은 아닙니다.

사용 예

c
Camera_ClampToSize(&cam,176,160,160,144);result[15]=cam.max_fx;result[16]=cam.max_fy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_ClampToSize: DMG
DMG
Camera_ClampToSize: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_ClampToSize: DMG
DMG
Camera_ClampToSize: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:46

선언 주석 원문
Derive nonnegative camera extents from world minus screen size, then convert
them to Q8.8 bounds. Extents must fit signed Q8.8; the u16 input type does
not imply support for arbitrary large worlds.

kitaqgb/lib/camera.c:123

c
void Camera_ClampToSize(Camera8_8* cam, u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px)
{
    s16 max_x = 0;
    s16 max_y = 0;

    if (world_w_px > screen_w_px) max_x = (s16)((u16)(world_w_px - screen_w_px) << 8);
    if (world_h_px > screen_h_px) max_y = (s16)((u16)(world_h_px - screen_h_px) << 8);
    Camera_SetBounds(cam, (s16)0, (s16)0, max_x, max_y);
}
Camera_ClearBounds

위치, 목표, 저장된 경계를 바꾸지 않고 범위 제한을 비활성화합니다.

사용 형식

c
void Camera_ClearBounds(Camera8_8* cam);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
Camera_ClearBounds(&cam);result[12]=cam.use_bounds;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_ClearBounds: DMG
DMG
Camera_ClearBounds: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_ClearBounds: DMG
DMG
Camera_ClearBounds: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:31

선언 주석 원문
Disable clamping while retaining the stored bounds and current position.

kitaqgb/lib/camera.c:72

c
void Camera_ClearBounds(Camera8_8* cam)
{
    cam->use_bounds = 0;
}
Camera_ClearTarget

현재 위치와 저장된 목표를 유지하면서 추적을 비활성화합니다.

사용 형식

c
void Camera_ClearTarget(Camera8_8* cam);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
Camera_ClearTarget(&cam);result[8]=cam.use_target;result[9]=cam.target_fx;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_ClearTarget: DMG
DMG
Camera_ClearTarget: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_ClearTarget: DMG
DMG
Camera_ClearTarget: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:27

선언 주석 원문
Disable target following without moving the camera or erasing the stored target.

kitaqgb/lib/camera.c:55

c
void Camera_ClearTarget(Camera8_8* cam)
{
    cam->use_target = 0;
}
camera_follow_xy

월드의 한 점이 지정한 화면 기준점에 나타나도록 공유 카메라를 즉시 이동합니다.

사용 형식

c
void camera_follow_xy(s16 x, s16 y, u8 screen_cx, u8 screen_cy);

매개변수

x

정수 픽셀 단위의 월드 X 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

y

정수 픽셀 단위의 월드 Y 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

screen_cx

정수 픽셀 단위의 화면 기준점 좌표이며, 범위는 0~255입니다.

screen_cy

정수 픽셀 단위의 화면 기준점 좌표이며, 범위는 0~255입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다. 이 호출들은 카메라 하나를 공유합니다. 독립된 카메라 객체에는 대문자로 시작하는 API를 사용하세요. 정수 픽셀에서 Q8.8로 변환할 위치는 −128~127 범위여야 합니다.

사용 예

c
camera_follow_xy(100,90,80,72);result[27]=camera_world_to_screen_x(100);result[28]=camera_world_to_screen_y(90);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

camera_follow_xy: DMG
DMG
camera_follow_xy: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

camera_follow_xy: DMG
DMG
camera_follow_xy: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:60

선언 주석 원문
Position the shared camera so the world point appears at the requested screen
anchor. This is an immediate move, not the smoothed target-following path.

kitaqgb/lib/camera.c:165

c
void camera_follow_xy(s16 x, s16 y, u8 screen_cx, u8 screen_cy)
{
    s16 cx = (s16)(x - screen_cx);
    s16 cy = (s16)(y - screen_cy);
    Camera_Set(&camera_default, (s16)(cx << 8), (s16)(cy << 8));
}
Camera_Init

위치, 목표, 경계를 0으로 초기화하고 추적과 범위 제한을 비활성화합니다.

사용 형식

c
void Camera_Init(Camera8_8* cam);

매개변수

cam

초기화할 쓰기 가능한 Camera8_8입니다. NULL이면 안 됩니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
Camera_Init(&cam);result[0]=cam.fx;result[1]=cam.use_target;result[2]=cam.use_bounds;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_Init: DMG
DMG
Camera_Init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_Init: DMG
DMG
Camera_Init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:21

선언 주석 원문
Zero all position/target/bound fields and disable targeting and bounds.

kitaqgb/lib/camera.c:24

c
void Camera_Init(Camera8_8* cam)
{
    cam->fx = 0;
    cam->fy = 0;
    cam->target_fx = 0;
    cam->target_fy = 0;
    cam->min_fx = 0;
    cam->min_fy = 0;
    cam->max_fx = 0;
    cam->max_fy = 0;
    cam->use_target = 0;
    cam->use_bounds = 0;
}
Camera_ScreenToWorldX

정수 화면 X 좌표에 카메라 X의 정수부를 더해 월드 X 좌표를 구합니다.

사용 형식

c
s16 Camera_ScreenToWorldX(const Camera8_8* cam, s16 screen_x);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

screen_x

정수 픽셀 단위의 화면 X 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

반환값

변환한 정수 픽셀 좌표를 s16으로 반환합니다. 화면에 보이는지 검사하거나 잘라내지는 않습니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
result[19]=Camera_ScreenToWorldX(&cam,27);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_ScreenToWorldX: DMG
DMG
Camera_ScreenToWorldX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_ScreenToWorldX: DMG
DMG
Camera_ScreenToWorldX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:52

선언 주석 원문
Convert integer-pixel screen X back to world X using the camera's integer component.

kitaqgb/lib/camera.c:146

c
s16 Camera_ScreenToWorldX(const Camera8_8* cam, s16 screen_x)
{
    return (s16)(screen_x + (cam->fx >> 8));
}
Camera_ScreenToWorldY

정수 화면 Y 좌표에 카메라 Y의 정수부를 더해 월드 Y 좌표를 구합니다.

사용 형식

c
s16 Camera_ScreenToWorldY(const Camera8_8* cam, s16 screen_y);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

screen_y

정수 픽셀 단위의 화면 Y 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

반환값

변환한 정수 픽셀 좌표를 s16으로 반환합니다. 화면에 보이는지 검사하거나 잘라내지는 않습니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
result[20]=Camera_ScreenToWorldY(&cam,24);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_ScreenToWorldY: DMG
DMG
Camera_ScreenToWorldY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_ScreenToWorldY: DMG
DMG
Camera_ScreenToWorldY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:54

선언 주석 원문
Convert integer-pixel screen Y back to world Y using the camera's integer component.

kitaqgb/lib/camera.c:152

c
s16 Camera_ScreenToWorldY(const Camera8_8* cam, s16 screen_y)
{
    return (s16)(screen_y + (cam->fy >> 8));
}
Camera_Set

현재 카메라 위치를 바꾸고, 범위 제한이 활성화되어 있으면 즉시 그 범위 안으로 제한합니다.

사용 형식

c
void Camera_Set(Camera8_8* cam, s16 fx, s16 fy);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

fx

X 좌표입니다. 부호 있는 Q8.8 좌표로, 256이 1픽셀이며 범위는 −128~127+255/256픽셀입니다.

fy

Y 좌표입니다. 부호 있는 Q8.8 좌표로, 256이 1픽셀이며 범위는 −128~127+255/256픽셀입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
Camera_Set(&cam,2560,5120);result[3]=cam.fx;result[4]=cam.fy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_Set: DMG
DMG
Camera_Set: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_Set: DMG
DMG
Camera_Set: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:23

선언 주석 원문
Replace the current Q8.8 position and immediately apply enabled bounds.

kitaqgb/lib/camera.c:39

c
void Camera_Set(Camera8_8* cam, s16 fx, s16 fy)
{
    cam->fx = fx;
    cam->fy = fy;
    Camera_ApplyBounds(cam);
}
camera_set

정수 픽셀 좌표로 공유 카메라를 이동하고 활성화된 범위 제한을 적용합니다.

사용 형식

c
void camera_set(s16 x, s16 y);

매개변수

x

정수 픽셀 단위의 월드 X 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

y

정수 픽셀 단위의 월드 Y 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다. 이 호출들은 카메라 하나를 공유합니다. 독립된 카메라 객체에는 대문자로 시작하는 API를 사용하세요. 정수 픽셀에서 Q8.8로 변환할 위치는 −128~127 범위여야 합니다.

사용 예

c
camera_set(5,6);result[26]=camera_world_to_screen_x(20);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

camera_set: DMG
DMG
camera_set: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

camera_set: DMG
DMG
camera_set: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:57

선언 주석 원문
Set the shared camera from integer pixels, converting to the representable Q8.8 range.

kitaqgb/lib/camera.c:158

c
void camera_set(s16 x, s16 y)
{
    Camera_Set(&camera_default, (s16)(x << 8), (s16)(y << 8));
}
Camera_SetBounds

최소·최대 좌표를 설정하고 범위 제한을 활성화한 뒤, 현재 위치에 즉시 적용합니다.

사용 형식

c
void Camera_SetBounds(Camera8_8* cam, s16 min_fx, s16 min_fy, s16 max_fx, s16 max_fy);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

min_fx

최소 X 좌표입니다. 부호 있는 Q8.8 좌표로, 256이 1픽셀이며 범위는 −128~127+255/256픽셀입니다.

min_fy

최소 Y 좌표입니다. 부호 있는 Q8.8 좌표로, 256이 1픽셀이며 범위는 −128~127+255/256픽셀입니다.

max_fx

최대 X 좌표입니다. 부호 있는 Q8.8 좌표로, 256이 1픽셀이며 범위는 −128~127+255/256픽셀입니다.

max_fy

최대 Y 좌표입니다. 부호 있는 Q8.8 좌표로, 256이 1픽셀이며 범위는 −128~127+255/256픽셀입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

각 축에서 최소값 ≤ 최대값이 되도록 전달하세요. 경계를 자동으로 재정렬하지 않습니다. 저장된 목표에는 범위 제한을 적용하지 않습니다.

사용 예

c
Camera_SetBounds(&cam,0,0,3072,3584);result[10]=cam.fx;result[11]=cam.fy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_SetBounds: DMG
DMG
Camera_SetBounds: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_SetBounds: DMG
DMG
Camera_SetBounds: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:29

선언 주석 원문
Install ordered Q8.8 bounds, enable them and clamp the current position immediately.

kitaqgb/lib/camera.c:61

c
void Camera_SetBounds(Camera8_8* cam, s16 min_fx, s16 min_fy, s16 max_fx, s16 max_fy)
{
    cam->min_fx = min_fx;
    cam->min_fy = min_fy;
    cam->max_fx = max_fx;
    cam->max_fy = max_fy;
    cam->use_bounds = 1;
    Camera_ApplyBounds(cam);
}
Camera_SetTarget

목표를 저장하고 추적을 활성화합니다. 현재 위치는 이동하지 않습니다.

사용 형식

c
void Camera_SetTarget(Camera8_8* cam, s16 fx, s16 fy);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

fx

X 좌표입니다. 부호 있는 Q8.8 좌표로, 256이 1픽셀이며 범위는 −128~127+255/256픽셀입니다.

fy

Y 좌표입니다. 부호 있는 Q8.8 좌표로, 256이 1픽셀이며 범위는 −128~127+255/256픽셀입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
Camera_SetTarget(&cam,4608,3072);result[5]=cam.use_target;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_SetTarget: DMG
DMG
Camera_SetTarget: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_SetTarget: DMG
DMG
Camera_SetTarget: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:25

선언 주석 원문
Store a Q8.8 target and enable subsequent step-toward-target updates.

kitaqgb/lib/camera.c:47

c
void Camera_SetTarget(Camera8_8* cam, s16 fx, s16 fy)
{
    cam->target_fx = fx;
    cam->target_fy = fy;
    cam->use_target = 1;
}
Camera_StepTowardTarget

남은 거리를 오른쪽 시프트한 만큼 목표에 접근합니다. 추적이 비활성화되어 있으면 아무 동작도 하지 않습니다.

사용 형식

c
void Camera_StepTowardTarget(Camera8_8* cam, u8 shift);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

shift

변위를 나눌 2의 거듭제곱의 지수입니다. 0이면 전체 변위, 1이면 절반을 사용합니다. 7보다 큰 값은 7로 제한합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

작은 양의 차이는 잘림으로 0이 될 수 있고, 산술 오른쪽 시프트는 작은 음의 차이를 −1로 만들 수 있습니다. 목표와의 일치 여부는 범위 제한 전에 검사합니다. 따라서 범위 밖의 목표는 추적 상태를 계속 활성화할 수도 있고, 최종 제한 위치가 목표와 달라도 추적을 해제할 수도 있습니다.

사용 예

c
Camera_StepTowardTarget(&cam,1);result[6]=cam.fx;result[7]=cam.fy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_StepTowardTarget: DMG
DMG
Camera_StepTowardTarget: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_StepTowardTarget: DMG
DMG
Camera_StepTowardTarget: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:38

선언 주석 원문
Move by the signed target delta shifted by 0..7 bits, then apply bounds.
Quantization can make a small delta produce no movement; only exact equality
clears targeting, and a target outside the bounds may remain active indefinitely.

kitaqgb/lib/camera.c:89

c
void Camera_StepTowardTarget(Camera8_8* cam, u8 shift)
{
    s16 dx;
    s16 dy;

    if (cam->use_target == 0) return;
    if (shift > 7) shift = 7;

    // Keep target-minus-position differences within s16 as well as the individual positions.
    dx = cam->target_fx - cam->fx;
    dy = cam->target_fy - cam->fy;

    if (dx != 0) cam->fx += (dx >> shift);
    if (dy != 0) cam->fy += (dy >> shift);

    if (cam->fx == cam->target_fx && cam->fy == cam->target_fy) cam->use_target = 0;
    Camera_ApplyBounds(cam);
}
camera_world_to_screen_x

월드 X에서 공유 카메라 X의 정수부를 빼서 화면 X로 변환합니다.

사용 형식

c
s16 camera_world_to_screen_x(s16 world_x);

매개변수

world_x

정수 픽셀 단위의 월드 X 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

반환값

변환한 정수 픽셀 좌표를 s16으로 반환합니다. 화면에 보이는지 검사하거나 잘라내지는 않습니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다. 이 호출들은 카메라 하나를 공유합니다. 독립된 카메라 객체에는 대문자로 시작하는 API를 사용하세요. 정수 픽셀에서 Q8.8로 변환할 위치는 −128~127 범위여야 합니다.

사용 예

c
result[33]=camera_world_to_screen_x(20);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

camera_world_to_screen_x: DMG
DMG
camera_world_to_screen_x: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

camera_world_to_screen_x: DMG
DMG
camera_world_to_screen_x: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:66

선언 주석 원문
Convert integer-pixel world X using the shared convenience camera.

kitaqgb/lib/camera.c:185

c
s16 camera_world_to_screen_x(s16 world_x)
{
    return Camera_WorldToScreenX(&camera_default, world_x);
}
camera_world_to_screen_y

월드 Y에서 공유 카메라 Y의 정수부를 빼서 화면 Y로 변환합니다.

사용 형식

c
s16 camera_world_to_screen_y(s16 world_y);

매개변수

world_y

정수 픽셀 단위의 월드 Y 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

반환값

변환한 정수 픽셀 좌표를 s16으로 반환합니다. 화면에 보이는지 검사하거나 잘라내지는 않습니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다. 이 호출들은 카메라 하나를 공유합니다. 독립된 카메라 객체에는 대문자로 시작하는 API를 사용하세요. 정수 픽셀에서 Q8.8로 변환할 위치는 −128~127 범위여야 합니다.

사용 예

c
result[34]=camera_world_to_screen_y(20);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

camera_world_to_screen_y: DMG
DMG
camera_world_to_screen_y: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

camera_world_to_screen_y: DMG
DMG
camera_world_to_screen_y: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:68

선언 주석 원문
Convert integer-pixel world Y using the shared convenience camera.

kitaqgb/lib/camera.c:191

c
s16 camera_world_to_screen_y(s16 world_y)
{
    return Camera_WorldToScreenY(&camera_default, world_y);
}
Camera_WorldToScreenX

정수 월드 X 좌표에서 카메라 X의 정수부를 빼서 화면 X 좌표를 구합니다.

사용 형식

c
s16 Camera_WorldToScreenX(const Camera8_8* cam, s16 world_x);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

world_x

정수 픽셀 단위의 월드 X 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

반환값

변환한 정수 픽셀 좌표를 s16으로 반환합니다. 화면에 보이는지 검사하거나 잘라내지는 않습니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
result[17]=Camera_WorldToScreenX(&cam,40);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_WorldToScreenX: DMG
DMG
Camera_WorldToScreenX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_WorldToScreenX: DMG
DMG
Camera_WorldToScreenX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:48

선언 주석 원문
Convert an integer-pixel world X by subtracting the camera's integer X component.

kitaqgb/lib/camera.c:134

c
s16 Camera_WorldToScreenX(const Camera8_8* cam, s16 world_x)
{
    return (s16)(world_x - (cam->fx >> 8));
}
Camera_WorldToScreenY

정수 월드 Y 좌표에서 카메라 Y의 정수부를 빼서 화면 Y 좌표를 구합니다.

사용 형식

c
s16 Camera_WorldToScreenY(const Camera8_8* cam, s16 world_y);

매개변수

cam

호출자가 소유하고 초기화를 마친 Camera8_8의 유효한 포인터입니다.

world_y

정수 픽셀 단위의 월드 Y 좌표입니다. 결과와 중간 차이는 s16 범위 안에 있어야 합니다.

반환값

변환한 정수 픽셀 좌표를 s16으로 반환합니다. 화면에 보이는지 검사하거나 잘라내지는 않습니다.

사용 조건과 제한

좌표의 소수부는 8비트입니다. 위치, 목표, 중간 합과 차를 s16 범위 안에 유지하세요. 화면은 Camera_ApplyBg 또는 버퍼 반영으로 별도 갱신해야 합니다.

사용 예

c
result[18]=Camera_WorldToScreenY(&cam,40);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Q8.8 추적, 범위 제한, 좌표 변환을 익히는 예제입니다. 추적 후 X/Y는 3584/4096이고, 경계를 적용하면 3072/3584가 됩니다. 보류 상태의 BG X는 13을 유지하다가 반영 후 8이 됩니다. 추가 이미지는 (8,16)의 카메라에 의해 월드 (32,32)의 32×24 사각형이 화면 (24,16)에 표시되는 모습을 보여 줍니다.

Camera_WorldToScreenY: DMG
DMG
Camera_WorldToScreenY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Camera_WorldToScreenY: DMG
DMG
Camera_WorldToScreenY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/camera.h:50

선언 주석 원문
Convert an integer-pixel world Y by subtracting the camera's integer Y component.

kitaqgb/lib/camera.c:140

c
s16 Camera_WorldToScreenY(const Camera8_8* cam, s16 world_y)
{
    return (s16)(world_y - (cam->fy >> 8));
}

cgb_palette.h — CGB 배경·OBJ 팔레트

cgb_palette.h와 cgb_palette.c는 RGB15 값 생성과 CGB 팔레트 즉시 갱신을 제공합니다. 배경·윈도우에는 BG 함수, 스프라이트에는 OBJ 함수를 사용합니다. 단색·RGB 성분 함수는 한 색, 범위 함수는 연속된 색 워드, 전체 팔레트 함수는 네 워드를 씁니다. raw 범위 함수는 절대 색 슬롯을, 레지스터 내장 함수는 바이트 위치를 사용합니다. 팔레트 할당은 맵 속성이나 OAM에서 별도로 지정합니다. 전체 예제처럼 구현은 프로그램에 한 번만 포함하세요.

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

cgb_bg_color

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

RGB15로 묶은 색 하나를 배경·윈도우 팔레트에 즉시 씁니다. 팔레트 번호와 색 번호로 32개 색 슬롯 중 하나를 고릅니다. 타일 데이터나 타일에 지정된 팔레트는 바꾸지 않습니다.

사용 형식

c
void cgb_bg_color(u8 palette_index, u8 color_index, u16 rgb15);

매개변수

palette_index

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

color_index

선택한 팔레트 안의 색 번호 0~3. 하위 2비트만 사용합니다(& 3).

rgb15

묶인 15비트 RGB 색(보통 0~32767). 전달한 u16의 하위·상위 바이트를 차례로 쓰며 라이브러리는 비트 15를 따로 지우지 않습니다. 올바른 값은 CGB_RGB15나 cgb_rgb15로 만들 수 있습니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_bg_color(1,3,31); // Red background color 3 of palette 1.
expect_color(0,7,31);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_bg_color: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_bg_color: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_bg_color: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_bg_color: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:22

선언 주석 원문
Set one background color through the indexed palette wrapper.

kitaqgb/lib/cgb_palette.c:110

c
void cgb_bg_color(u8 palette_index, u8 color_index, u16 rgb15)
{
    cgb__write_color_bg_raw(cgb__palette_color_slot(palette_index, color_index), rgb15);
}
cgb_bg_colors

지정한 팔레트 번호와 시작 색 번호부터 배경·윈도우 팔레트에 RGB15 워드를 연속해서 씁니다. 4색 팔레트 경계는 넘을 수 있지만 전체 32색 저장 공간의 끝에서 멈춥니다.

사용 형식

c
void cgb_bg_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);

매개변수

palette_index

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

start_color_index

선택한 팔레트 안의 색 번호 0~3. 하위 2비트만 사용합니다(& 3).

colors

필요한 색 워드가 있는 읽기 가능한 const u16*입니다. 호출 중에 읽으며 큐에 보관하지 않습니다. 배열과 해당 ROM 뱅크를 계속 읽을 수 있어야 하며 자동 뱅크 전환은 없습니다. null이면 아무것도 쓰지 않습니다.

color_count

바이트가 아닌 색 워드 수이며 u8(0~255)로 전달합니다. 0이면 아무 작업도 하지 않습니다. 실제 수는 32 - 정규화된 시작 슬롯으로 제한되며 그만큼의 원본 워드만 읽습니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_bg_colors(3,2,tail_green,2); // Two color words; color 3 becomes green.
expect_color(0,14,0); expect_color(0,15,992);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_bg_colors: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_bg_colors: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_bg_colors: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_bg_colors: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:32

선언 주석 원문
Write background colors starting at the indexed slot. The range may cross
palette boundaries and is clamped only at the end of all 32 slots.

kitaqgb/lib/cgb_palette.c:135

c
void cgb_bg_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count)
{
    cgb__write_colors_bg_raw(cgb__palette_color_slot(palette_index, start_color_index), colors, color_count);
}
cgb_bg_colors_raw

전체 32색 중 절대 슬롯 번호를 시작 위치로 삼아 배경·윈도우 팔레트에 RGB15 워드를 연속해서 씁니다. 팔레트·색 번호 쌍 대신 0~31의 번호 하나를 사용합니다. 입력은 타일 바이트가 아닌 색 워드 배열입니다.

사용 형식

c
void cgb_bg_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);

매개변수

start_color_slot

절대 색 슬롯 번호 0~31. & 31로 정규화한 뒤 쓰기 길이를 제한합니다. 슬롯 = 팔레트 × 4 + 색 번호이며 바이트 오프셋이 아닙니다.

colors

필요한 색 워드가 있는 읽기 가능한 const u16*입니다. 호출 중에 읽으며 큐에 보관하지 않습니다. 배열과 해당 ROM 뱅크를 계속 읽을 수 있어야 하며 자동 뱅크 전환은 없습니다. null이면 아무것도 쓰지 않습니다.

color_count

바이트가 아닌 색 워드 수이며 u8(0~255)로 전달합니다. 0이면 아무 작업도 하지 않습니다. 실제 수는 32 - 정규화된 시작 슬롯으로 제한되며 그만큼의 원본 워드만 읽습니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_bg_colors_raw(23,blue_word,1); // Absolute slot 23 = palette 5, color 3.
expect_color(0,23,31744);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_bg_colors_raw: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_bg_colors_raw: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_bg_colors_raw: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_bg_colors_raw: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:42

선언 주석 원문
Expose sequential background writes using an absolute color-slot index.

kitaqgb/lib/cgb_palette.c:159

c
void cgb_bg_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count)
{
    cgb__write_colors_bg_raw(start_color_slot, colors, color_count);
}
cgb_bg_palette

RGB15 워드 네 개로 배경·윈도우 팔레트 하나의 모든 색을 설정합니다. 시작 색 0, 색 수 4로 범위 쓰기를 호출하는 함수입니다. 타일이나 스프라이트에 이 팔레트를 지정하는 작업은 별도입니다.

사용 형식

c
void cgb_bg_palette(u8 palette_index, const u16* colors);

매개변수

palette_index

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

colors

필요한 색 워드가 있는 읽기 가능한 const u16*입니다. 호출 중에 읽으며 큐에 보관하지 않습니다. 배열과 해당 ROM 뱅크를 계속 읽을 수 있어야 하며 자동 뱅크 전환은 없습니다. null이면 아무것도 쓰지 않습니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_bg_palette(4,red_palette); // Exactly four color words for BG palette 4.
expect_color(0,16,32767); expect_color(0,19,31);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_bg_palette: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_bg_palette: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_bg_palette: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_bg_palette: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:37

선언 주석 원문
Write four consecutive colors for one background palette.

kitaqgb/lib/cgb_palette.c:147

c
void cgb_bg_palette(u8 palette_index, const u16* colors)
{
    cgb_bg_colors(palette_index, 0, colors, 4);
}
cgb_bg_rgb

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

빨강·초록·파랑 성분을 cgb_rgb15로 묶어 배경·윈도우 팔레트에 색 하나를 씁니다. 완성된 색 워드 대신 각 성분을 따로 지정할 때 사용합니다.

사용 형식

c
void cgb_bg_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);

매개변수

palette_index

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

color_index

선택한 팔레트 안의 색 번호 0~3. 하위 2비트만 사용합니다(& 3).

r5, g5, b5

각각 빨강·초록·파랑 성분이며 보통 각각 0~31입니다. 포화 대신 마스크를 적용합니다. 매크로 확장에서 각 인수는 한 번씩만 나타납니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_bg_rgb(2,3,0,0,31); // Blue, supplied as three five-bit components.
expect_color(0,11,31744);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_bg_rgb: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_bg_rgb: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_bg_rgb: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_bg_rgb: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:26

선언 주석 원문
Pack component values and write one background color.

kitaqgb/lib/cgb_palette.c:122

c
void cgb_bg_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5)
{
    cgb_bg_color(palette_index, color_index, cgb_rgb15(r5, g5, b5));
}
cgb_obj_color

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

RGB15로 묶은 색 하나를 스프라이트(OBJ) 팔레트에 즉시 씁니다. 팔레트 번호와 색 번호로 32개 색 슬롯 중 하나를 고릅니다. 타일 데이터나 타일에 지정된 팔레트는 바꾸지 않습니다.

사용 형식

c
void cgb_obj_color(u8 palette_index, u8 color_index, u16 rgb15);

매개변수

palette_index

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

color_index

선택한 팔레트 안의 색 번호 0~3. 하위 2비트만 사용합니다(& 3).

rgb15

묶인 15비트 RGB 색(보통 0~32767). 전달한 u16의 하위·상위 바이트를 차례로 쓰며 라이브러리는 비트 15를 따로 지우지 않습니다. 올바른 값은 CGB_RGB15나 cgb_rgb15로 만들 수 있습니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_obj_color(1,3,31744); // Blue sprite color at the same palette/color indices.
expect_color(1,7,31744);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_obj_color: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_obj_color: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_obj_color: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_obj_color: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:24

선언 주석 원문
Set one object color through the indexed palette wrapper.

kitaqgb/lib/cgb_palette.c:116

c
void cgb_obj_color(u8 palette_index, u8 color_index, u16 rgb15)
{
    cgb__write_color_obj_raw(cgb__palette_color_slot(palette_index, color_index), rgb15);
}
cgb_obj_colors

지정한 팔레트 번호와 시작 색 번호부터 스프라이트(OBJ) 팔레트에 RGB15 워드를 연속해서 씁니다. 4색 팔레트 경계는 넘을 수 있지만 전체 32색 저장 공간의 끝에서 멈춥니다.

사용 형식

c
void cgb_obj_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);

매개변수

palette_index

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

start_color_index

선택한 팔레트 안의 색 번호 0~3. 하위 2비트만 사용합니다(& 3).

colors

필요한 색 워드가 있는 읽기 가능한 const u16*입니다. 호출 중에 읽으며 큐에 보관하지 않습니다. 배열과 해당 ROM 뱅크를 계속 읽을 수 있어야 하며 자동 뱅크 전환은 없습니다. null이면 아무것도 쓰지 않습니다.

color_count

바이트가 아닌 색 워드 수이며 u8(0~255)로 전달합니다. 0이면 아무 작업도 하지 않습니다. 실제 수는 32 - 정규화된 시작 슬롯으로 제한되며 그만큼의 원본 워드만 읽습니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_obj_colors(3,2,tail_red,2); // Sprite color 3 becomes red.
expect_color(1,14,0); expect_color(1,15,31);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_obj_colors: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_obj_colors: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_obj_colors: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_obj_colors: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:34

선언 주석 원문
Write object colors from the indexed slot, potentially crossing into later palettes.

kitaqgb/lib/cgb_palette.c:141

c
void cgb_obj_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count)
{
    cgb__write_colors_obj_raw(cgb__palette_color_slot(palette_index, start_color_index), colors, color_count);
}
cgb_obj_colors_raw

전체 32색 중 절대 슬롯 번호를 시작 위치로 삼아 스프라이트(OBJ) 팔레트에 RGB15 워드를 연속해서 씁니다. 팔레트·색 번호 쌍 대신 0~31의 번호 하나를 사용합니다. 입력은 타일 바이트가 아닌 색 워드 배열입니다.

사용 형식

c
void cgb_obj_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);

매개변수

start_color_slot

절대 색 슬롯 번호 0~31. & 31로 정규화한 뒤 쓰기 길이를 제한합니다. 슬롯 = 팔레트 × 4 + 색 번호이며 바이트 오프셋이 아닙니다.

colors

필요한 색 워드가 있는 읽기 가능한 const u16*입니다. 호출 중에 읽으며 큐에 보관하지 않습니다. 배열과 해당 ROM 뱅크를 계속 읽을 수 있어야 하며 자동 뱅크 전환은 없습니다. null이면 아무것도 쓰지 않습니다.

color_count

바이트가 아닌 색 워드 수이며 u8(0~255)로 전달합니다. 0이면 아무 작업도 하지 않습니다. 실제 수는 32 - 정규화된 시작 슬롯으로 제한되며 그만큼의 원본 워드만 읽습니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_obj_colors_raw(23,green_word,1); // Same absolute slot in the separate OBJ store.
expect_color(1,23,992);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_obj_colors_raw: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_obj_colors_raw: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_obj_colors_raw: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_obj_colors_raw: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:44

선언 주석 원문
Expose sequential object writes using an absolute color-slot index.

kitaqgb/lib/cgb_palette.c:165

c
void cgb_obj_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count)
{
    cgb__write_colors_obj_raw(start_color_slot, colors, color_count);
}
cgb_obj_palette

RGB15 워드 네 개로 스프라이트(OBJ) 팔레트 하나의 모든 색을 설정합니다. 시작 색 0, 색 수 4로 범위 쓰기를 호출하는 함수입니다. 타일이나 스프라이트에 이 팔레트를 지정하는 작업은 별도입니다.

사용 형식

c
void cgb_obj_palette(u8 palette_index, const u16* colors);

매개변수

palette_index

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

colors

필요한 색 워드가 있는 읽기 가능한 const u16*입니다. 호출 중에 읽으며 큐에 보관하지 않습니다. 배열과 해당 ROM 뱅크를 계속 읽을 수 있어야 하며 자동 뱅크 전환은 없습니다. null이면 아무것도 쓰지 않습니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_obj_palette(4,blue_palette); // Exactly four words; OBJ color zero is transparent on screen.
expect_color(1,16,32767); expect_color(1,19,31744);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_obj_palette: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_obj_palette: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_obj_palette: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_obj_palette: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:39

선언 주석 원문
Write four consecutive colors for one object palette.

kitaqgb/lib/cgb_palette.c:153

c
void cgb_obj_palette(u8 palette_index, const u16* colors)
{
    cgb_obj_colors(palette_index, 0, colors, 4);
}
cgb_obj_rgb

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

빨강·초록·파랑 성분을 cgb_rgb15로 묶어 스프라이트(OBJ) 팔레트에 색 하나를 씁니다. 완성된 색 워드 대신 각 성분을 따로 지정할 때 사용합니다.

사용 형식

c
void cgb_obj_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);

매개변수

palette_index

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

color_index

선택한 팔레트 안의 색 번호 0~3. 하위 2비트만 사용합니다(& 3).

r5, g5, b5

각각 빨강·초록·파랑 성분이며 보통 각각 0~31입니다. 포화 대신 마스크를 적용합니다. 매크로 확장에서 각 인수는 한 번씩만 나타납니다.

반환값

없음(void).

사용 조건과 제한

팔레트와 보호된 레지스터 쓰기는 DMG 모드에서 아무것도 쓰지 않습니다. 여기서 safe는 CGB 모드 확인을 뜻하며 PPU 접근 대기나 임계 구역을 뜻하지 않습니다. LCD를 끄거나 접근 가능한 PPU 구간 안에 끝나는 짧은 갱신에 사용하세요. VBlank를 기다리거나 여러 바이트 갱신을 인터럽트로부터 보호하지 않습니다.

배경·윈도우와 OBJ 팔레트는 별도 저장 공간입니다. 라이브러리 색 쓰기는 인덱스 자동 증가를 켜고 인덱스 레지스터를 바꾼 채 둡니다. OBJ 색 번호 0은 저장·읽기가 가능하지만 스프라이트를 그릴 때는 투명합니다.

사용 예

c
cgb_obj_rgb(2,3,0,31,0); // Green sprite color.
expect_color(1,11,992);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_obj_rgb: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_obj_rgb: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_obj_rgb: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_obj_rgb: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:28

선언 주석 원문
Pack component values and write one object color.

kitaqgb/lib/cgb_palette.c:128

c
void cgb_obj_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5)
{
    cgb_obj_color(palette_index, color_index, cgb_rgb15(r5, g5, b5));
}
CGB_RGB15

RGB 성분을 u16으로 묶습니다. 빨강은 비트 0~4, 초록은 5~9, 파랑은 10~14이며 비트 15는 0입니다. 각 성분에 31 마스크를 적용하므로 범위를 넘으면 상한에 고정하지 않고 하위 5비트만 남깁니다. 하드웨어 쓰기 없이 DMG와 CGB 모두에서 값을 계산합니다.

사용 형식

c
#define CGB_RGB15(r5, g5, b5) ((u16)((u16)((r5) & 31) | ((u16)((g5) & 31) << 5) | ((u16)((b5) & 31) << 10)))

매개변수

r5, g5, b5

각각 빨강·초록·파랑 성분이며 보통 각각 0~31입니다. 포화 대신 마스크를 적용합니다. 매크로 확장에서 각 인수는 한 번씩만 나타납니다.

반환값

0~32767의 RGB15 값(u16).

사용 예

c
if (CGB_RGB15(component,64,95)!=31775) failures++; // (31,0,31), not saturation.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

CGB_RGB15: --cgb=cgb / DMG
--cgb=cgb / DMG
CGB_RGB15: --cgb=cgb / CGB
--cgb=cgb / CGB
CGB_RGB15: --cgb=dmg / DMG
--cgb=dmg / DMG
CGB_RGB15: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:16

cgb_rgb15

RGB 성분을 u16으로 묶습니다. 빨강은 비트 0~4, 초록은 5~9, 파랑은 10~14이며 비트 15는 0입니다. 각 성분에 31 마스크를 적용하므로 범위를 넘으면 상한에 고정하지 않고 하위 5비트만 남깁니다. 하드웨어 쓰기 없이 DMG와 CGB 모두에서 값을 계산합니다.

사용 형식

c
u16 cgb_rgb15(u8 r5, u8 g5, u8 b5);

매개변수

r5, g5, b5

각각 빨강·초록·파랑 성분이며 보통 각각 0~31입니다. 포화 대신 마스크를 적용합니다. 매크로 확장에서 각 인수는 한 번씩만 나타납니다.

반환값

0~32767의 RGB15 값(u16).

사용 예

c
if (cgb_rgb15(component,64,95)!=31775) failures++; // Same packed value through a function.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

cgb_rgb15: --cgb=cgb / DMG
--cgb=cgb / DMG
cgb_rgb15: --cgb=cgb / CGB
--cgb=cgb / CGB
cgb_rgb15: --cgb=dmg / DMG
--cgb=dmg / DMG
cgb_rgb15: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_palette.h:19

선언 주석 원문
Pack the red, green and blue components using the public RGB15 macro.

kitaqgb/lib/cgb_palette.c:104

c
u16 cgb_rgb15(u8 r5, u8 g5, u8 b5)
{
    return CGB_RGB15(r5, g5, b5);
}

cgb_tile.h — CGB 타일 번호와 속성

cgb_tile.h는 타일 맵 내장 함수 선언과 CGB 타일 속성을 구성하는 매크로를 모아 둡니다. 타일 번호는 패턴을 선택하며, 속성은 팔레트, 패턴 VRAM 뱅크, 반전, 배경 우선순위를 선택합니다. 속성을 설정해도 패턴의 픽셀은 바뀌지 않습니다.

__settile 계열은 맵 0x9800을 사용하고, __settileat은 명시한 맵 시작 주소, __settilebg는 LCDC가 선택한 배경 맵, __settilewin은 윈도우 맵을 사용합니다. attr 형식은 속성만, cgb 형식은 타일 번호와 속성을 모두 씁니다. bulk 형식은 지정한 주소에 연속 바이트를 전송합니다. 대상 위치와 기록할 데이터 모두를 기준으로 함수를 선택하세요.

개별 속성 비트에는 KQ_CGB_ATTR_PAL 같은 매크로를, 필드를 합칠 때는 KQ_CGB_ATTR을 사용하세요. bank 필드는 ROM 뱅크가 아니라 패턴이 들어 있는 VRAM 뱅크를 선택합니다. 일반 타일 번호 쓰기는 현재 VRAM 뱅크를 사용하므로 타일·속성 결합 작업 전에 뱅크 0을 선택하세요. DMG에서는 속성 전용 작업은 아무것도 하지 않고, 결합 작업은 타일 번호를 씁니다.

__ 내장 함수 구현은 컴파일러가 생성하므로 cgb_tile.c를 링크할 필요가 없습니다. 일반 쓰기 경로는 VRAM 접근이 가능해질 때까지 기다리지만, 일부는 인터럽트 활성 상태도 바꿉니다. _unsafe, _fast 형식은 이 대기를 생략하므로 LCD가 꺼져 있을 때처럼 호출자가 VRAM 쓰기 가능 상태를 보장할 때만 사용하세요. 각 항목의 인터럽트·뱅크·전송 길이 조건을 확인하세요.

KQ_CGB_ATTR

팔레트, 타일 데이터 뱅크, 좌우 반전, 상하 반전, BG 우선순위로 CGB 맵 속성 바이트를 만듭니다. 팔레트는 비트 0~2, 네 불리언 필드는 차례로 비트 3·5·6·7을 설정합니다. 비트 4는 0입니다.

사용 형식

c
#define KQ_CGB_ATTR(palette, bank, xflip, yflip, priority) ((u8)(((palette) & KQ_CGB_ATTR_PAL_MASK) | ((bank) ? KQ_CGB_ATTR_BANK1 : 0) | ((xflip) ? KQ_CGB_ATTR_XFLIP : 0) | ((yflip) ? KQ_CGB_ATTR_YFLIP : 0) | ((priority) ? KQ_CGB_ATTR_PRIORITY : 0)))

매개변수

palette

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

bank, xflip, yflip, priority

0이면 끄고 0이 아니면 켭니다. 특히 2도 켜짐입니다. 하위 비트가 아니라 값이 0인지 검사합니다.

반환값

위 비트 배치에 따른 속성 필드 또는 조합된 속성 바이트(u8).

사용 조건과 제한

이 매크로는 u8 값만 계산하며 VRAM이나 레지스터에 쓰지 않습니다. 각 인수는 한 번씩 나타납니다. 결과는 CGB 속성 쓰기 API나 뱅크 1 맵에 직접 써서 적용합니다. DMG는 CGB 맵 속성을 표시하지 않습니다.

CGB 맵 속성의 비트 3을 만듭니다. bank가 0이 아니면 0x08, 0이면 0을 반환합니다. 표시할 타일 패턴을 가져올 VRAM 뱅크를 정하며 VBK나 CPU 접근 뱅크는 바꾸지 않습니다.

좌우 반전 플래그를 만듭니다. enabled가 0이 아니면 0x20, 0이면 0입니다. CGB 맵 속성으로 쓰면 타일 각 행의 8픽셀을 역순으로 표시하며 저장된 패턴은 바꾸지 않습니다.

상하 반전 플래그를 만듭니다. enabled가 0이 아니면 0x40, 0이면 0입니다. CGB 맵 속성에서는 저장된 패턴을 바꾸지 않고 타일의 8행을 역순으로 표시합니다.

BG를 OBJ보다 앞에 놓는 우선순위 플래그를 만듭니다. enabled가 0이 아니면 0x80, 0이면 0입니다. CGB 전체 우선순위(LCDC 비트 0)가 켜져 있으면 BG 색 번호 0 이외의 픽셀이 스프라이트를 가립니다. 색 번호 0 부분은 스프라이트가 보이므로 타일 전체를 불투명하게 만들지는 않습니다.

사용 예

c
attr=KQ_CGB_ATTR(10,0,2,2,0); // Palette 2, bank 0, both reflections: 0x62.
if (attr!=98 || KQ_CGB_ATTR(10,2,3,4,5)!=234) failures++;
cell(10,11,1,attr);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

KQ_CGB_ATTR: --cgb=cgb / DMG
--cgb=cgb / DMG
KQ_CGB_ATTR: --cgb=cgb / CGB
--cgb=cgb / CGB
KQ_CGB_ATTR: --cgb=dmg / DMG
--cgb=dmg / DMG
KQ_CGB_ATTR: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_tile.h:23

KQ_CGB_ATTR_BANK

CGB 맵 속성의 비트 3을 만듭니다. bank가 0이 아니면 0x08, 0이면 0을 반환합니다. 표시할 타일 패턴을 가져올 VRAM 뱅크를 정하며 VBK나 CPU 접근 뱅크는 바꾸지 않습니다.

사용 형식

c
#define KQ_CGB_ATTR_BANK(bank) ((u8)((bank) ? KQ_CGB_ATTR_BANK1 : 0))

매개변수

bank

0이면 끄고 0이 아니면 켭니다. 특히 2도 켜짐입니다. 하위 비트가 아니라 값이 0인지 검사합니다.

반환값

위 비트 배치에 따른 속성 필드 또는 조합된 속성 바이트(u8).

사용 조건과 제한

이 매크로는 u8 값만 계산하며 VRAM이나 레지스터에 쓰지 않습니다. 각 인수는 한 번씩 나타납니다. 결과는 CGB 속성 쓰기 API나 뱅크 1 맵에 직접 써서 적용합니다. DMG는 CGB 맵 속성을 표시하지 않습니다.

사용 예

c
attr=(u8)(2|KQ_CGB_ATTR_BANK(enabled)); // Any nonzero value selects tile-data bank 1.
if (attr!=10) failures++;
cell(4,11,1,attr); // Blue hollow square, unlike the bank-0 triangle.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

KQ_CGB_ATTR_BANK: --cgb=cgb / DMG
--cgb=cgb / DMG
KQ_CGB_ATTR_BANK: --cgb=cgb / CGB
--cgb=cgb / CGB
KQ_CGB_ATTR_BANK: --cgb=dmg / DMG
--cgb=dmg / DMG
KQ_CGB_ATTR_BANK: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_tile.h:19

KQ_CGB_ATTR_PAL

CGB 맵 속성의 팔레트 번호 필드를 n & 7로 만들어 u8로 반환합니다. 다른 속성 플래그와는 비트 OR로 합칩니다.

사용 형식

c
#define KQ_CGB_ATTR_PAL(n) ((u8)((n) & KQ_CGB_ATTR_PAL_MASK))

매개변수

n

팔레트 번호 0~7. 하위 3비트만 사용합니다(& 7).

반환값

위 비트 배치에 따른 속성 필드 또는 조합된 속성 바이트(u8).

사용 조건과 제한

이 매크로는 u8 값만 계산하며 VRAM이나 레지스터에 쓰지 않습니다. 각 인수는 한 번씩 나타납니다. 결과는 CGB 속성 쓰기 API나 뱅크 1 맵에 직접 써서 적용합니다. DMG는 CGB 맵 속성을 표시하지 않습니다.

사용 예

c
attr=KQ_CGB_ATTR_PAL(9); // 9 & 7 = palette 1, red in this BG example.
if (attr!=1) failures++;
cell(2,11,1,attr);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

KQ_CGB_ATTR_PAL: --cgb=cgb / DMG
--cgb=cgb / DMG
KQ_CGB_ATTR_PAL: --cgb=cgb / CGB
--cgb=cgb / CGB
KQ_CGB_ATTR_PAL: --cgb=dmg / DMG
--cgb=dmg / DMG
KQ_CGB_ATTR_PAL: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_tile.h:18

KQ_CGB_ATTR_PRIORITY_IF

BG를 OBJ보다 앞에 놓는 우선순위 플래그를 만듭니다. enabled가 0이 아니면 0x80, 0이면 0입니다. CGB 전체 우선순위(LCDC 비트 0)가 켜져 있으면 BG 색 번호 0 이외의 픽셀이 스프라이트를 가립니다. 색 번호 0 부분은 스프라이트가 보이므로 타일 전체를 불투명하게 만들지는 않습니다.

사용 형식

c
#define KQ_CGB_ATTR_PRIORITY_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_PRIORITY : 0))

매개변수

enabled

0이면 끄고 0이 아니면 켭니다. 특히 2도 켜짐입니다. 하위 비트가 아니라 값이 0인지 검사합니다.

반환값

위 비트 배치에 따른 속성 필드 또는 조합된 속성 바이트(u8).

사용 조건과 제한

이 매크로는 u8 값만 계산하며 VRAM이나 레지스터에 쓰지 않습니다. 각 인수는 한 번씩 나타납니다. 결과는 CGB 속성 쓰기 API나 뱅크 1 맵에 직접 써서 적용합니다. DMG는 CGB 맵 속성을 표시하지 않습니다.

사용 예

c
attr=(u8)(3|KQ_CGB_ATTR_PRIORITY_IF(enabled)); // Keep nonzero BG pixels in front of sprites.
if (attr!=131) failures++;
cell(12,11,1,attr);
sprite(7,96,88,2,3); // Red full tile behind the green priority triangle.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

KQ_CGB_ATTR_PRIORITY_IF: --cgb=cgb / DMG
--cgb=cgb / DMG
KQ_CGB_ATTR_PRIORITY_IF: --cgb=cgb / CGB
--cgb=cgb / CGB
KQ_CGB_ATTR_PRIORITY_IF: --cgb=dmg / DMG
--cgb=dmg / DMG
KQ_CGB_ATTR_PRIORITY_IF: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_tile.h:22

KQ_CGB_ATTR_XFLIP_IF

좌우 반전 플래그를 만듭니다. enabled가 0이 아니면 0x20, 0이면 0입니다. CGB 맵 속성으로 쓰면 타일 각 행의 8픽셀을 역순으로 표시하며 저장된 패턴은 바꾸지 않습니다.

사용 형식

c
#define KQ_CGB_ATTR_XFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_XFLIP : 0))

매개변수

enabled

0이면 끄고 0이 아니면 켭니다. 특히 2도 켜짐입니다. 하위 비트가 아니라 값이 0인지 검사합니다.

반환값

위 비트 배치에 따른 속성 필드 또는 조합된 속성 바이트(u8).

사용 조건과 제한

이 매크로는 u8 값만 계산하며 VRAM이나 레지스터에 쓰지 않습니다. 각 인수는 한 번씩 나타납니다. 결과는 CGB 속성 쓰기 API나 뱅크 1 맵에 직접 써서 적용합니다. DMG는 CGB 맵 속성을 표시하지 않습니다.

사용 예

c
attr=(u8)(3|KQ_CGB_ATTR_XFLIP_IF(enabled));
if (attr!=35) failures++;
cell(6,11,1,attr); // Green triangle reflected horizontally.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

KQ_CGB_ATTR_XFLIP_IF: --cgb=cgb / DMG
--cgb=cgb / DMG
KQ_CGB_ATTR_XFLIP_IF: --cgb=cgb / CGB
--cgb=cgb / CGB
KQ_CGB_ATTR_XFLIP_IF: --cgb=dmg / DMG
--cgb=dmg / DMG
KQ_CGB_ATTR_XFLIP_IF: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_tile.h:20

KQ_CGB_ATTR_YFLIP_IF

상하 반전 플래그를 만듭니다. enabled가 0이 아니면 0x40, 0이면 0입니다. CGB 맵 속성에서는 저장된 패턴을 바꾸지 않고 타일의 8행을 역순으로 표시합니다.

사용 형식

c
#define KQ_CGB_ATTR_YFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_YFLIP : 0))

매개변수

enabled

0이면 끄고 0이 아니면 켭니다. 특히 2도 켜짐입니다. 하위 비트가 아니라 값이 0인지 검사합니다.

반환값

위 비트 배치에 따른 속성 필드 또는 조합된 속성 바이트(u8).

사용 조건과 제한

이 매크로는 u8 값만 계산하며 VRAM이나 레지스터에 쓰지 않습니다. 각 인수는 한 번씩 나타납니다. 결과는 CGB 속성 쓰기 API나 뱅크 1 맵에 직접 써서 적용합니다. DMG는 CGB 맵 속성을 표시하지 않습니다.

사용 예

c
attr=(u8)(1|KQ_CGB_ATTR_YFLIP_IF(enabled));
if (attr!=65) failures++;
cell(8,11,1,attr); // Red triangle reflected vertically.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 타일 패턴에도 BG와 OBJ의 별도 팔레트가 적용됨을 배우는 프로그램입니다. 각 삼각형은 8 × 8픽셀로, 맨 위 왼쪽 한 픽셀에서 맨 아래 8픽셀까지 넓어집니다. x = 16, 32, 48, 64, 80, 96, 112에서 y = 24의 BG 행은 빨강·파랑·초록·빨강·파랑·초록·빨강, y = 64의 OBJ 행은 파랑·초록·빨강·파랑·초록·빨강·파랑입니다. 각 열은 한 색, RGB 성분, 인덱스 범위, 전체 팔레트, 절대 범위, 기본 레지스터 이름, 별칭 레지스터 이름을 차례로 사용합니다.

y = 88의 8 × 8칸 일곱 개는 x = 16부터 차례로 빨간 삼각형, 뱅크 1의 파란 1픽셀 두께 사각 테두리(32), 좌우 반전한 초록 삼각형(48), 상하 반전한 빨간 삼각형(64), 양방향 반전한 파란 삼각형(80), 빨간 스프라이트 앞의 초록 삼각형(96), 우선순위 비교용으로 BG 앞을 덮는 빨간 정사각형 스프라이트(112)입니다. x = 96에서는 BG 색 번호 0 부분으로 빨강이 보입니다. 좌표는 화면 왼쪽 위 기준의 픽셀 단위이며 여백은 흰색, 글자는 검은색입니다.

FAILED CHECKS 000은 RGB 마스크, 2를 포함한 참·거짓 플래그, 팔레트 인덱스 순환, 팔레트 경계를 넘는 쓰기, 슬롯 31에서 제한, null·길이 0 무동작, LCD를 끈 상태의 색 읽기 검사가 통과했음을 뜻합니다. 겸용 ROM의 DMG/CGB 실행, DMG 전용의 DMG 실행, CGB 전용의 CGB 실행 등 네 조합을 검사합니다. DMG에서는 CGB MODE가 0이고 삼각형은 검정이며 뱅크·반전 속성은 표시를 바꾸지 않고 맨 아래 마지막 두 칸은 검은 정사각형입니다. CGB 검사에서는 CGB MODE가 1입니다. 실기와 LCD 표시 중 팔레트 접근 충돌은 검사하지 않았습니다.

KQ_CGB_ATTR_YFLIP_IF: --cgb=cgb / DMG
--cgb=cgb / DMG
KQ_CGB_ATTR_YFLIP_IF: --cgb=cgb / CGB
--cgb=cgb / CGB
KQ_CGB_ATTR_YFLIP_IF: --cgb=dmg / DMG
--cgb=dmg / DMG
KQ_CGB_ATTR_YFLIP_IF: --cgb=cgb_only / CGB
--cgb=cgb_only / CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\cgb_palette_attributes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\cgb_palette_attributes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/cgb_tile.h:21

chain.h — 위치 이력용 링 버퍼

관절로 이어진 뱀이나 밧줄에는 ChainBody를, 위치 이력 기록에는 Chain을 사용하세요. 몸체의 각 관절은 현재 위치와 16방향 중 하나를 저장하며, 굽힘은 갱신할 때마다 한 관절씩 뒤로 전달됩니다. 몸체 연산은 필드 경계 래핑, 꼬리 복제로 길이 늘리기, 축마다 최대 2픽셀의 보정을 지원합니다.

chain_wrap_delta

양 끝이 연결된 축에서 현재 위치부터 목표까지의 가장 짧은 부호 있는 변위를 계산합니다. 필드 경계를 넘는 추적이나 거리 비교에 사용하세요.

사용 형식

c
s16 chain_wrap_delta(u8 target, u8 current, u16 size);

매개변수

target

목표 좌표이며, 범위는 0~size−1입니다.

current

현재 좌표이며, 범위는 0~size−1입니다.

size

경계가 이어지는 축 길이 1~256입니다. X에는 너비, Y에는 높이를 사용합니다. 256을 표현할 수 있도록 16비트 인수입니다.

반환값

최단 변위를 s16으로 반환합니다. 좌표가 증가하는 방향은 양수, 감소하는 방향은 음수, 같은 위치는 0입니다. 유효한 입력의 결과는 −128~+128입니다. 화면 좌표에서는 오른쪽과 아래 방향이 양수입니다.

사용 조건과 제한

chain.h를 포함하고 chain.c를 정확히 한 번 컴파일하세요. Chain이나 ChainBody를 초기화할 필요는 없습니다. 이 함수는 변위만 계산하며 좌표 배열, 관절 수, 화면을 변경하지 않습니다.

입력을 검사하거나 정규화하지 않습니다. size=0, size>256 또는 size 이상의 좌표를 전달하지 마세요. 더 큰 좌표계에서 온 좌표는 호출 전에 0~size−1로 래핑하세요.

양쪽 경로 길이가 같으면 직접 계산한 target−current의 부호를 유지합니다. size=160일 때 0→80은 +80, 80→0은 −80입니다. size=1이면 유효한 좌표는 0뿐이며 결과도 0입니다.

사용 예

c
distances[0]=chain_wrap_delta(1,159,160);   // +2: cross the right edge.
    distances[1]=chain_wrap_delta(159,1,160);   // -2: cross the left edge.
    distances[2]=chain_wrap_delta(80,0,160);    // +80: keep the direct sign.
    distances[3]=chain_wrap_delta(0,80,160);    // -80: same-length routes.
    distances[4]=chain_wrap_delta(0,0,1);       // 0: the only valid position.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

경계 래핑 좌표를 보여 주는 예제입니다. 각 화살표는 현재 위치에서 목표로 향합니다. 너비 160의 경계 통과는 +02/−02, 필드 절반은 +80/−80, 너비 1은 +00으로 표시합니다. 앞의 0은 10진수 자리 채움입니다. 이 예제는 오브젝트를 그리거나 움직이지 않습니다.

chain_wrap_delta: DMG
DMG
chain_wrap_delta: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_wrap.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_wrap.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/chain.h:35

선언 주석 원문
Return target minus current along the shortest wrapped route.
Supply size 1..256 and coordinates in 0..size-1; inputs are not normalized.
Exactly half a field retains the direct displacement sign.

kitaqgb/lib/chain.c:98

c
s16 chain_wrap_delta(u8 target, u8 current, u16 size)
{
    s16 delta;
    s16 half;
    delta = (s16)((s16)target - (s16)current);
    half = (s16)(size >> 1);
    // At exactly half a field, retain the sign of the direct displacement.
    if (delta > half) delta = (s16)(delta - (s16)size);
    else if (delta < (s16)(0 - half)) delta = (s16)(delta + (s16)size);
    return delta;
}
chain_body_init

메모리를 할당하지 않고 호출자가 소유한 관절 배열 3개를 연결한 뒤 관절 수를 0으로 설정합니다.

사용 형식

c
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);

매개변수

body

대상 ChainBody입니다. null은 무시합니다. 초기화 함수 외에는 초기화된 상태를 전달하세요.

x

관절 X 좌표 배열입니다.

y

관절 Y 좌표 배열입니다.

heading

관절 방향 배열입니다.

capacity

할당한 배열 길이 1~255입니다.

width

경계가 이어지는 필드 너비 1~256입니다.

height

경계가 이어지는 필드 높이 1~256입니다.

반환값

성공하면 1, 인수가 유효하지 않으면 0을 반환합니다. null이 아닌 몸체에서 실패하면 capacity와 count를 0으로 설정하여 갱신을 비활성화합니다.

사용 조건과 제한

chain.h를 포함하고 chain.c를 정확히 한 번 컴파일하세요. ChainBody는 각 관절의 현재 위치와 방향을 저장합니다. Chain 위치 이력 링과는 별도의 상태 형식입니다.

각각 capacity바이트인 별도의 쓰기 가능한 배열 x, y, heading을 제공하세요. 몸체를 사용하는 동안 배열을 유지해야 합니다. 인덱스 0은 머리이며 count에 포함됩니다. 초기화 후에는 저장 공간 포인터, 용량, 필드 크기를 바꾸지 마세요.

방향은 시계 방향의 16구간입니다. 0=오른쪽, 4=아래, 8=왼쪽, 12=위이며 입력의 하위 4비트만 사용합니다. 화면 좌표는 오른쪽·아래로 증가하고 각 필드 크기는 1~256픽셀입니다.

사용 예

c
chain_body_init(&body,joint_x,joint_y,joint_heading,8,160,144);
    // Eight caller-owned slots, including the head, on a wrapped 160x144 field.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

chain_body_init: DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
chain_body_init: CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/chain.h:53

선언 주석 원문
Attach three non-overlapping capacity-byte arrays. Return 1 on success.
Invalid storage, zero capacity or dimensions outside 1..256 disable the body.

kitaqgb/lib/chain.c:119

c
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height)
{
    if (body == 0) return 0;
    body->x = x;
    body->y = y;
    body->heading = heading;
    body->count = 0;
    body->capacity = 0;
    body->width = width;
    body->height = height;
    if (x == 0 || y == 0 || heading == 0 || capacity == 0) return 0;
    if (width == 0 || width > 256 || height == 0 || height > 256) return 0;
    body->capacity = capacity;
    return 1;
}
chain_body_reset

지정한 머리 뒤에 관절을 배치하여 곧은 초기 자세를 만듭니다.

사용 형식

c
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);

매개변수

body

대상 ChainBody입니다. null은 무시합니다. 초기화 함수 외에는 초기화된 상태를 전달하세요.

count

머리를 포함한 관절 수이며 1~capacity입니다.

head_x

머리 X 좌표이며 필드 너비에 맞게 래핑됩니다.

head_y

머리 Y 좌표이며 필드 높이에 맞게 래핑됩니다.

heading

16구간 체계의 머리 방향입니다.

반환값

성공하면 1을 반환합니다. count가 0이거나 너무 크거나 body가 null이면 자세를 바꾸지 않고 0을 반환합니다.

사용 조건과 제한

chain.h를 포함하고 chain.c를 정확히 한 번 컴파일하세요. ChainBody는 각 관절의 현재 위치와 방향을 저장합니다. Chain 위치 이력 링과는 별도의 상태 형식입니다.

각각 capacity바이트인 별도의 쓰기 가능한 배열 x, y, heading을 제공하세요. 몸체를 사용하는 동안 배열을 유지해야 합니다. 인덱스 0은 머리이며 count에 포함됩니다. 초기화 후에는 저장 공간 포인터, 용량, 필드 크기를 바꾸지 마세요.

방향은 시계 방향의 16구간입니다. 0=오른쪽, 4=아래, 8=왼쪽, 12=위이며 입력의 하위 4비트만 사용합니다. 화면 좌표는 오른쪽·아래로 증가하고 각 필드 크기는 1~256픽셀입니다.

상하좌우 간격은 4픽셀입니다. 중간 방향은 (4,1), (3,3), (1,4) 같은 정수 벡터를 사용하므로 유클리드 거리가 정확히 4픽셀은 아닙니다. 초기 자세가 필드 경계를 넘을 수 있습니다.

사용 예

c
chain_body_reset(&body,7,48,16,0); // Seven joints, facing right.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

chain_body_reset: DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
chain_body_reset: CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/chain.h:57

선언 주석 원문
Seed count joints in a straight pose behind the head; count includes the head.
Return 0 without changing the pose if count is zero or exceeds capacity.
Coordinates wrap to the playfield and headings are masked to 0..15.

kitaqgb/lib/chain.c:135

c
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading)
{
    u8 i;
    u8 x;
    u8 y;
    s16 ox;
    s16 oy;
    if (body == 0) return 0;
    if (count == 0 || count > body->capacity) return 0;
    heading = (u8)(heading & 15);
    x = chain_body_wrap((s16)head_x, body->width);
    y = chain_body_wrap((s16)head_y, body->height);
    ox = chain_body_offset_x(heading);
    oy = chain_body_offset_y(heading);
    i = 0;
    while (i < count) {
        body->x[(__safe_index u8)i] = x;
        body->y[(__safe_index u8)i] = y;
        body->heading[(__safe_index u8)i] = heading;
        x = chain_body_wrap((s16)((s16)x - ox), body->width);
        y = chain_body_wrap((s16)((s16)y - oy), body->height);
        i = (u8)(i + 1);
    }
    body->count = count;
    return 1;
}
chain_body_step

머리 자세를 설정하고 각 관절을 앞 관절 뒤의 연결점으로 조금씩 끌어당깁니다. 방향 변화는 갱신마다 한 관절씩 전파됩니다.

사용 형식

c
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);

매개변수

body

대상 ChainBody입니다. null은 무시합니다. 초기화 함수 외에는 초기화된 상태를 전달하세요.

head_x

머리 X 좌표이며 필드 너비에 맞게 래핑됩니다.

head_y

머리 Y 좌표이며 필드 높이에 맞게 래핑됩니다.

heading

16구간 체계의 머리 방향입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

chain.h를 포함하고 chain.c를 정확히 한 번 컴파일하세요. ChainBody는 각 관절의 현재 위치와 방향을 저장합니다. Chain 위치 이력 링과는 별도의 상태 형식입니다.

각각 capacity바이트인 별도의 쓰기 가능한 배열 x, y, heading을 제공하세요. 몸체를 사용하는 동안 배열을 유지해야 합니다. 인덱스 0은 머리이며 count에 포함됩니다. 초기화 후에는 저장 공간 포인터, 용량, 필드 크기를 바꾸지 마세요.

방향은 시계 방향의 16구간입니다. 0=오른쪽, 4=아래, 8=왼쪽, 12=위이며 입력의 하위 4비트만 사용합니다. 화면 좌표는 오른쪽·아래로 증가하고 각 필드 크기는 1~256픽셀입니다.

앞 관절의 갱신된 위치로 목표 연결점을 구한 뒤, 각 축에서 경계를 고려한 최단 변위를 계산합니다. 변위가 0이면 이동하지 않고, 크기 1~4는 1픽셀, 5 이상은 2픽셀 이동합니다. 정확히 필드 절반이면 원래 변위의 부호를 유지합니다.

각 관절의 갱신 전 저장된 방향을 다음 관절로 전달하여 굽힘이 몸체를 따라 이동하게 합니다. 빈 몸체는 변경하지 않습니다.

머리 속도, 가속도, 충돌, 그리기, 대기는 호출자가 처리합니다. 보통 머리를 먼저 갱신하고 시뮬레이션 틱마다 chain_body_step을 한 번 호출하세요. 관절 추적 기능이며, 강체나 정확한 길이 제약을 푸는 솔버는 아닙니다.

사용 예

c
chain_body_step(&body,48,20,4); // The head turns down; only joint 1 receives 4.
    show_pose(8,34);
    for(step=1;step<4;step++) {
        chain_body_step(&body,48,(u8)(20+step),4);
    }
    // After four ticks, the new heading has reached joints 1 through 4.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

chain_body_step: DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
chain_body_step: CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/chain.h:62

선언 주석 원문
Install the caller's head pose, then pull joints from front to rear.
Each joint aims four pixels behind its updated predecessor and receives that
predecessor's OLD heading. Each axis moves 1 pixel, or 2 when error exceeds 4.
Call once per simulation tick; this does not advance head physics or render.

kitaqgb/lib/chain.c:162

c
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading)
{
    u8 i;
    u8 previous;
    u8 pull;
    u8 old;
    u8 x;
    u8 y;
    u8 tx;
    u8 ty;
    s16 sx;
    s16 sy;
    if (body == 0) return;
    if (body->count == 0) return;
    heading = (u8)(heading & 15);
    body->x[0] = chain_body_wrap((s16)head_x, body->width);
    body->y[0] = chain_body_wrap((s16)head_y, body->height);
    body->heading[0] = heading;
    pull = heading;
    i = 1;
    while (i < body->count) {
        previous = (u8)(i - 1);
        old = body->heading[(__safe_index u8)i];
        x = body->x[(__safe_index u8)i];
        y = body->y[(__safe_index u8)i];
        tx = chain_body_wrap((s16)((s16)body->x[(__safe_index u8)previous] - chain_body_offset_x(pull)), body->width);
        ty = chain_body_wrap((s16)((s16)body->y[(__safe_index u8)previous] - chain_body_offset_y(pull)), body->height);
        sx = chain_body_correction(chain_wrap_delta(tx, x, body->width));
        sy = chain_body_correction(chain_wrap_delta(ty, y, body->height));
        body->heading[(__safe_index u8)i] = pull;
        body->x[(__safe_index u8)i] = chain_body_wrap((s16)((s16)x + sx), body->width);
        body->y[(__safe_index u8)i] = chain_body_wrap((s16)((s16)y + sy), body->height);
        // Save before overwriting: a bend advances by one joint per update.
        pull = old;
        i = (u8)(i + 1);
    }
}
chain_body_grow

꼬리의 현재 위치와 방향을 다음 빈 슬롯에 복사하고 개수를 1 늘립니다.

사용 형식

c
u8 chain_body_grow(ChainBody* body);

매개변수

body

대상 ChainBody입니다. null은 무시합니다. 초기화 함수 외에는 초기화된 상태를 전달하세요.

반환값

관절을 추가하면 1을 반환합니다. 몸체가 비어 있거나 가득 찼거나 비활성 또는 null이면 0입니다.

사용 조건과 제한

chain.h를 포함하고 chain.c를 정확히 한 번 컴파일하세요. ChainBody는 각 관절의 현재 위치와 방향을 저장합니다. Chain 위치 이력 링과는 별도의 상태 형식입니다.

각각 capacity바이트인 별도의 쓰기 가능한 배열 x, y, heading을 제공하세요. 몸체를 사용하는 동안 배열을 유지해야 합니다. 인덱스 0은 머리이며 count에 포함됩니다. 초기화 후에는 저장 공간 포인터, 용량, 필드 크기를 바꾸지 마세요.

방향은 시계 방향의 16구간입니다. 0=오른쪽, 4=아래, 8=왼쪽, 12=위이며 입력의 하위 4비트만 사용합니다. 화면 좌표는 오른쪽·아래로 증가하고 각 필드 크기는 1~256픽셀입니다.

새 꼬리는 처음에 이전 꼬리와 겹치고, 이후 chain_body_step 호출로 분리됩니다. 성장 자체는 머리나 다른 관절을 움직이지 않습니다.

사용 예

c
chain_body_grow(&body); // Copy the tail pose into the eighth slot.
    chain_body_step(&body,48,16,0);
    chain_body_step(&body,48,16,0);
    chain_body_step(&body,48,16,0);
    chain_body_step(&body,48,16,0); // Allow the duplicated tail to separate.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

chain_body_grow: DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
chain_body_grow: CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/chain.h:65

선언 주석 원문
Append a copy of the current tail; later steps separate the new joint.
Return 1 on growth, or 0 for an empty, disabled or full body.

kitaqgb/lib/chain.c:200

c
u8 chain_body_grow(ChainBody* body)
{
    u8 tail;
    u8 next;
    if (body == 0) return 0;
    next = body->count;
    if (next == 0 || next >= body->capacity) return 0;
    tail = (u8)(next - 1);
    body->x[(__safe_index u8)next] = body->x[(__safe_index u8)tail];
    body->y[(__safe_index u8)next] = body->y[(__safe_index u8)tail];
    body->heading[(__safe_index u8)next] = body->heading[(__safe_index u8)tail];
    body->count = (u8)(next + 1);
    return 1;
}
chain_body_clear

배열과 필드 설정을 유지하면서 관절 수를 0으로 설정합니다.

사용 형식

c
void chain_body_clear(ChainBody* body);

매개변수

body

대상 ChainBody입니다. null은 무시합니다. 초기화 함수 외에는 초기화된 상태를 전달하세요.

반환값

반환값은 없습니다.

사용 조건과 제한

chain.h를 포함하고 chain.c를 정확히 한 번 컴파일하세요. ChainBody는 각 관절의 현재 위치와 방향을 저장합니다. Chain 위치 이력 링과는 별도의 상태 형식입니다.

각각 capacity바이트인 별도의 쓰기 가능한 배열 x, y, heading을 제공하세요. 몸체를 사용하는 동안 배열을 유지해야 합니다. 인덱스 0은 머리이며 count에 포함됩니다. 초기화 후에는 저장 공간 포인터, 용량, 필드 크기를 바꾸지 마세요.

방향은 시계 방향의 16구간입니다. 0=오른쪽, 4=아래, 8=왼쪽, 12=위이며 입력의 하위 4비트만 사용합니다. 화면 좌표는 오른쪽·아래로 증가하고 각 필드 크기는 1~256픽셀입니다.

배열 바이트는 지우지 않습니다. 다시 시작하려면 chain_body_reset을 사용하세요. 비운 직후 chain_body_grow를 호출해도 관절은 추가되지 않습니다.

사용 예

c
chain_body_clear(&body); // Forget the pose; the three arrays remain owned by us.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

chain_body_clear: DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
DMG — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
chain_body_clear: CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.
CGB — 이미지 위쪽은 곧은 몸체, 가운데는 아래로 방향을 바꾼 뒤 한 번 갱신한 모습, 아래쪽은 네 번 갱신한 모습입니다. 좌표는 논리 크기의 두 배로 그립니다. 굽힘은 오른쪽 머리에서 뒤로 전달됩니다. CGB와 FC는 머리를 빨강, 몸통을 파랑, 꼬리를 초록으로 표시하며 DMG는 검은색입니다. 성장 후 네 번 안정화 갱신을 하면 겹친 꼬리가 분리됩니다. 이는 같은 여덟 관절의 세 상태이며, 관절 24개짜리 몸체 하나가 아닙니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\chain_body.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\chain_body.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/chain.h:67

선언 주석 원문
Remove all joints while retaining caller-owned storage and playfield settings.

kitaqgb/lib/chain.c:215

c
void chain_body_clear(ChainBody* body)
{
    if (body == 0) return;
    body->count = 0;
}
chain_clear

기록된 이력을 비워 같은 저장 배열을 다시 사용할 수 있게 합니다.

사용 형식

c
void chain_clear(Chain* chain);

매개변수

chain

초기화된 Chain을 가리키는 포인터입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

저장 배열을 지우거나 해제하지 않고 개수와 head를 0으로 초기화합니다. Chain과 점 배열은 호출 측이 소유하며 사용 중 계속 유효해야 합니다. 읽기 함수의 8비트 인덱스 덧셈이 넘치지 않도록 용량은 128 이하로 지정하세요.

GB 버전에는 유효한 chain 포인터가 필요합니다.

사용 예

c
chain_clear(&trail);result[11]=chain_get_count(&trail);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 점 네 개의 이력을 비우고 개수가 0이 되는지 확인합니다.

chain_clear: DMG
DMG
chain_clear: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/chain.h:21

선언 주석 원문
Forget the recorded points without clearing or freeing the backing storage.

kitaqgb/lib/chain.c:14

c
void chain_clear(Chain* chain)
{
    chain->count = 0;
    chain->head = 0;
}
chain_get_count

현재 이력에서 읽을 수 있는 위치의 개수를 반환합니다.

사용 형식

c
u8 chain_get_count(const Chain* chain);

매개변수

chain

초기화된 Chain을 가리키는 포인터입니다.

반환값

0부터 용량까지의 개수를 반환합니다. chain이 NULL이면 0입니다.

사용 조건과 제한

Chain과 점 배열은 호출 측이 소유하며 사용 중 계속 유효해야 합니다. 읽기 함수의 8비트 인덱스 덧셈이 넘치지 않도록 용량은 128 이하로 지정하세요.

사용 예

c
result[4]=chain_get_count(&trail);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

네 슬롯에 다섯 번 추가해도 개수는 4입니다. 비우면 0이 되며, 용량이 0인 이력에서는 계속 0입니다.

chain_get_count: DMG
DMG
chain_get_count: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/chain.h:30

선언 주석 원문
Return the number of stored points, or zero for a null chain.

kitaqgb/lib/chain.c:63

c
u8 chain_get_count(const Chain* chain)
{
    if (chain == 0) return 0;
    return chain->count;
}
chain_get_segment

얼마나 오래된 점인지 지정하여 저장된 위치를 읽습니다.

사용 형식

c
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);

매개변수

chain

초기화된 Chain을 가리키는 포인터입니다.

index

점의 이력 인덱스입니다. 0이 최신 점이며 count - 1이 남아 있는 가장 오래된 점입니다.

out

결과를 받을 별도의 쓰기 가능한 ChainPoint입니다. NULL이면 실패합니다.

반환값

성공하면 1, 요청이 유효하지 않으면 0을 반환합니다. out이 NULL이 아니면 유효성 검사 전에 (0,0)으로 초기화합니다.

사용 조건과 제한

out이 저장 배열이나 Chain과 같은 메모리를 가리키면 안 됩니다. 출력을 초기화하면서 소스 데이터가 손상되기 때문입니다. Chain과 점 배열은 호출 측이 소유하며 사용 중 계속 유효해야 합니다. 읽기 함수의 8비트 인덱스 덧셈이 넘치지 않도록 용량은 128 이하로 지정하세요.

사용 예

c
result[1]=chain_get_segment(&trail,0,&point);result[2]=point.x;result[3]=point.y;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

인덱스 0은 최신 점 (40,24), 인덱스 3은 가장 오래된 점 (16,8)을 읽습니다. 유효하지 않은 인덱스 4는 실패를 반환하고 출력은 (0,0)이 됩니다.

chain_get_segment: DMG
DMG
chain_get_segment: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/chain.h:28

선언 주석 원문
Read a point by age, with index zero denoting the newest point. Return zero
for an invalid request and clear a non-null output first. Keep head + index
within the 8-bit range: addition is narrowed before the capacity wrap.

kitaqgb/lib/chain.c:40

c
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out)
{
    u8 pos;
    if (out != 0) {
        out->x = 0;
        out->y = 0;
    }

    if (out == 0) return 0;
    if (chain == 0) return 0;
    if (chain->capacity == 0) return 0;
    if (index >= chain->count) return 0;

    pos = (u8)(chain->head + index);
    while (pos >= chain->capacity) {
        pos = (u8)(pos - chain->capacity);
    }
    out->x = chain->points[pos].x;
    out->y = chain->points[pos].y;
    return 1;
}
chain_init

위치 이력용 순환 버퍼에 저장 공간을 연결하고, 기록된 점이 없는 상태로 시작합니다.

사용 형식

c
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);

매개변수

chain

초기화할 쓰기 가능한 Chain입니다.

storage

ChainPoint 항목을 capacity개 담을 수 있는 배열입니다.

capacity

점 슬롯 수입니다. 이력을 사용하려면 1~128을 지정하세요. 0이면 기록하지 않습니다.

반환값

반환값은 없습니다.

사용 조건과 제한

Chain과 점 배열은 호출 측이 소유하며 사용 중 계속 유효해야 합니다. 읽기 함수의 8비트 인덱스 덧셈이 넘치지 않도록 용량은 128 이하로 지정하세요.

GB 버전에는 유효한 chain 포인터가 필요합니다.

사용 예

c
chain_init(&trail,storage,4);result[0]=chain_get_count(&trail);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 점 슬롯 네 개를 연결하고 초기 개수가 0인지 검사합니다.

chain_init: DMG
DMG
chain_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/chain.h:19

선언 주석 원문
Attach caller-owned ring storage and start with no recorded points.
The storage must remain valid for the lifetime of the chain.
Use a valid chain pointer and capacity entries of caller-owned storage.
Capacity at most 128 keeps every head+age sum in the byte range used by the reader.

kitaqgb/lib/chain.c:5

c
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity)
{
    chain->points = storage;
    chain->capacity = capacity;
    chain->count = 0;
    chain->head = 0;
}
chain_push_head

이력의 head에 최신 위치를 추가합니다. 가득 찬 경우 가장 오래된 점을 덮어씁니다.

사용 형식

c
void chain_push_head(Chain* chain, s16 x, s16 y);

매개변수

chain

초기화된 Chain을 가리키는 포인터입니다.

x

새 점의 부호 있는 X 좌표입니다.

y

새 점의 부호 있는 Y 좌표입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

chain이 NULL이거나 용량이 0이면 아무 작업도 하지 않습니다. Chain과 점 배열은 호출 측이 소유하며 사용 중 계속 유효해야 합니다. 읽기 함수의 8비트 인덱스 덧셈이 넘치지 않도록 용량은 128 이하로 지정하세요.

사용 예

c
chain_push_head(&trail,8,8);chain_push_head(&trail,16,8);chain_push_head(&trail,24,16);chain_push_head(&trail,32,16);chain_push_head(&trail,40,24);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

네 슬롯에 다섯 번 추가하면 최신 점은 (40,24), 남아 있는 가장 오래된 점은 (16,8)이 됩니다. 원래의 (8,8)은 덮어써집니다.

chain_push_head: DMG
DMG
chain_push_head: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_chain.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_chain.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/chain.h:24

선언 주석 원문
Move the ring head backward and store the newest point. Once full, each push
replaces the oldest point; zero capacity is a no-op.

kitaqgb/lib/chain.c:22

c
void chain_push_head(Chain* chain, s16 x, s16 y)
{
    if (chain == 0) return;
    if (chain->capacity == 0) return;

    if (chain->head == 0) chain->head = (u8)(chain->capacity - 1);
    else chain->head--;

    chain->points[chain->head].x = x;
    chain->points[chain->head].y = y;

    if (chain->count < chain->capacity) chain->count++;
}

danmaku.h — 탄환 풀, 부채꼴 발사, 충돌, 스침

160×128픽셀 영역에서 최대 96발을 처리하는 동적 할당 없는 탄막 기능입니다. 1/16픽셀 이동, 32방향 부채꼴, 충돌·스침 이벤트, 네 사분면 타일 합성을 제공합니다. 시뮬레이션은 GB에서 실행되며, present_now 전송은 CGB 전용입니다.

danmaku_clear

모든 탄환을 비활성화하고 활성 개수, 현재 충돌·스침 이벤트, 할당 커서를 지웁니다.

사용 형식

c
void danmaku_clear();

반환값

반환값은 없습니다.

사용 조건과 제한

최대값과 누적 카운터는 유지합니다. 화면에서 탄환을 지우려면 RAM 맵을 지운 뒤 전송하세요.

사용 예

c
danmaku_clear();result[6]=dm_count;result[7]=dm_spawned;result[8]=dm_peak;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

CGB 전용 그리기 예제입니다. (80,64)에서 여덟 방향으로 생성하고 여덟 번 갱신하여 방사형으로 배치된 빨간 3×3 점 여덟 개를 표시합니다. 상하좌우 탄환은 32픽셀 이동하고, 대각선은 정수 근사를 사용합니다. 풀 비우기와 누적 생성 수 유지도 검사합니다.

danmaku_clear: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/danmaku.h:35

선언 주석 원문
Deactivate the pool while retaining peak/spawn/rejection counters and the RAM map.

kitaqgb/lib/danmaku.c:28

c
void danmaku_clear() {
    u8 i;
    for (i=0; i<DANMAKU_MAX; i++) dm_bullets[i].active=0;
    dm_count=0; dm_hit=0; dm_graze=0; dm_cursor=0;
}
danmaku_clear_map

32×18 RAM 타일 맵의 576바이트를 모두 지웁니다.

사용 형식

c
void danmaku_clear_map();

반환값

반환값은 없습니다.

사용 조건과 제한

탄환 상태와 VRAM은 변경하지 않습니다. 매 프레임 clear_map, 장식 기록, step, 전송 순서로 처리하세요.

사용 예

c
danmaku_clear_map();result[11]=dm_map[0];

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

CGB 전용 그리기 예제입니다. (80,64)에서 여덟 방향으로 생성하고 여덟 번 갱신하여 방사형으로 배치된 빨간 3×3 점 여덟 개를 표시합니다. 상하좌우 탄환은 32픽셀 이동하고, 대각선은 정수 근사를 사용합니다. 풀 비우기와 누적 생성 수 유지도 검사합니다.

danmaku_clear_map: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/danmaku.h:42

선언 주석 원문
32 directions, 0=right, 8=down, 16=left, 24=up. speed in 1/16 px.
Clear the 32x18 RAM map before drawing the next frame; no transfer is performed.

kitaqgb/lib/danmaku.c:78

c
void danmaku_clear_map() {
    __asm {
        LD_HL_IMM dm_map
        LD_B_IMM 72
        XOR_A
    dm_clm_loop:
        LDI_HL_A
        LDI_HL_A
        LDI_HL_A
        LDI_HL_A
        LDI_HL_A
        LDI_HL_A
        LDI_HL_A
        LDI_HL_A
        DEC_B
        JR_NZ dm_clm_loop
        RET
    }
}
danmaku_fan

32방향 속도 테이블과 일정한 각도 간격으로 부채꼴 탄막을 만듭니다.

사용 형식

c
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);

매개변수

x

초기 X 좌표로, 범위는 0~159픽셀입니다.

y

초기 Y 좌표로, 범위는 0~127픽셀입니다.

direction

시작 각도이며 하위 5비트만 사용합니다. 0=오른쪽, 8=아래, 16=왼쪽, 24=위입니다.

step

탄환마다 더할 각도입니다. 32방향 안에서 순환합니다.

count

시도 횟수이며, 최대 96으로 제한합니다.

speed

1/16픽셀 단위의 속도이며, 최대 64(갱신당 4픽셀)입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

풀이 가득 차도 남은 생성 시도를 계속합니다. 정수 sin/cos 테이블 때문에 대각선 이동에는 반올림 오차가 생깁니다.

사용 예

c
danmaku_fan(80,64,0,4,8,64);result[9]=dm_count;result[10]=dm_spawned;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

CGB 전용 그리기 예제입니다. (80,64)에서 여덟 방향으로 생성하고 여덟 번 갱신하여 방사형으로 배치된 빨간 3×3 점 여덟 개를 표시합니다. 상하좌우 탄환은 32픽셀 이동하고, 대각선은 정수 근사를 사용합니다. 풀 비우기와 누적 생성 수 유지도 검사합니다.

danmaku_fan: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/danmaku.h:39

선언 주석 원문
Attempt a fan using wrapping 32-step angles; count is capped at 96 and speed at 64.

kitaqgb/lib/danmaku.c:62

c
void danmaku_fan(u8 x,u8 y,u8 direction,u8 step,u8 count,u8 speed) {
    u8 n;
    u8 a;
    s8 vx;
    s8 vy;
    if(count>DANMAKU_MAX) count=DANMAKU_MAX;
    if(speed>64) speed=64;
    a=direction&31;
    for(n=0;n<count;n++) {
        vx=(s8)(((s16)dm_cos[a]*(s16)speed)>>6);
        vy=(s8)(((s16)dm_sin[a]*(s16)speed)>>6);
        danmaku_spawn(x,y,vx,vy);
        a=(u8)((a+step)&31);
    }
}
danmaku_present_now

CGB GDMA를 사용하여 dm_map의 576바이트 전체를 배경 맵 $9800으로 동기 전송합니다.

사용 형식

c
void danmaku_present_now();

반환값

반환값은 없습니다.

사용 조건과 제한

CGB 전용이며 DMG에서 호출하면 안 됩니다. LCD가 꺼져 있거나 VBlank 시작 시 사용하세요. VRAM 뱅크 0을 선택하며 이전 VBK로 복원하지 않습니다. 타일 0~15의 탄환 그래픽은 애플리케이션에서 제공해야 합니다.

사용 예

c
// CGB general DMA; the LCD is stopped for this complete-map upload.
danmaku_present_now();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

CGB 전용 그리기 예제입니다. (80,64)에서 여덟 방향으로 생성하고 여덟 번 갱신하여 방사형으로 배치된 빨간 3×3 점 여덟 개를 표시합니다. 상하좌우 탄환은 32픽셀 이동하고, 대각선은 정수 근사를 사용합니다. 풀 비우기와 누적 생성 수 유지도 검사합니다.

danmaku_present_now: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/danmaku.h:48

선언 주석 원문
Requires CGB and LCD off or the beginning of VBlank. VBK restored to 0.
Transfers 18 rows (32-byte stride) to BG map 9800 with 36-block GDMA.

kitaqgb/lib/danmaku.c:301

c
void danmaku_present_now() {
    __asm {
        XOR_A
        LDH_MEM_A 0x4F
        LD_HL_IMM dm_map
        LD_A_H
        LDH_MEM_A 0x51
        LD_A_L
        LDH_MEM_A 0x52
        LD_A_IMM 0x18
        LDH_MEM_A 0x53
        XOR_A
        LDH_MEM_A 0x54
        LD_A_IMM 35
        LDH_MEM_A 0x55
        RET
    }
}
danmaku_reset

96발짜리 탄환 풀을 비우고 최대 동시 탄환 수, 누적 생성 수, 풀 부족으로 거부된 횟수를 초기화합니다.

사용 형식

c
void danmaku_reset();

반환값

반환값은 없습니다.

사용 조건과 제한

플레이어 좌표, 무적 상태, RAM 타일 맵은 변경하지 않습니다. 게임 시작 시 별도로 설정하세요.

사용 예

c
danmaku_reset();result[0]=dm_count;result[1]=dm_peak;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

CGB 전용 그리기 예제입니다. (80,64)에서 여덟 방향으로 생성하고 여덟 번 갱신하여 방사형으로 배치된 빨간 3×3 점 여덟 개를 표시합니다. 상하좌우 탄환은 32픽셀 이동하고, 대각선은 정수 근사를 사용합니다. 풀 비우기와 누적 생성 수 유지도 검사합니다.

danmaku_reset: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/danmaku.h:33

선언 주석 원문
Reset pool, peak and lifetime counters; player fields and map contents remain caller-owned state.

kitaqgb/lib/danmaku.c:34

c
void danmaku_reset() {
    danmaku_clear(); dm_peak=0; dm_spawned=0; dm_rejected=0;
}
danmaku_spawn

빈 슬롯을 순환 탐색하여 지정한 위치와 속도의 탄환 하나를 만듭니다.

사용 형식

c
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);

매개변수

x

초기 X 좌표로, 범위는 0~159픽셀입니다.

y

초기 Y 좌표로, 범위는 0~127픽셀입니다.

vx

부호 있는 Q4.4 속도 −128~127입니다. 16은 갱신마다 오른쪽으로 1픽셀 이동합니다.

vy

부호 있는 Q4.4 속도입니다. 양수는 아래로 이동합니다.

반환값

할당하면 1, 좌표가 밖이거나 풀이 가득 차면 0을 반환합니다. 범위 밖의 요청은 dm_rejected를 증가시키지 않습니다.

사용 조건과 제한

위치는 1/16픽셀 단위로 저장합니다. u16 생성·거부 누계는 65535 다음에 래핑됩니다. 동적 할당은 사용하지 않습니다.

사용 예

c
result[2]=danmaku_spawn(40,40,16,0);result[3]=danmaku_spawn(160,40,0,0);result[4]=dm_count;result[5]=dm_rejected;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

CGB 전용 그리기 예제입니다. (80,64)에서 여덟 방향으로 생성하고 여덟 번 갱신하여 방사형으로 배치된 빨간 3×3 점 여덟 개를 표시합니다. 상하좌우 탄환은 32픽셀 이동하고, 대각선은 정수 근사를 사용합니다. 풀 비우기와 누적 생성 수 유지도 검사합니다.

danmaku_spawn: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/danmaku.h:37

선언 주석 원문
Use pixel origins inside 160x128 and signed sixteenth-pixel velocities; return one if a slot was allocated.

kitaqgb/lib/danmaku.c:39

c
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy) {
    u8 n;
    u8 i;
    if (x>=160 || y>=128) return 0;
    for(n=0;n<DANMAKU_MAX;n++) {
        i=dm_cursor;
        dm_cursor++;
        if(dm_cursor>=DANMAKU_MAX) dm_cursor=0;
        if(dm_bullets[i].active==0) {
            dm_bullets[i].x=(s16)((u16)x<<4);
            dm_bullets[i].y=(s16)((u16)y<<4);
            dm_bullets[i].vx=vx; dm_bullets[i].vy=vy;
            dm_bullets[i].active=1; dm_bullets[i].grazed=0;
            dm_count++; dm_spawned++;
            if(dm_count>dm_peak) dm_peak=dm_count;
            return 1;
        }
    }
    dm_rejected++;
    return 0;
}
danmaku_step

모든 탄환을 한 번 이동하고, 범위 밖 탄환을 제거하며, 탄환 타일을 합성하고 충돌·스침을 검사합니다.

사용 형식

c
void danmaku_step();

반환값

반환값은 없습니다.

사용 조건과 제한

그릴 중심 좌표는 4픽셀 격자에 맞춥니다. 각 축의 차이가 8 이하면 첫 스침, 3 이하면 충돌로 판정합니다. 무적은 충돌만 막습니다. dm_hit/dm_graze는 호출마다 초기화하며, 각 탄환은 한 번만 스침을 기록합니다. 타일 ID 0~15는 네 사분면 비트를 나타냅니다. ID 16 이상인 장식 타일이 차지한 칸은 대체됩니다.

사용 예

c
dm_player_x=0;dm_player_y=0;dm_invulnerable=0;for(i=0;i<8;i++){danmaku_clear_map();danmaku_step();}result[12]=dm_count;result[13]=dm_hit;result[14]=dm_graze;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

CGB 전용 그리기 예제입니다. (80,64)에서 여덟 방향으로 생성하고 여덟 번 갱신하여 방사형으로 배치된 빨간 3×3 점 여덟 개를 표시합니다. 상하좌우 탄환은 32픽셀 이동하고, 대각선은 정수 근사를 사용합니다. 풀 비우기와 누적 생성 수 유지도 검사합니다.

danmaku_step: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_danmaku.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_danmaku.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/danmaku.h:45

선언 주석 원문
Caller fills decoration after clear_map, then calls step to overlay bullets.
hit and graze are events for this step. Collision uses rendered centers.

kitaqgb/lib/danmaku.c:99

c
void danmaku_step() {
    // One linear pass. No per-bullet bank calls, multiplication or division.
    // The 8-byte packed public layout is x16,y16,vx8,vy8,active,graze.
    __asm {
        XOR_A
        LD_MEM_A dm_hit
        LD_MEM_A dm_graze
        LD_A_IMM 96
        LD_MEM_A dm_remaining
        LD_HL_IMM dm_bullets
    dm_tick_loop:
        PUSH_HL
        LD_BC_IMM 6
        ADD_HL_BC
        LD_A_HL
        OR_A
        JP_Z dm_tick_next
        DEC_HL
        LD_A_HL
        LD_MEM_A dm_vy
        DEC_HL
        LD_A_HL
        LD_C_A
        LD_B_IMM 0
        AND_IMM 128
        JR_Z dm_tick_xsign
        DEC_B
    // B:C is the sign-extended X velocity. Add to Q12.4 position; high byte >=10 also rejects negative X.
    dm_tick_xsign:
        POP_HL
        PUSH_HL
        LD_A_HL
        ADD_C
        LDI_HL_A
        LD_E_A
        LD_A_HL
        ADC_B
        LDI_HL_A
        CP_IMM 10
        JP_NC dm_tick_kill
        RRCA
        RRCA
        RRCA
        RRCA
        LD_D_A
        LD_A_E
        RRCA
        RRCA
        RRCA
        RRCA
        AND_IMM 15
        OR_D
        LD_MEM_A dm_px
        LD_A_MEM dm_vy
        LD_C_A
        LD_B_IMM 0
        AND_IMM 128
        JR_Z dm_tick_ysign
        DEC_B
    // Apply signed Y velocity similarly; high byte >=8 rejects negative Y and positions at or below 128 pixels.
    dm_tick_ysign:
        LD_A_HL
        ADD_C
        LDI_HL_A
        LD_E_A
        LD_A_HL
        ADC_B
        LDI_HL_A
        CP_IMM 8
        JP_NC dm_tick_kill
        RRCA
        RRCA
        RRCA
        RRCA
        LD_D_A
        LD_A_E
        RRCA
        RRCA
        RRCA
        RRCA
        AND_IMM 15
        OR_D
        LD_MEM_A dm_py
        // Signed differences shifted into 0..16 for a wrap-safe range test.
        // Rendered centers are (pixel & FC)+2. Test a square of radius eight around the player for graze eligibility.
        LD_A_MEM dm_player_x
        LD_C_A
        LD_A_MEM dm_px
        AND_IMM 252
        ADD_A_IMM 10
        SUB_C
        CP_IMM 17
        JR_NC dm_tick_plot
        LD_B_A
        LD_A_MEM dm_player_y
        LD_C_A
        LD_A_MEM dm_py
        AND_IMM 252
        ADD_A_IMM 10
        SUB_C
        CP_IMM 17
        JR_NC dm_tick_plot
        LD_C_A
        INC_HL
        INC_HL
        INC_HL
        LD_A_HL
        OR_A
        JR_NZ dm_tick_check_hit
        LD_A_IMM 1
        LD_HL_A
        LD_A_MEM dm_graze
        INC_A
        LD_MEM_A dm_graze
    // A bullet grazes at most once during its lifetime. Invulnerability suppresses hits, but not first-graze events.
    // The inner hit test uses a square of radius three around the same quantized center.
    dm_tick_check_hit:
        LD_A_MEM dm_invulnerable
        OR_A
        JR_NZ dm_tick_plot
        LD_A_B
        SUB_IMM 5
        CP_IMM 7
        JR_NC dm_tick_plot
        LD_A_C
        SUB_IMM 5
        CP_IMM 7
        JR_NC dm_tick_plot
        LD_A_IMM 1
        LD_MEM_A dm_hit
    // Select one of four quadrant bits from pixel bit 2, then address map[(y>>3)*32+(x>>3)].
    // Decoration IDs >=16 are replaced at occupied cells; bullet IDs 0..15 merge with OR.
    dm_tick_plot:
        LD_A_MEM dm_py
        AND_IMM 4
        AND_IMM 254
        RRCA
        LD_B_A
        LD_A_MEM dm_px
        AND_IMM 4
        AND_IMM 254
        RRCA
        AND_IMM 254
        RRCA
        OR_B
        LD_E_A
        LD_D_IMM 0
        LD_HL_IMM dm_bits
        ADD_HL_DE
        LD_A_HL
        LD_C_A
        LD_A_MEM dm_py
        AND_IMM 120
        LD_L_A
        LD_H_IMM 0
        ADD_HL_HL
        ADD_HL_HL
        LD_A_MEM dm_px
        AND_IMM 254
        RRCA
        AND_IMM 254
        RRCA
        AND_IMM 254
        RRCA
        LD_E_A
        LD_D_IMM 0
        ADD_HL_DE
        LD_DE_IMM dm_map
        ADD_HL_DE
        LD_A_HL
        CP_IMM 16
        JR_C dm_tick_merge
        XOR_A
    dm_tick_merge:
        OR_C
        LD_HL_A
        JR dm_tick_next
    // Restore the saved record base, clear active at offset six and decrement the live count exactly once.
    dm_tick_kill:
        POP_HL
        PUSH_HL
        LD_BC_IMM 6
        ADD_HL_BC
        XOR_A
        LD_HL_A
        LD_A_MEM dm_count
        DEC_A
        LD_MEM_A dm_count
    // Restore the saved base even for inactive or culled bullets, then advance by the fixed eight-byte record size.
    dm_tick_next:
        POP_HL
        LD_BC_IMM 8
        ADD_HL_BC
        LD_A_MEM dm_remaining
        DEC_A
        LD_MEM_A dm_remaining
        JP_NZ dm_tick_loop
        RET
    }
}

debug.h — RAM 기록과 단언

이름, 값, 프레임 태그를 고정 용량의 RAM 로그에 기록합니다. 어설션은 진단 정보를 남기며 실행은 계속됩니다.

debug_assert_fail

어설션 실패 코드를 보관하고 ASSERT 항목 추가를 시도합니다.

사용 형식

c
void debug_assert_fail(u16 code);

매개변수

code

보관할 16비트 오류 식별자입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

실행은 계속됩니다. 로그가 가득 차도 마지막 어설션 코드는 갱신합니다. 로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
debug_assert_fail(42);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 코드 42를 기록하고 로그를 가득 채운 뒤 코드 999를 기록합니다. 개수는 32로 유지되지만 마지막 코드는 999로 바뀝니다.

debug_assert_fail: DMG
DMG
debug_assert_fail: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:33

선언 주석 원문
Record the assertion code and attempt to append an ASSERT entry. This helper
does not halt execution, and the code is retained even if the log is full.

kitaqgb/lib/debug.c:56

c
void debug_assert_fail(u16 code)
{
    kq_debug_last_assert = code;
    debug_push((const u8*)"ASSERT", code);
}
debug_get_last_assert

남은 로그 공간과 관계없이 최근 어설션 코드를 읽습니다.

사용 형식

c
u16 debug_get_last_assert();

반환값

최근 16비트 코드를 반환합니다. 초기화 직후의 값은 0입니다.

사용 조건과 제한

0은 초기값이기도 하므로 코드 0으로 기록한 실패와 구분할 수 없습니다. 읽어도 코드는 지워지지 않습니다.

사용 예

c
result[22]=debug_get_last_assert();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 어설션 매크로의 77, 로그가 가득 찬 뒤의 999, 재초기화 후의 0을 확인합니다.

debug_get_last_assert: DMG
DMG
debug_get_last_assert: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:39

선언 주석 원문
Read the last recorded assertion code, or the zero value installed by initialization.

kitaqgb/lib/debug.c:75

c
u16 debug_get_last_assert()
{
    return kq_debug_last_assert;
}
debug_get_trace_count

추적 배열의 유효한 항목 수를 읽습니다.

사용 형식

c
u8 debug_get_trace_count();

반환값

0~DEBUG_TRACE_MAX 범위의 개수를 반환합니다.

사용 조건과 제한

로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
result[1]=debug_get_trace_count();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 처음 열 개의 항목과, 추가 기록 후의 상한 32를 확인합니다. 가득 차도 개수는 순환하여 0으로 돌아가지 않습니다.

debug_get_trace_count: DMG
DMG
debug_get_trace_count: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:35

선언 주석 원문
Return the number of valid entries in the fixed trace buffer.

kitaqgb/lib/debug.c:63

c
u8 debug_get_trace_count()
{
    return kq_debug_trace_count;
}
debug_get_trace_log

기록된 이름, 값, 프레임 태그를 확인할 수 있도록 내부 배열의 참조를 얻습니다.

사용 형식

c
const DebugTraceEntry* debug_get_trace_log();

반환값

내부 DebugTraceEntry 배열의 읽기 전용 포인터를 반환합니다.

사용 조건과 제한

복사본이 아닙니다. debug_get_trace_count()가 반환한 개수만큼만 읽으세요. 초기화 후 남아 있는 이전 바이트는 유효한 레코드가 아닙니다. 로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
entries=debug_get_trace_log();for(i=0;i<10;i++){result[2+i]=entries[i].value;result[12+i]=entries[i].frame;}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 열 개 항목의 값과 프레임 필드를 모두 읽고, BEGIN 이름의 첫 글자가 B인지 확인합니다.

debug_get_trace_log: DMG
DMG
debug_get_trace_log: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:37

선언 주석 원문
Expose the internal trace array for inspection; use the count to bound reads.

kitaqgb/lib/debug.c:69

c
const DebugTraceEntry* debug_get_trace_log()
{
    return kq_debug_trace_log;
}
debug_init

유효한 로그 길이, 프레임 태그, 마지막 어설션 코드를 초기화합니다.

사용 형식

c
void debug_init();

반환값

반환값은 없습니다.

사용 조건과 제한

기존 항목의 바이트는 지우지 않습니다. 첫 항목을 기록하기 전에 호출하세요. 로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
debug_init();result[0]=debug_get_trace_count();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

초기 개수가 0인지 확인한 뒤, 데이터가 있는 로그를 초기화합니다. 이전 배열 값은 남아 있지만 개수와 어설션 코드는 0이 되는지 검사합니다.

debug_init: DMG
DMG
debug_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:22

선언 주석 원문
Reset log length, frame tag and last assertion code; existing entry bytes are not erased.

kitaqgb/lib/debug.c:10

c
void debug_init()
{
    kq_debug_trace_count = 0;
    kq_debug_frame = 0;
    kq_debug_last_assert = 0;
}
debug_mark_frame

처리 흐름의 특정 지점을 식별하도록 이름 있는 프레임 마커를 기록합니다.

사용 형식

c
void debug_mark_frame(const u8* label);

매개변수

label

0으로 끝나는 이름 문자열입니다. 해당 메모리는 확인할 때까지 읽을 수 있어야 합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
debug_mark_frame("BEGIN");

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

BEGIN 마커를 추가하면 프레임 태그 513과 함께 값 65535(0xFFFF)가 기록됩니다.

debug_mark_frame: DMG
DMG
debug_mark_frame: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:26

선언 주석 원문
Append a named frame marker using 0xFFFF as its value.

kitaqgb/lib/debug.c:37

c
void debug_mark_frame(const u8* label)
{
    debug_push(label, 0xFFFF);
}
debug_set_frame

이후 로그 항목에 복사할 프레임 태그를 설정합니다.

사용 형식

c
void debug_set_frame(u16 frame);

매개변수

frame

이후 항목에 사용할 16비트 프레임 번호입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

프레임을 기다리거나 태그를 자동으로 증가시키지 않습니다. 게임의 프레임 카운터를 명시적으로 전달하세요. 로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
debug_set_frame(513);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 태그를 513으로 설정하고 항목 열 개를 기록한 뒤, 열 개의 프레임 필드를 모두 다시 읽어 태그를 확인합니다.

debug_set_frame: DMG
DMG
debug_set_frame: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:24

선언 주석 원문
Set the frame tag copied into subsequently recorded entries.

kitaqgb/lib/debug.c:18

c
void debug_set_frame(u16 frame)
{
    kq_debug_frame = frame;
}
debug_trace_u16

이름을 붙여 16비트 점수나 카운터를 기록합니다.

사용 형식

c
void debug_trace_u16(const u8* name, u16 value);

매개변수

name

0으로 끝나는 이름 문자열입니다. 해당 메모리는 확인할 때까지 읽을 수 있어야 합니다.

value

기록할 0~65535의 값입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
debug_trace_u16("WORD",4660);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

WORD 항목은 4660(0x1234)을 저장하며, 예제에서 다시 읽어 두 바이트를 모두 확인합니다.

debug_trace_u16: DMG
DMG
debug_trace_u16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:30

선언 주석 원문
Append a 16-bit value with the current frame tag.

kitaqgb/lib/debug.c:49

c
void debug_trace_u16(const u8* name, u16 value)
{
    debug_push(name, value);
}
debug_trace_u8

이름 및 현재 프레임 태그와 함께 8비트 상태값을 기록합니다.

사용 형식

c
void debug_trace_u8(const u8* name, u8 value);

매개변수

name

0으로 끝나는 이름 문자열입니다. 해당 메모리는 확인할 때까지 읽을 수 있어야 합니다.

value

0~255의 값이며, 상위 비트를 0으로 채워 로그의 16비트 필드에 저장합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
debug_trace_u8("BYTE",255);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

BYTE 항목에 255를 기록하고, 로그의 16비트 값 필드에도 255가 들어 있는지 확인합니다.

debug_trace_u8: DMG
DMG
debug_trace_u8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:28

선언 주석 원문
Append an unsigned byte value, widened to the log's 16-bit value field.

kitaqgb/lib/debug.c:43

c
void debug_trace_u8(const u8* name, u8 value)
{
    debug_push(name, (u16)value);
}
KITAQGB_ASSERT

조건이 거짓이면 어설션 코드 1을 기록하는 문장 형태의 매크로입니다.

사용 형식

c
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)

매개변수

cond

성립해야 하는 조건입니다. 0이면 실패입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

조건은 한 번 평가합니다. 참이면 아무것도 기록하지 않고, 거짓이면 실행을 멈추지 않은 채 실패를 기록합니다. do…while (0) 형태이므로 if…else에서 하나의 문장처럼 사용할 수 있습니다.

사용 예

c
KITAQGB_ASSERT(1);KITAQGB_ASSERT(0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

참인 어설션과 거짓인 어설션을 하나씩 실행하면 코드 1인 항목이 정확히 하나 생깁니다.

KITAQGB_ASSERT: DMG
DMG
KITAQGB_ASSERT: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:45

c
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)
KITAQGB_ASSERT_CODE

조건이 거짓일 때만 지정한 어설션 코드를 기록합니다.

사용 형식

c
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)

매개변수

cond

성립해야 하는 조건입니다.

code

실패했을 때 평가하고 16비트로 변환할 코드 식입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

조건은 한 번 평가하고, 코드 식은 실패했을 때만 평가합니다. 기록 후에도 실행은 계속됩니다.

사용 예

c
KITAQGB_ASSERT_CODE(1,++side_effect);KITAQGB_ASSERT_CODE(0,77);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

조건이 참이면 코드 식 ++side_effect는 평가하지 않으며 변수는 0으로 유지됩니다. 조건이 거짓이면 코드 77을 기록합니다.

KITAQGB_ASSERT_CODE: DMG
DMG
KITAQGB_ASSERT_CODE: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:46

c
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)
KITAQGB_MARK_FRAME

이름을 문자열 포인터로 변환하고 값이 0xFFFF인 프레임 마커를 추가합니다.

사용 형식

c
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))

매개변수

label

0으로 끝나는 이름 문자열입니다. 해당 메모리는 확인할 때까지 읽을 수 있어야 합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
KITAQGB_MARK_FRAME("END");

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

END 마커의 값이 65535, 프레임 태그가 513인지 확인합니다.

KITAQGB_MARK_FRAME: DMG
DMG
KITAQGB_MARK_FRAME: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:44

c
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))
KITAQGB_TRACE

값을 명시적으로 16비트로 변환한 뒤 이름과 함께 기록합니다.

사용 형식

c
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))

매개변수

name

0으로 끝나는 이름 문자열입니다. 해당 메모리는 확인할 때까지 읽을 수 있어야 합니다.

value

기록 전에 16비트로 변환할 식입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

매크로는 항상 활성화되어 있으며 빌드 설정으로 자동 비활성화되지 않습니다. 16비트 기록 동작은 KITAQGB_TRACE_U16과 같습니다. 로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
KITAQGB_TRACE("SCORE",600);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 600을 기록합니다. 검증을 위해 로그에서 값을 다시 읽습니다.

KITAQGB_TRACE: DMG
DMG
KITAQGB_TRACE: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:43

c
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
KITAQGB_TRACE_U16

값을 명시적으로 16비트로 변환한 뒤 이름과 함께 기록합니다.

사용 형식

c
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))

매개변수

name

0으로 끝나는 이름 문자열입니다. 해당 메모리는 확인할 때까지 읽을 수 있어야 합니다.

value

기록 전에 16비트로 변환할 식입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

매크로는 항상 활성화되어 있으며 빌드 설정으로 자동 비활성화되지 않습니다. 로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
KITAQGB_TRACE_U16("WORD2",500);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 500을 기록합니다. 검증을 위해 로그에서 값을 다시 읽습니다.

KITAQGB_TRACE_U16: DMG
DMG
KITAQGB_TRACE_U16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:42

c
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
KITAQGB_TRACE_U8

값을 명시적으로 8비트로 변환한 뒤 이름과 함께 기록합니다.

사용 형식

c
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))

매개변수

name

0으로 끝나는 이름 문자열입니다. 해당 메모리는 확인할 때까지 읽을 수 있어야 합니다.

value

기록 전에 8비트로 변환할 식입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

매크로는 항상 활성화되어 있으며 빌드 설정으로 자동 비활성화되지 않습니다. 로그는 기본적으로 32개 항목을 담으며 가득 차면 새 항목을 버립니다. DEBUG_TRACE_MAX를 재정의할 때는 모든 번역 단위에서 동일한 1~255 값을 사용하세요. 이름은 복사하지 않고 포인터로 보관하므로 확인이 끝날 때까지 해당 메모리를 읽을 수 있어야 합니다. 인터럽트와 메인 코드의 쓰기가 겹치지 않도록 호출 측에서 순서를 보장하세요.

사용 예

c
KITAQGB_TRACE_U8("CAST",0x1234);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 52를 기록합니다. 0x1234의 하위 바이트인 0x34만 남습니다.

KITAQGB_TRACE_U8: DMG
DMG
KITAQGB_TRACE_U8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_debug.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_debug.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/debug.h:41

c
#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))

dmg3d.h — DMG용 128×120 단색 와이어프레임

흑백 3D 선 그리기입니다. 모델 정점·모서리·면과 오브젝트 위치·회전·배율을 제공하세요. 초기화, 프레임 시작, 그리기, 업로드 순서로 사용합니다. 물리는 별도입니다. 각도는 한 바퀴당 16단계이고 모델 배율 256이 1배입니다.

Vec3는 x/y/z, Edge는 정점 인덱스 a/b, Face는 삼각형 인덱스 a/b/c를 담습니다. Model의 vertices, edges, faces는 이 배열을 가리키고 각 count는 길이를 나타냅니다. edge_faces에는 인접 면 인덱스 f0/f1이 들어가며, 없는 면은 FACE_NONE입니다. flags의 MODEL_HIDDEN_LINES는 면 기반 모서리 선택을 요청합니다. 투영된 부호 있는 면적으로 면 방향을 결정하므로 정점 순서가 중요합니다.

Object는 모델 참조, 위치 x/y/z, 각도 rx/ry/rz, scale_q8, visible을 저장합니다. 여러 오브젝트가 모델을 공유할 수 있지만 그리기는 테이블을 복사하거나 ROM 뱅크를 자동 전환하지 않습니다. 그리는 동안 참조 데이터를 계속 읽을 수 있어야 합니다. CGB Object에는 색상 인덱스도 있습니다.

DMG3D_BeginFrame

프레임 그리기를 시작하고 가림 검사를 끕니다.

사용 형식

c
void DMG3D_BeginFrame();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 가림 필터만 끕니다. 스테이징 영역은 보통 전송 중에 지워지고 첫 빈 스테이징 영역은 Init이 제공합니다. 아직 제출하지 않은 프레임을 버리거나 마스크를 지우거나 대기 중인 BG 쓰기/변경 플래그를 재설정하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_BeginFrame: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_BeginFrame: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:17

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Disable occlusion filtering only. Stage clearing normally happens during
transfer, and Init supplies the first clean stage. This does not discard an
unsubmitted frame, clear the mask, or reset pending BG writes/dirty flags.

kitaqgb/lib/wire3d_dmg.c:2641

c
void Wire3DDMG_BeginFrame()
{




    /* The consuming stage transfer clears D000 as it uploads, so BeginFrame only
       resets draw state. Wire3DDMG_Init supplies the first clean buffer. */

    w3ddmg_occlusion_active = 0;
}
DMG3D_DrawIndexedEdges

정점과 2바이트 모서리 인덱스 쌍으로 정수 배율의 선 모델을 그립니다.

사용 형식

c
void DMG3D_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale);

매개변수

vertices

3D 정점 배열입니다.

vertex_count

정점 배열의 항목 수입니다.

edges

각 모서리의 정점 인덱스입니다. 선언된 구조체 또는 바이트 쌍 형식을 사용합니다.

edge_count

모서리 수입니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

scale

정수 배율입니다. 0은 1로 처리합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 정수 배율과 이동을 적용한 뒤 바이트 쌍 모서리 인덱스를 그립니다. 배율 0은 1이며 오브젝트 회전이나 면 필터는 없습니다. 정점을 최대 24개 투영합니다. 바이트 오프셋이 255를 넘으면 래핑되므로 모서리 쌍은 최대 128개로 지정하세요. 유효하지 않은 정점 ID와 깊이에서 제외된 끝점은 건너뛰며 null 배열은 무시합니다. 좌표 곱과 합은 s16으로 표현할 수 있어야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        DMG3D_BeginFrame();
    DMG3D_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
    DMG3D_TransferMainNow();
    // Direct auxiliary transfer writes a separate tile after the main upload.
    for(i=24;i<=31;i++) DMG3D_DrawLine2D(40,i,47,i);
    stage_byte=(u8*)0xD518;result[1]=*stage_byte;
    DMG3D_TransferAuxNow();result[2]=*stage_byte;

    // Do not upload the consumed stage again.
    result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

DMG3D_DrawIndexedEdges: DMG — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
DMG — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
DMG3D_DrawIndexedEdges: CGB — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
CGB — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_direct.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:20

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Draw byte-pair edge indices after integer scaling and translation; scale
zero means one, and there is no object rotation or face filtering. Project at
most 24 vertices. Supply at most 128 edge pairs because byte offsets wrap
after 255. Invalid vertex IDs/depth-rejected endpoints are skipped; null arrays
are ignored. Keep coordinate products/sums representable as s16.

kitaqgb/lib/wire3d_dmg.c:3824

c
void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale)
{
    w3ddmg_u8 i;
    w3ddmg_u8 count;

    if (vertices == 0) return;
    if (edges == 0) return;

    count = vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
    if (scale == 0) scale = 1;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)(x + (w3ddmg_i16)(v->x * scale));
        vy = (w3ddmg_i16)(y + (w3ddmg_i16)(v->y * scale));
        vz = (w3ddmg_i16)(z + (w3ddmg_i16)(v->z * scale));

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }

        i = (w3ddmg_u8)(i + 1);
    }

    i = 0;
    while (i < edge_count)
    {
        w3ddmg_u8 a;
        w3ddmg_u8 b;

        a = edges[(__safe_index w3ddmg_u8)((w3ddmg_u8)(i << 1))];
        b = edges[(__safe_index w3ddmg_u8)((w3ddmg_u8)((i << 1) + 1))];
        if ((a < count) && (b < count) &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)a] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)b])
        {
            Wire3DDMG_DrawLine2D(
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)a],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)a],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)b],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)b]);
        }

        i = (w3ddmg_u8)(i + 1);
    }
}
DMG3D_DrawLine2D

양 끝점을 포함하는 4방향 연결 화면 좌표 선을 스테이징 영역에 그립니다.

사용 형식

c
void DMG3D_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 변경 영역 전송이 켜져 있으면 경계 타일 직사각형을 표시한 뒤 스테이징 영역에 연결 선을 그립니다. 장면 그리기는 마스크 샘플 5개로 선을 제외할 수 있습니다. 128×120 뷰포트 안의 끝점을 지정하세요. 저수준 픽셀 경계 검사는 선분의 기하학적 클리핑을 수행하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_DrawLine2D: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_DrawLine2D: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:21

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Mark the bounding tile rectangle when dirty transfer is enabled, then draw
a connected staged line. Scene drawing may reject it using five mask samples.
Supply 128x120 viewport endpoints; low-level pixel bounds checks do not clip
the segment geometrically.

kitaqgb/lib/wire3d_dmg.c:2685

c
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by)
{

    w3ddmg_mark_line_dirty(ax, ay, bx, by);


    if (w3ddmg_occlusion_active)
    {
        w3ddmg_line_stage_masked_c(ax, ay, bx, by);
        return;
    }

    w3ddmg_line_x0 = ax;
    w3ddmg_line_y0 = ay;
    w3ddmg_line_x1 = bx;
    w3ddmg_line_y1 = by;
    if (ax < 128 && bx < 128 && ay < WIRE3D_DMG_SCREEN_H && by < WIRE3D_DMG_SCREEN_H)
        w3ddmg_line_inside_asm();
    else
        w3ddmg_line_stage_asm();
}
DMG3D_DrawLine3D

두 월드 좌표 끝점을 투영하고 그 사이에 선을 그립니다.

사용 형식

c
void DMG3D_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);

매개변수

ax

월드 좌표계에서 시작점의 X 성분입니다.

ay

월드 좌표계에서 시작점의 Y 성분입니다.

az

월드 좌표계에서 시작점의 Z 성분입니다.

bx

월드 좌표계에서 끝점의 X 성분입니다.

by

월드 좌표계에서 끝점의 Y 성분입니다.

bz

월드 좌표계에서 끝점의 Z 성분입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 두 월드 끝점을 투영하고 둘 다 깊이 범위를 통과할 때만 그립니다. 경계를 가로지르는 선분과 근·원평면의 교점을 구하지 않습니다. 투영된 끝점은 각각 화면 가장자리로 제한합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_DrawLine3D: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_DrawLine3D: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:22

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Project both world endpoints and draw only when both pass the depth range.
Do not intersect a crossing segment with near/far planes; projected endpoints
are independently clamped to the screen edges.

kitaqgb/lib/wire3d_dmg.c:2808

c
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz)
{
    w3ddmg_u8 sx0;
    w3ddmg_u8 sy0;
    w3ddmg_u8 sx1;
    w3ddmg_u8 sy1;

    if (w3ddmg_project_world(ax, ay, az, &sx0, &sy0) == 0) return;
    if (w3ddmg_project_world(bx, by, bz, &sx1, &sy1) == 0) return;
    Wire3DDMG_DrawLine2D(sx0, sy0, sx1, sy1);
}
DMG3D_DrawModel

정점과 모서리로 된 모델을 지정한 위치와 회전으로 원래 크기에 그립니다.

사용 형식

c
void DMG3D_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 배율 256으로 DrawModelScaled를 호출하여 크기를 바꾸지 않고 모델을 그립니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom DMG3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
DMG3D_Model cube;
DMG3D_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;

    DMG3D_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    DMG3D_DrawModel(&cube,-32,32,96,0,0,0);
    DMG3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    DMG3D_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    px=16;py=0;pz=0;DMG3D_RotatePoint(&px,&py,&pz,0,4,0);
    result[1]=px; result[2]=py; result[3]=pz;
    DMG3D_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

DMG3D_DrawModel: DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG3D_DrawModel: CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_models.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:23

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Draw an unscaled model by delegating to DrawModelScaled with scale 256.

kitaqgb/lib/wire3d_dmg.c:2827

c
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz)

{
    Wire3DDMG_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}
DMG3D_DrawModelScaled

모델 크기를 조절하고 Y/X/Z 순서로 회전한 뒤 정점을 이동·투영하여 모서리를 그립니다.

사용 형식

c
void DMG3D_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 최대 24개 정점을 크기 조절하고 Y/X/Z 순서로 회전한 뒤 이동·투영합니다. 이어서 선택적 인접 면 필터를 적용하여 바이트형 개수인 edge_count의 모든 항목을 순회합니다. 면 임시 공간은 최대 16개이며, 모서리 테이블에는 선언한 모든 항목이 있어야 합니다. 0 이하의 배율은 256입니다. 모델·정점·모서리 포인터가 null이면 무시합니다. 곱과 이동 결과를 부호 있는 16비트 범위에 유지하세요. 깊이 경계를 가로지르는 모서리는 제외합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom DMG3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
DMG3D_Model cube;
DMG3D_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;

    DMG3D_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    DMG3D_DrawModel(&cube,-32,32,96,0,0,0);
    DMG3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    DMG3D_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    px=16;py=0;pz=0;DMG3D_RotatePoint(&px,&py,&pz,0,4,0);
    result[1]=px; result[2]=py; result[3]=pz;
    DMG3D_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

DMG3D_DrawModelScaled: DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG3D_DrawModelScaled: CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_models.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:24

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Scale up to 24 vertices, rotate Y/X/Z, translate and project, then traverse
all edge_count entries (a byte count) with optional adjacent-face filtering.
Face scratch is capped at 16; edge tables must contain all declared entries.
Nonpositive scale means 256. Null model/vertex/edge pointers are ignored.
Keep products/translations in signed 16-bit range; depth-crossing edges are dropped.

kitaqgb/lib/wire3d_dmg.c:2972

c
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8)

{
    w3ddmg_u8 i;
    w3ddmg_u8 count;
    w3ddmg_u8 edge_count;
    w3ddmg_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->edges == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &model->vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
        vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
        vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);






        w3ddmg_rotate_y(&vx, &vz, ry);
        w3ddmg_rotate_x(&vy, &vz, rx);
        w3ddmg_rotate_z(&vx, &vy, rz);


        vx = (w3ddmg_i16)(vx + x);
        vy = (w3ddmg_i16)(vy + y);
        vz = (w3ddmg_i16)(vz + z);

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }
        i = (w3ddmg_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
    if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
    {
        w3ddmg_build_face_visibility(model, count, face_count);
    }

    edge_count = model->edge_count;




    i = 0;
    while (i < edge_count)
    {
        const Wire3DDMG_Edge* e;
        e = &model->edges[(__safe_index w3ddmg_u8)i];
        if ((e->a < count) && (e->b < count))
        {
            if (w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->a] &&
                w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->b] &&



                w3ddmg_is_edge_visible(model, i, face_count))

            {
                Wire3DDMG_DrawLine2D(
                    w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->a],
                    w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->a],
                    w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->b],
                    w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->b]);
            }
        }
        i = (w3ddmg_u8)(i + 1);
    }
}
DMG3D_DrawScene

가까운 면으로 나중의 모서리를 가리면서 최대 8개 오브젝트를 가까운 순서로 그립니다.

사용 형식

c
void DMG3D_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);

매개변수

objects

위치, 회전, 배율, 표시 여부 플래그를 담은 오브젝트 배열입니다.

count

제공한 배열 항목 수입니다. 실제 처리 상한은 해당 연산의 설명을 참조하세요.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 최대 8개 오브젝트 원점을 카메라 깊이 기준으로 가까운 순서로 정렬합니다. 보이는 유효 모델을 그리고 이후 오브젝트용으로 앞면 경계 직사각형을 등록합니다. 정렬 후 첫 슬롯은 마스크 검사를 생략하고 마지막 슬롯은 새 가림 영역이 필요 없습니다. 깊이 버퍼가 아닌 대략적인 선 제외입니다. null/빈 입력은 무시합니다. 순회 중 호출자 데이터와 현재 투영 캐시는 유효해야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom DMG3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
DMG3D_Model cube;
DMG3D_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;

    DMG3D_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    DMG3D_DrawModel(&cube,-32,32,96,0,0,0);
    DMG3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    DMG3D_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    px=16;py=0;pz=0;DMG3D_RotatePoint(&px,&py,&pz,0,4,0);
    result[1]=px; result[2]=py; result[3]=pz;
    DMG3D_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

DMG3D_DrawScene: DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG3D_DrawScene: CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_models.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:25

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Sort at most eight object origins by camera depth, near to far. Draw visible
valid models and mark front-face bounding rectangles for later objects. The
first sorted slot bypasses mask tests and the last needs no new occluder.
This is coarse line rejection, not a depth buffer. Null/empty input is ignored;
caller data and the current projection cache must remain valid during traversal.

kitaqgb/lib/wire3d_dmg.c:2723

c
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count)
{
    w3ddmg_u8 scene_count;
    w3ddmg_u8 i;

    if (objects == 0) return;

    scene_count = count;
    if (scene_count > WIRE3D_DMG_SCENE_OBJECT_LIMIT) scene_count = WIRE3D_DMG_SCENE_OBJECT_LIMIT;

    if (scene_count == 0) return;


    i = 0;
    while (i < scene_count)
    {
        w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = i;
        w3ddmg_scene_depth[(__safe_index w3ddmg_u8)i] = w3ddmg_scene_object_depth(&objects[(__safe_index w3ddmg_u8)i]);
        i = (w3ddmg_u8)(i + 1);
    }

    i = 0;
    while (i < scene_count)
    {
        w3ddmg_u8 j;
        j = (w3ddmg_u8)(i + 1);
        while (j < scene_count)
        {
            w3ddmg_u8 oi;
            w3ddmg_u8 oj;
            oi = w3ddmg_scene_order[(__safe_index w3ddmg_u8)i];
            oj = w3ddmg_scene_order[(__safe_index w3ddmg_u8)j];





            if (w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oj] < w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oi])
            {
                w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = oj;
                w3ddmg_scene_order[(__safe_index w3ddmg_u8)j] = oi;
            }
            j = (w3ddmg_u8)(j + 1);
        }
        i = (w3ddmg_u8)(i + 1);
    }

    w3ddmg_clear_occlusion_mask();



    w3ddmg_occlusion_active = 0;


    i = 0;
    while (i < scene_count)
    {
        Wire3DDMG_Object* obj;
        obj = &objects[(__safe_index w3ddmg_u8)w3ddmg_scene_order[(__safe_index w3ddmg_u8)i]];
        if ((obj->visible != 0) && (obj->model != 0))
        {




            w3ddmg_occlusion_active = i == 0 ? 0 : 1;
            Wire3DDMG_DrawModelScaled(obj->model, obj->x, obj->y, obj->z, obj->rx, obj->ry, obj->rz, obj->scale_q8);
            if ((w3ddmg_u8)(i + 1) < scene_count)
            {
                w3ddmg_mark_model_occluder(obj->model);
            }

        }
        i = (w3ddmg_u8)(i + 1);
    }

    w3ddmg_occlusion_active = 0;
}
DMG3D_EndFrame

대기 중인 배경 쓰기와 스테이징된 그림을 VRAM에 제출합니다.

사용 형식

c
void DMG3D_EndFrame();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 다음 VBlank를 기다려 BG 쓰기를 처리한 뒤, 설정에 따라 보조 띠를 먼저 소비하고 변경 타일 또는 주 스테이징 영역 전체를 업로드합니다. 보조·주 원본이 겹치므로 이 순서가 중요합니다. 접근 가능 구간을 따라 STAT 폴링이 계속되며 한 번의 VBlank 안에 끝나지 않을 수 있습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_EndFrame: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_EndFrame: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:28

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Wait for the next VBlank and flush BG writes, then optionally consume the
auxiliary strips before uploading either dirty tiles or the entire main stage.
Auxiliary/main source overlap makes that ordering significant. STAT polling
continues across access windows; the update need not fit one VBlank.

kitaqgb/lib/wire3d_dmg.c:3081

c
void Wire3DDMG_EndFrame()
{
    w3ddmg_wait_vblank_start();
    w3ddmg_flush_bg_queue();



    if (w3ddmg_aux_transfer_enabled)
    {
        w3ddmg_transfer_stage_aux_asm();
    }
    if (w3ddmg_dirty_transfer_enabled)
    {
        w3ddmg_transfer_dirty_stage();
    }
    else
    {
        w3ddmg_transfer_stage_asm();
    }

}
DMG3D_EraseModelFaces

모델의 앞면 삼각형을 투영하고 그 안의 스테이징 픽셀을 지웁니다.

사용 형식

c
void DMG3D_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 은선 플래그와 면 데이터를 가진 모델의 정점을 최대 24개 투영하고 앞면 삼각형 내부를 스테이징 영역에서 지웁니다. 0 이하의 배율은 256(1배)입니다. 최대 16개 면을 확인하며 깊이 경계를 가로지르는 면은 건너뜁니다. 공유 투영 캐시도 교체하지만 VRAM은 갱신하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom DMG3D_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom DMG3D_Face faces[2]={{0,2,1},{0,3,2}};
DMG3D_Model plane;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
    plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;
    DMG3D_BeginFrame();
    // Separate panels show a direct screen triangle and a projected square face.
    for(i=8;i<=32;i++) DMG3D_DrawLine2D(8,i,32,i);
    for(i=36;i<=84;i++) DMG3D_DrawLine2D(40,i,88,i);
    DMG3D_EraseTriangle2D(12,12,28,12,12,28);
    DMG3D_EraseModelFaces(&plane,0,0,64,0,0,0,256);

    DMG3D_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

DMG3D_EraseModelFaces: DMG — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
DMG — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
DMG3D_EraseModelFaces: CGB — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
CGB — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_faces.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:29

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Project up to 24 vertices and erase front-facing triangle interiors from
the stage for a model with hidden-line flags and face data. Nonpositive scale
means 256 (unity). Up to 16 faces are considered; depth-crossing faces are
skipped. This also replaces shared projection caches, but does not update VRAM.

kitaqgb/lib/wire3d_dmg.c:2843

c
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8)

{
    w3ddmg_u8 i;
    w3ddmg_u8 count;
    w3ddmg_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->faces == 0) return;
    if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &model->vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
        vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
        vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);






        w3ddmg_rotate_y(&vx, &vz, ry);
        w3ddmg_rotate_x(&vy, &vz, rx);
        w3ddmg_rotate_z(&vx, &vy, rz);


        vx = (w3ddmg_i16)(vx + x);
        vy = (w3ddmg_i16)(vy + y);
        vz = (w3ddmg_i16)(vz + z);

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }
        i = (w3ddmg_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
    w3ddmg_build_face_visibility(model, count, face_count);

    i = 0;
    while (i < face_count)
    {
        const Wire3DDMG_Face* f;
        f = &model->faces[(__safe_index w3ddmg_u8)i];
        if (w3ddmg_face_visible[(__safe_index w3ddmg_u8)i] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->a] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->b] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->c])
        {
            w3ddmg_clear_triangle(
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->a],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->a],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->b],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->b],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->c],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->c]);
        }
        i = (w3ddmg_u8)(i + 1);
    }
}
DMG3D_EraseSpan2D

스테이징 영역 한 행에서 양 끝점을 포함하는 수평 스팬을 지웁니다.

사용 형식

c
void DMG3D_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);

매개변수

y

지울 행의 픽셀 Y 좌표입니다.

x0

뷰포트 픽셀 단위의 작은 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

x1

뷰포트 픽셀 단위의 큰 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. X 끝점 순서를 맞추고 양 끝점을 포함하는 스테이징 스팬을 지웁니다. 두 끝점은 모두 0~127이어야 합니다. 유효하지 않은 Y는 무시합니다. X를 자동으로 잘라 주지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_EraseSpan2D: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_EraseSpan2D: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:30

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Order the X endpoints and erase the inclusive staged span. Both endpoints
must be in 0..127; invalid Y is ignored. The routine does not clip X for you.

kitaqgb/lib/wire3d_dmg.c:2943

c
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1)
{
    w3ddmg_u8 tx;

    if (x0 > x1)
    {
        tx = x0;
        x0 = x1;
        x1 = tx;
    }
    w3ddmg_stage_clear_span(y, x0, x1);
}
DMG3D_EraseTriangle2D

수평 주사선 스팬을 사용해 화면 좌표 삼각형을 스테이징 영역에서 지웁니다.

사용 형식

c
void DMG3D_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

cx

뷰포트 픽셀 단위의 정점 C X 좌표입니다.

cy

뷰포트 픽셀 단위의 정점 C Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 정수 주사선 교점으로 스테이징 픽셀에서 삼각형을 지웁니다. 뷰포트 좌표를 지정하세요. 퇴화 삼각형은 무시하며 가림 마스크와 VRAM은 바꾸지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom DMG3D_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom DMG3D_Face faces[2]={{0,2,1},{0,3,2}};
DMG3D_Model plane;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
    plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;
    DMG3D_BeginFrame();
    // Separate panels show a direct screen triangle and a projected square face.
    for(i=8;i<=32;i++) DMG3D_DrawLine2D(8,i,32,i);
    for(i=36;i<=84;i++) DMG3D_DrawLine2D(40,i,88,i);
    DMG3D_EraseTriangle2D(12,12,28,12,12,28);
    DMG3D_EraseModelFaces(&plane,0,0,64,0,0,0,256);

    DMG3D_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

DMG3D_EraseTriangle2D: DMG — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
DMG — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
DMG3D_EraseTriangle2D: CGB — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
CGB — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_faces.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:31

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Erase a triangle from staged pixels using integer scanline intersections.
Supply viewport coordinates. Degenerate triangles are ignored; the occlusion
mask and VRAM are unchanged.

kitaqgb/lib/wire3d_dmg.c:2933

c
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy)
{
    w3ddmg_clear_triangle(ax, ay, bx, by, cx, cy);
}
DMG3D_Init

흑백 와이어프레임 뷰포트용으로 LCD, 타일, 배경 맵을 초기화합니다.

사용 형식

c
void DMG3D_Init();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. LCD 상태를 제어하고 타일 VRAM과 BG 맵을 지운 뒤, 맵 타일 (3,1)부터 16×15 뷰포트를 설치합니다. 스크롤 (8,0), BGP=0xB4와 BG 표시를 설정합니다. 카메라, 큐, 전송 모드, 두 변경 테이블과 스테이징 영역을 재설정합니다. 0xD000..0xDFFF를 예약하고 WRAM 매핑을 유지하세요. 보조 저장 영역이 이 영역과 겹칩니다. 그리기 전에 BeginFrame을 호출해 가림 상태를 설정하세요.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_Init: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_Init: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:35

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Take over LCD state, clear tile VRAM and the BG map, and install a 16x15
viewport beginning at map tile (3,1). Set scroll (8,0), BGP=0xB4 and BG display.
Reset camera, queues, transfer modes, both dirty tables and stage. Reserve
0xD000..0xDFFF and retain its WRAM mapping; auxiliary storage aliases it.
Call BeginFrame before drawing to establish occlusion state.

kitaqgb/lib/wire3d_dmg.c:2572

c
void Wire3DDMG_Init()
{
    w3ddmg_u8 row;
    w3ddmg_u8 col;
    w3ddmg_u8 tid;
    w3ddmg_u16 off;

    w3ddmg_wait_vblank_start();
    w3ddmg_reg_lcdc = 0;

    w3ddmg_clear_vram_asm();



    w3ddmg_fill_bg_map_asm();

    row = 0;
    tid = 0x90;
    while (row < WIRE3D_DMG_TILE_H)
    {



        off = (w3ddmg_u16)(0x23 + ((w3ddmg_u16)row << 5));

        col = 0;
        while (col < WIRE3D_DMG_TILE_W)
        {
            w3ddmg_bg_map_9800[(w3ddmg_u16)(off + (w3ddmg_u16)col)] = tid;
            tid = (w3ddmg_u8)(tid + WIRE3D_DMG_TILE_H);
            col = (w3ddmg_u8)(col + 1);
        }
        row = (w3ddmg_u8)(row + 1);
        tid = (w3ddmg_u8)(0x90 + row);
    }




    w3ddmg_reg_scx = 8;

    w3ddmg_reg_scy = 0;
    w3ddmg_reg_bgp = 0xB4;
    w3ddmg_reg_lcdc = 0x81;
    w3ddmg_bgq_count = 0;

    w3ddmg_aux_transfer_enabled = 0;
    w3ddmg_dirty_transfer_enabled = 0;


    Wire3DDMG_SetCamera(0, 0, 0, 0, 0, 0);
    w3ddmg_clear_stage_asm();

    w3ddmg_clear_stage_aux_asm();
    w3ddmg_clear_dirty_tables();

}
DMG3D_ProjectPoint

월드 좌표의 점을 카메라를 통해 뷰포트 좌표로 투영합니다.

사용 형식

c
w3ddmg_u8 DMG3D_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);

매개변수

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

sx

투영된 X 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

sy

투영된 Y 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

반환값

투영에 성공하면 1, 깊이 검사에서 제외되면 0을 반환합니다.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 현재 카메라로 월드 점을 투영합니다. 깊이가 유효하지 않으면 출력을 바꾸지 않고 0을 반환하며, 성공하면 128×120 범위로 제한한 좌표를 씁니다. 두 출력 포인터 모두 유효해야 하며 좌표 차이는 s16에 들어가야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_ProjectPoint: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_ProjectPoint: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:43

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Project a world point with the current camera. Return zero for invalid
depth without changing outputs; success writes clamped 128x120 coordinates.
Both output pointers must be valid. Coordinate differences must fit s16.

kitaqgb/lib/wire3d_dmg.c:549

c
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy)
{
    return w3ddmg_project_world(x, y, z, sx, sy);
}
DMG3D_PutBgTile

배경 맵 셀 하나의 타일 번호 쓰기를 큐에 넣습니다.

사용 형식

c
void DMG3D_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);

매개변수

x

32×32 배경 맵의 X 타일 좌표입니다.

y

32×32 배경 맵의 Y 타일 좌표입니다.

tile

배경 셀의 8비트 타일 번호입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 0x9800의 32×32 맵에 쓸 타일을 EndFrame용 큐에 넣습니다. 잘못된 맵 좌표와 대기 중인 쓰기 48개를 초과하는 요청은 조용히 무시합니다. 이 큐는 일반 vram 라이브러리 큐와 별개입니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_PutBgTile: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_PutBgTile: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:44

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Queue a tile write to the 32x32 map at 0x9800 for EndFrame. Invalid map
coordinates and submissions beyond 48 pending writes are silently ignored.
This queue is separate from the general vram library queue.

kitaqgb/lib/wire3d_dmg.c:582

c
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile)
{
    if (x >= 32) return;
    if (y >= 32) return;
    if (w3ddmg_bgq_count >= WIRE3D_DMG_BG_QUEUE_LIMIT) return;
    w3ddmg_bgq_x[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = x;
    w3ddmg_bgq_y[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = y;
    w3ddmg_bgq_tile[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = tile;
    w3ddmg_bgq_count = (w3ddmg_u8)(w3ddmg_bgq_count + 1);
}
DMG3D_RotatePoint

주어진 각도로 점 하나를 제자리 회전시킵니다.

사용 형식

c
void DMG3D_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);

매개변수

x

X 성분용 쓰기 가능한 s16 포인터입니다. 다른 성분과 별도 주소여야 합니다.

y

Y 성분용 쓰기 가능한 s16 포인터입니다. 다른 성분과 별도 주소여야 합니다.

z

Z 성분용 쓰기 가능한 s16 포인터입니다. 다른 성분과 별도 주소여야 합니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 한 바퀴를 16단계로 하여 Y/X/Z 순서로 제자리 회전합니다. 성분 포인터 하나라도 null이면 호출 전체가 아무것도 하지 않습니다. 포인터는 각각 다른 주소를 사용하세요. 각 축 회전은 입력을 ±220으로 제한합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom DMG3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
DMG3D_Model cube;
DMG3D_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;

    DMG3D_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    DMG3D_DrawModel(&cube,-32,32,96,0,0,0);
    DMG3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    DMG3D_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    px=16;py=0;pz=0;DMG3D_RotatePoint(&px,&py,&pz,0,4,0);
    result[1]=px; result[2]=py; result[3]=pz;
    DMG3D_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

DMG3D_RotatePoint: DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG3D_RotatePoint: CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_models.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:46

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Rotate in place in Y/X/Z order using 16 steps per full turn. A null
component pointer makes the whole call a no-op; use distinct pointers.
Each axis rotation clamps its inputs to +/-220.

kitaqgb/lib/wire3d_dmg.c:3121

c
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz)
{
    if (x == 0) return;
    if (y == 0) return;
    if (z == 0) return;

    w3ddmg_rotate_y(x, z, ry);
    w3ddmg_rotate_x(y, z, rx);
    w3ddmg_rotate_z(x, y, rz);
}
DMG3D_SetAuxTransfer

EndFrame이 보조 띠도 전송할지 선택합니다.

사용 형식

c
void DMG3D_SetAuxTransfer(w3ddmg_u8 flag);

매개변수

flag

0은 전송 기능을 끄고 그 외의 값은 켭니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. EndFrame의 보조 전송 허용 상태를 저장합니다. 0이 아닌 값이면 켭니다. 여기서는 데이터를 복사하거나 지우지 않습니다. 보조 원본 바이트는 주 스테이징 영역과 주소를 공유합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Use the auxiliary-transfer gate to consume an overlapping stage strip.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        DMG3D_SetDirtyTransfer(1); DMG3D_SetAuxTransfer(1);
    DMG3D_BeginFrame();
    for(i=24;i<=31;i++) DMG3D_DrawLine2D(40,i,47,i);
    // Auxiliary upload consumes this source before the dirty main tile is sent.

    DMG3D_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

주 스테이징 영역 일부가 보조 전송으로 소비되어 화면 좌표 (80,24)에 검은 8×8 블록이 생깁니다.

DMG3D_SetAuxTransfer: DMG — 주 스테이징 영역 일부가 보조 전송으로 소비되어 화면 좌표 (80,24)에 검은 8×8 블록이 생깁니다.
DMG — 주 스테이징 영역 일부가 보조 전송으로 소비되어 화면 좌표 (80,24)에 검은 8×8 블록이 생깁니다.
DMG3D_SetAuxTransfer: CGB — 주 스테이징 영역 일부가 보조 전송으로 소비되어 화면 좌표 (80,24)에 검은 8×8 블록이 생깁니다.
CGB — 주 스테이징 영역 일부가 보조 전송으로 소비되어 화면 좌표 (80,24)에 검은 8×8 블록이 생깁니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_aux_gate.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_aux_gate.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:50

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Store the EndFrame auxiliary-transfer gate; any nonzero value enables it.
No data is copied or cleared here. Auxiliary source bytes alias the main stage.

kitaqgb/lib/wire3d_dmg.c:3895

c
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag)
{
    w3ddmg_aux_transfer_enabled = flag;
}
DMG3D_SetCamera

이후 투영에 사용할 카메라 위치와 방향을 저장합니다.

사용 형식

c
void DMG3D_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);

매개변수

x

월드 좌표계에서 카메라의 X 성분입니다.

y

월드 좌표계에서 카메라의 Y 성분입니다.

z

월드 좌표계에서 카메라의 Z 성분입니다.

pitch

X축 회전입니다. 16단계가 한 바퀴입니다.

yaw

Y축 회전입니다. 16단계가 한 바퀴입니다.

roll

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 이후 그리기를 위해 카메라 위치와 각도를 저장합니다. 한 바퀴는 16각도 단계입니다. 기존 그림을 다시 투영하거나 입력 범위를 검사하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_SetCamera: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_SetCamera: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:51

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Store camera position and angles for later draws; a full turn is 16 angle
steps. No existing drawing is reprojected and no input range validation occurs.

kitaqgb/lib/wire3d_dmg.c:2661

c
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll)

{
    w3ddmg_cam_x = x;
    w3ddmg_cam_y = y;
    w3ddmg_cam_z = z;
    w3ddmg_cam_pitch = pitch;
    w3ddmg_cam_yaw = yaw;
    w3ddmg_cam_roll = roll;
}
DMG3D_SetDirtyTransfer

높이 120인 주 뷰포트의 변경 타일 전송을 선택합니다.

사용 형식

c
void DMG3D_SetDirtyTransfer(w3ddmg_u8 flag);

매개변수

flag

0은 전송 기능을 끄고 그 외의 값은 켭니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 변경 영역 전송 허용 상태를 저장하고 값이 그대로여도 두 변경 이력과 주 스테이징 영역을 지웁니다. VRAM은 유지합니다. 기존 그림 위에서 켜면 표시되지 않은 옛 타일이 남을 수 있으므로, 미리 깨끗한 표시 상태를 마련하세요.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Remove the previous frame and upload only the tracked current/previous tiles.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        DMG3D_SetDirtyTransfer(1); DMG3D_SetAuxTransfer(0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,24,8); DMG3D_DrawLine2D(24,8,24,24);
    DMG3D_DrawLine2D(24,24,8,24); DMG3D_DrawLine2D(8,24,8,8);
    DMG3D_EndFrame();
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(80,80,104,80); DMG3D_DrawLine2D(104,80,104,104);
    DMG3D_DrawLine2D(104,104,80,104); DMG3D_DrawLine2D(80,104,80,80);

    DMG3D_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

이전의 왼쪽 위 테두리가 사라지고 화면 좌표 (96,88)..(120,112)에 새 테두리만 남습니다.

DMG3D_SetDirtyTransfer: DMG — 이전의 왼쪽 위 테두리가 사라지고 화면 좌표 (96,88)..(120,112)에 새 테두리만 남습니다.
DMG — 이전의 왼쪽 위 테두리가 사라지고 화면 좌표 (96,88)..(120,112)에 새 테두리만 남습니다.
DMG3D_SetDirtyTransfer: CGB — 이전의 왼쪽 위 테두리가 사라지고 화면 좌표 (96,88)..(120,112)에 새 테두리만 남습니다.
CGB — 이전의 왼쪽 위 테두리가 사라지고 화면 좌표 (96,88)..(120,112)에 새 테두리만 남습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_dirty.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_dirty.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:52

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Store the dirty-transfer gate and clear both dirty histories and the main
stage, even if the value is unchanged. VRAM is retained; enabling this over an
old image can leave unmarked old tiles, so arrange a clean displayed baseline.

kitaqgb/lib/wire3d_dmg.c:3955

c
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag)
{
    w3ddmg_dirty_transfer_enabled = flag;
    w3ddmg_clear_dirty_tables();
    w3ddmg_clear_stage_asm();
}
DMG3D_SetPalette

흑백 배경 팔레트 레지스터 BGP의 네 명암 매핑을 씁니다.

사용 형식

c
void DMG3D_SetPalette(w3ddmg_u8 bgp);

매개변수

bgp

2비트 명암 할당 네 개를 담은 BGP 레지스터 값입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. DMG BGP 팔레트의 원시 인코딩 값을 즉시 씁니다. 프레임 동기화는 하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    DMG3D_SetCamera(8,0,0,0,0,0);
    result[1]=DMG3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=DMG3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    DMG3D_SetCamera(0,0,0,0,0,0);
    DMG3D_BeginFrame();
    DMG3D_DrawLine2D(8,8,56,8);
    DMG3D_DrawLine2D(56,8,56,40);
    DMG3D_DrawLine2D(56,40,8,40);
    DMG3D_DrawLine2D(8,40,8,8);
    DMG3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    DMG3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    DMG3D_PutBgTile(1,1,160);
    DMG3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

DMG3D_SetPalette: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG3D_SetPalette: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_raster.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:53

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Write the raw DMG BGP palette encoding immediately; no frame synchronization occurs.

kitaqgb/lib/wire3d_dmg.c:597

c
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp)
{
    w3ddmg_reg_bgp = bgp;
}
DMG3D_TransferAuxNow

보조 띠 6개를 즉시 업로드하고 원본 바이트를 지웁니다.

사용 형식

c
void DMG3D_TransferAuxNow();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 보조 전송 허용 상태와 관계없이 보조 원본 띠를 즉시 업로드·소비합니다. VBlank 시작을 기다리거나 변경 이력/BG 큐를 갱신하지 않습니다. 원본은 주 스테이징 영역과 겹치므로 주 영역 업로드와 순서를 조정해야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        DMG3D_BeginFrame();
    DMG3D_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
    DMG3D_TransferMainNow();
    // Direct auxiliary transfer writes a separate tile after the main upload.
    for(i=24;i<=31;i++) DMG3D_DrawLine2D(40,i,47,i);
    stage_byte=(u8*)0xD518;result[1]=*stage_byte;
    DMG3D_TransferAuxNow();result[2]=*stage_byte;

    // Do not upload the consumed stage again.
    result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

DMG3D_TransferAuxNow: DMG — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
DMG — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
DMG3D_TransferAuxNow: CGB — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
CGB — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_direct.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:57

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Upload and consume auxiliary source strips immediately, independent of the
auxiliary gate. No VBlank-start wait or dirty-history/BG-queue update occurs.
The source overlaps the main stage and must be coordinated with its upload.

kitaqgb/lib/wire3d_dmg.c:3983

c
void Wire3DDMG_TransferAuxNow()
{
    w3ddmg_transfer_stage_aux_asm();
}
DMG3D_TransferMainNow

주 스테이징 영역 전체를 즉시 업로드하고 소비한 원본 픽셀을 지웁니다.

사용 형식

c
void DMG3D_TransferMainNow();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120. 다음 VBlank를 기다리지 않고 STAT를 폴링하면서 주 스테이징 영역 전체를 즉시 업로드·소비합니다. 전송 게이트는 무시하고 변경 이력과 BG 타일 큐는 유지합니다. 프레임 처리 순서는 호출자가 조정해야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "dmg3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom DMG3D_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    DMG3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    DMG3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        DMG3D_BeginFrame();
    DMG3D_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
    DMG3D_TransferMainNow();
    // Direct auxiliary transfer writes a separate tile after the main upload.
    for(i=24;i<=31;i++) DMG3D_DrawLine2D(40,i,47,i);
    stage_byte=(u8*)0xD518;result[1]=*stage_byte;
    DMG3D_TransferAuxNow();result[2]=*stage_byte;

    // Do not upload the consumed stage again.
    result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

DMG3D_TransferMainNow: DMG — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
DMG — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
DMG3D_TransferMainNow: CGB — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.
CGB — 투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg3d_direct.c .\kitaqgb\lib\dmg3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg3d_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/dmg3d.h:58

선언 주석 원문
WIRE3D_DMG_HEIGHT = 120.
Upload and consume the full main stage immediately, polling STAT but not
waiting for the next VBlank. Ignore transfer gates and leave dirty histories
and BG tile queue unchanged; the caller coordinates the frame lifecycle.

kitaqgb/lib/wire3d_dmg.c:3970

c
void Wire3DDMG_TransferMainNow()
{
    w3ddmg_transfer_stage_asm();
}

entity.h — 고정 배열 기반 오브젝트 풀

entity는 적, 탄환, 아이템 등의 상태를 담는 고정 배열 기반 오브젝트 풀입니다. 빈 슬롯을 할당하고 ID로 참조하다가 오브젝트가 필요 없어지면 슬롯을 재사용합니다. 힙 메모리는 할당하지 않습니다. 좌표와 속도의 단위, 이동, 충돌 처리, 타이머 갱신은 게임에서 정의합니다.

entity.h를 포함하고 entity.c를 정확히 한 번 컴파일하세요. 먼저 entity_init을 호출하고 entity_create의 반환값이 0xFF가 아닌지 확인하세요. ENTITY_MAX의 기본값은 16입니다. ID 체계는 1~255개 슬롯을 지원하지만 실제 할당 가능한 개수는 가용 RAM에 따라 달라집니다. 모든 컴파일 단위에서 같은 용량 정의를 사용하세요.

entity_get이 반환하는 포인터는 재사용 가능한 풀 저장 공간을 가리킵니다. 해제한 뒤에는 같은 ID가 다른 오브젝트를 나타낼 수 있으므로 ID와 포인터 모두 영구적인 식별자가 아닙니다. entity_destroy는 슬롯을 비활성화할 뿐입니다. 스프라이트를 숨기거나 해제하고 다른 자원을 정리하는 일은 호출자가 맡아야 합니다. sprite 필드는 관리용 정보이며 OAM을 자동으로 갱신하지 않습니다.

entity_update_all과 entity_draw_all은 활성 슬롯을 ID 오름차순으로 순회하며 fn(id)를 호출합니다. 실제 갱신이나 그리기 처리는 콜백에 작성하세요. 콜백이 null이면 아무 일도 하지 않습니다. 콜백 안에서 뒤쪽 슬롯을 생성하거나 해제하면 현재 순회에도 영향을 줍니다. 갱신 순회를 먼저 수행하고 그리기 순회를 수행하면 두 작업을 분리할 수 있습니다.

entity_clear_all

모든 엔티티를 해제하고 스프라이트 미할당 표시를 포함한 필드를 초기화합니다.

사용 형식

c
void entity_clear_all();

반환값

없음(void).

사용 조건과 제한

풀은 고정 배열이며 힙을 동적으로 할당하지 않습니다. ENTITY_MAX의 기본값은 16이고 범위는 1~255입니다. 모든 컴파일 단위에서 같은 값으로 정의하세요. ID는 0부터 시작하며 0xFF는 실패를 나타냅니다.

모든 슬롯의 active,type,x,y,vx,vy,state,timer를 0, sprite를 0xFF로 설정합니다. 하드웨어 스프라이트를 숨기거나 해제하지는 않으므로 렌더링 자원은 별도로 정리하세요.

사용 예

c
entity_clear_all();
after_clear = entity_count_active();
if (after_clear != 0 || entity_get(reused) != 0) { failures++; }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전체 프로그램은 재사용되는 풀 슬롯의 수명 주기를 보여 줍니다. 숫자는 라벨과 함께 읽으세요. 두 개를 할당하면 CREATED 002, 첫 번째를 해제하면 AFTER FREE 001, 가장 작은 빈 ID를 재사용하면 REUSED ID 000, 전체를 해제하면 AFTER CLEAR 000입니다. 해제 후 조회가 null인지, 재할당 시 필드가 초기화되는지도 검사합니다. FAILED CHECKS 000은 기대값과 일치했다는 뜻입니다.

GB 순회는 활성 엔티티 두 개에 각각 콜백을 호출하므로 UPDATE CALLS 002, DRAW CALLS 002가 됩니다. 예제의 갱신 콜백은 둘을 오른쪽으로 한 타일 이동합니다. 그리기 콜백은 두 객체를 나타내는 A를 타일 (3,12), B를 (7,12)에 놓습니다. 콜백이 그린 배경 글자 타일이며 자동 할당된 스프라이트가 아닙니다.

entity_clear_all: DMG
DMG
entity_clear_all: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm
구현과 소스

kitaqgb/lib/entity.h:43

선언 주석 원문
Release every entity and restore deterministic defaults, including the no-sprite sentinel.

kitaqgb/lib/entity.c:14

c
void entity_clear_all()
{
    u8 i = 0;
    while (i < ENTITY_MAX) {
        entity_pool[i].active = 0;
        entity_pool[i].type = 0;
        entity_pool[i].x = 0;
        entity_pool[i].y = 0;
        entity_pool[i].vx = 0;
        entity_pool[i].vy = 0;
        entity_pool[i].state = 0;
        entity_pool[i].timer = 0;
        entity_pool[i].sprite = 0xFF;
        i++;
    }
}
entity_count_active

엔티티 상태를 바꾸지 않고 사용 중인 슬롯 수를 반환합니다.

사용 형식

c
u8 entity_count_active();

반환값

active 바이트가 0이 아닌 슬롯 수로, 0~ENTITY_MAX입니다. 사용 중인 수이며 가장 큰 ID나 화면의 스프라이트 수가 아닙니다.

사용 조건과 제한

풀은 고정 배열이며 힙을 동적으로 할당하지 않습니다. ENTITY_MAX의 기본값은 16이고 범위는 1~255입니다. 모든 컴파일 단위에서 같은 값으로 정의하세요. ID는 0부터 시작하며 0xFF는 실패를 나타냅니다.

사용 예

c
created = entity_count_active();
if (created != 2) { failures++; }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전체 프로그램은 재사용되는 풀 슬롯의 수명 주기를 보여 줍니다. 숫자는 라벨과 함께 읽으세요. 두 개를 할당하면 CREATED 002, 첫 번째를 해제하면 AFTER FREE 001, 가장 작은 빈 ID를 재사용하면 REUSED ID 000, 전체를 해제하면 AFTER CLEAR 000입니다. 해제 후 조회가 null인지, 재할당 시 필드가 초기화되는지도 검사합니다. FAILED CHECKS 000은 기대값과 일치했다는 뜻입니다.

GB 순회는 활성 엔티티 두 개에 각각 콜백을 호출하므로 UPDATE CALLS 002, DRAW CALLS 002가 됩니다. 예제의 갱신 콜백은 둘을 오른쪽으로 한 타일 이동합니다. 그리기 콜백은 두 객체를 나타내는 A를 타일 (3,12), B를 (7,12)에 놓습니다. 콜백이 그린 배경 글자 타일이며 자동 할당된 스프라이트가 아닙니다.

entity_count_active: DMG
DMG
entity_count_active: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm
구현과 소스

kitaqgb/lib/entity.h:41

선언 주석 원문
Count occupied slots without changing entity state.

kitaqgb/lib/entity.c:93

c
u8 entity_count_active()
{
    u8 i = 0;
    u8 count = 0;
    while (i < ENTITY_MAX) {
        if (entity_pool[i].active != 0) count++;
        i++;
    }
    return count;
}
entity_create

지정한 종류와 좌표로 엔티티를 할당하고 재사용 가능한 ID를 반환합니다. 빈 슬롯이 없으면 0xFF입니다.

사용 형식

c
u8 entity_create(u8 type, s16 x, s16 y);

매개변수

type

게임에서 정의하는 0~255의 종류 번호입니다. 풀은 값을 저장할 뿐, 종류에 따라 동작이나 그리기 함수를 선택하지 않습니다.

x, y

부호 있는 16비트 좌표(-32768~32767)입니다. 픽셀이나 Q8.8 등 단위는 게임이 정합니다. 풀은 단위 변환, 좌표 제한, 속도에 따른 자동 이동을 하지 않습니다.

반환값

가장 작은 빈 슬롯 ID(0~ENTITY_MAX-1)를 반환하며, 빈 슬롯이 없으면 0xFF입니다. 성공하면 active=1로 설정하고 종류·좌표를 저장하며 속도·상태·타이머는 0, sprite는 0xFF로 초기화합니다.

사용 조건과 제한

풀은 고정 배열이며 힙을 동적으로 할당하지 않습니다. ENTITY_MAX의 기본값은 16이고 범위는 1~255입니다. 모든 컴파일 단위에서 같은 값으로 정의하세요. ID는 0부터 시작하며 0xFF는 실패를 나타냅니다.

사용 예

c
first = entity_create(1, 2, 12);
second = entity_create(2, 6, 12);
if (first == 0xFF || second == 0xFF) { failures++; }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전체 프로그램은 재사용되는 풀 슬롯의 수명 주기를 보여 줍니다. 숫자는 라벨과 함께 읽으세요. 두 개를 할당하면 CREATED 002, 첫 번째를 해제하면 AFTER FREE 001, 가장 작은 빈 ID를 재사용하면 REUSED ID 000, 전체를 해제하면 AFTER CLEAR 000입니다. 해제 후 조회가 null인지, 재할당 시 필드가 초기화되는지도 검사합니다. FAILED CHECKS 000은 기대값과 일치했다는 뜻입니다.

GB 순회는 활성 엔티티 두 개에 각각 콜백을 호출하므로 UPDATE CALLS 002, DRAW CALLS 002가 됩니다. 예제의 갱신 콜백은 둘을 오른쪽으로 한 타일 이동합니다. 그리기 콜백은 두 객체를 나타내는 A를 타일 (3,12), B를 (7,12)에 놓습니다. 콜백이 그린 배경 글자 타일이며 자동 할당된 스프라이트가 아닙니다.

entity_create: DMG
DMG
entity_create: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm
구현과 소스

kitaqgb/lib/entity.h:29

선언 주석 원문
Returns a reusable slot ID, or 0xFF if no slot is free.

kitaqgb/lib/entity.c:33

c
u8 entity_create(u8 type, s16 x, s16 y)
{
    u8 i = 0;
    while (i < ENTITY_MAX) {
        if (entity_pool[i].active == 0) {
            entity_pool[i].active = 1;
            entity_pool[i].type = type;
            entity_pool[i].x = x;
            entity_pool[i].y = y;
            entity_pool[i].vx = 0;
            entity_pool[i].vy = 0;
            entity_pool[i].state = 0;
            entity_pool[i].timer = 0;
            entity_pool[i].sprite = 0xFF;
            return i;
        }
        i++;
    }
    return 0xFF;
}
entity_destroy

id의 엔티티 슬롯을 해제합니다. 저장된 데이터는 다시 할당할 때 초기화됩니다.

사용 형식

c
void entity_destroy(u8 id);

매개변수

id

0~ENTITY_MAX-1의 재사용 가능한 슬롯 번호입니다. 범위 밖 ID는 유효하지 않습니다. 잘못된 ID를 해제해도 변화가 없고 조회하면 null을 반환합니다.

반환값

없음(void).

사용 조건과 제한

풀은 고정 배열이며 힙을 동적으로 할당하지 않습니다. ENTITY_MAX의 기본값은 16이고 범위는 1~255입니다. 모든 컴파일 단위에서 같은 값으로 정의하세요. ID는 0부터 시작하며 0xFF는 실패를 나타냅니다.

해제는 active만 0으로 만듭니다. 다른 필드를 지우거나 스프라이트·에셋을 해제하지 않습니다. 이후 같은 ID와 주소가 다른 엔티티에 재사용될 수 있습니다. 관련 자원은 게임에서 정리하세요.

사용 예

c
entity_destroy(first);
after_free = entity_count_active();
if (entity_get(first) != 0 || after_free != 1) { failures++; }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전체 프로그램은 재사용되는 풀 슬롯의 수명 주기를 보여 줍니다. 숫자는 라벨과 함께 읽으세요. 두 개를 할당하면 CREATED 002, 첫 번째를 해제하면 AFTER FREE 001, 가장 작은 빈 ID를 재사용하면 REUSED ID 000, 전체를 해제하면 AFTER CLEAR 000입니다. 해제 후 조회가 null인지, 재할당 시 필드가 초기화되는지도 검사합니다. FAILED CHECKS 000은 기대값과 일치했다는 뜻입니다.

GB 순회는 활성 엔티티 두 개에 각각 콜백을 호출하므로 UPDATE CALLS 002, DRAW CALLS 002가 됩니다. 예제의 갱신 콜백은 둘을 오른쪽으로 한 타일 이동합니다. 그리기 콜백은 두 객체를 나타내는 A를 타일 (3,12), B를 (7,12)에 놓습니다. 콜백이 그린 배경 글자 타일이며 자동 할당된 스프라이트가 아닙니다.

entity_destroy: DMG
DMG
entity_destroy: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm
구현과 소스

kitaqgb/lib/entity.h:32

선언 주석 원문
Release a valid slot without clearing its payload. Reallocation resets the payload;
a saved pointer or ID must not be treated as a persistent entity identity.

kitaqgb/lib/entity.c:56

c
void entity_destroy(u8 id)
{
    if (id >= ENTITY_MAX) return;
    // Deactivation only releases this pool slot; the caller handles sprite/resource cleanup.
    entity_pool[id].active = 0;
}
entity_draw_all

활성 엔티티를 순회하며 각 ID를 그리기 콜백에 전달합니다. 순회 방식은 entity_update_all과 같습니다. 콜백이 그리기 데이터를 제출하지 않으면 스프라이트나 픽셀은 그려지지 않습니다.

사용 형식

c
void entity_draw_all(EntityFn fn);

매개변수

fn

형식이 void fn(u8 id)인 함수 포인터입니다. 슬롯 ID를 받으므로 필드에 접근하려면 entity_get(id)를 사용하세요. null도 허용되며 이때는 호출하지 않습니다.

반환값

없음(void).

사용 조건과 제한

풀은 고정 배열이며 힙을 동적으로 할당하지 않습니다. ENTITY_MAX의 기본값은 16이고 범위는 1~255입니다. 모든 컴파일 단위에서 같은 값으로 정의하세요. ID는 0부터 시작하며 0xFF는 실패를 나타냅니다.

순회가 슬롯에 도달했을 때 활성 상태를 검사합니다. 콜백이 뒤쪽 슬롯을 비활성화하면 건너뛰고, 활성화하면 이번 순회에서 처리할 수 있습니다. 시작 시점의 활성 목록을 고정한 스냅샷이 아닙니다.

사용 예

c
void demo_draw(u8 id) {
    Entity* entity;
    entity = entity_get(id);
    if (entity != 0) {
        m_put((u8)entity->x, (u8)entity->y, (u8)('A' + entity->type - 1));
        draw_calls++;
    }
}

// From main(), after creating two entities:
draw_calls = 0;
entity_draw_all(demo_draw);
automatic_draws = draw_calls;
if (automatic_draws != 2) { failures++; }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전체 프로그램은 재사용되는 풀 슬롯의 수명 주기를 보여 줍니다. 숫자는 라벨과 함께 읽으세요. 두 개를 할당하면 CREATED 002, 첫 번째를 해제하면 AFTER FREE 001, 가장 작은 빈 ID를 재사용하면 REUSED ID 000, 전체를 해제하면 AFTER CLEAR 000입니다. 해제 후 조회가 null인지, 재할당 시 필드가 초기화되는지도 검사합니다. FAILED CHECKS 000은 기대값과 일치했다는 뜻입니다.

GB 순회는 활성 엔티티 두 개에 각각 콜백을 호출하므로 UPDATE CALLS 002, DRAW CALLS 002가 됩니다. 예제의 갱신 콜백은 둘을 오른쪽으로 한 타일 이동합니다. 그리기 콜백은 두 객체를 나타내는 A를 타일 (3,12), B를 (7,12)에 놓습니다. 콜백이 그린 배경 글자 타일이며 자동 할당된 스프라이트가 아닙니다.

entity_draw_all: DMG
DMG
entity_draw_all: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm
구현과 소스

kitaqgb/lib/entity.h:39

선언 주석 원문
Use the same active-slot traversal for drawing; the callback supplies all rendering.

kitaqgb/lib/entity.c:87

c
void entity_draw_all(EntityFn fn)
{
    entity_update_all(fn);
}
entity_get

사용 중인 유효 ID의 엔티티 포인터를 반환하며, 그 외에는 null입니다. 해당 저장 공간은 재사용됩니다.

사용 형식

c
Entity* entity_get(u8 id);

매개변수

id

0~ENTITY_MAX-1의 재사용 가능한 슬롯 번호입니다. 범위 밖 ID는 유효하지 않습니다. 잘못된 ID를 해제해도 변화가 없고 조회하면 null을 반환합니다.

반환값

사용 중인 슬롯을 수정할 수 있는 포인터를 반환하며, ID가 잘못됐거나 비활성이면 null입니다. 메모리는 풀 소유입니다. 직접 해제하거나 삭제·재할당을 거치는 영구 식별자로 사용하지 마세요.

사용 조건과 제한

풀은 고정 배열이며 힙을 동적으로 할당하지 않습니다. ENTITY_MAX의 기본값은 16이고 범위는 1~255입니다. 모든 컴파일 단위에서 같은 값으로 정의하세요. ID는 0부터 시작하며 0xFF는 실패를 나타냅니다.

해제는 active만 0으로 만듭니다. 다른 필드를 지우거나 스프라이트·에셋을 해제하지 않습니다. 이후 같은 ID와 주소가 다른 엔티티에 재사용될 수 있습니다. 관련 자원은 게임에서 정리하세요.

사용 예

c
current_entity = entity_get(first);
if (current_entity != 0) { current_entity->vx = 5; }
else { failures++; }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전체 프로그램은 재사용되는 풀 슬롯의 수명 주기를 보여 줍니다. 숫자는 라벨과 함께 읽으세요. 두 개를 할당하면 CREATED 002, 첫 번째를 해제하면 AFTER FREE 001, 가장 작은 빈 ID를 재사용하면 REUSED ID 000, 전체를 해제하면 AFTER CLEAR 000입니다. 해제 후 조회가 null인지, 재할당 시 필드가 초기화되는지도 검사합니다. FAILED CHECKS 000은 기대값과 일치했다는 뜻입니다.

GB 순회는 활성 엔티티 두 개에 각각 콜백을 호출하므로 UPDATE CALLS 002, DRAW CALLS 002가 됩니다. 예제의 갱신 콜백은 둘을 오른쪽으로 한 타일 이동합니다. 그리기 콜백은 두 객체를 나타내는 A를 타일 (3,12), B를 (7,12)에 놓습니다. 콜백이 그린 배경 글자 타일이며 자동 할당된 스프라이트가 아닙니다.

entity_get: DMG
DMG
entity_get: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm
구현과 소스

kitaqgb/lib/entity.h:34

선언 주석 원문
Returns null for an invalid or inactive ID; the returned pointer aliases reusable pool storage.

kitaqgb/lib/entity.c:65

c
Entity* entity_get(u8 id)
{
    if (id >= ENTITY_MAX) return 0;
    if (entity_pool[id].active == 0) return 0;
    return &entity_pool[(__safe_index u8)id];
}
entity_init

엔티티 풀의 모든 슬롯을 초기화합니다.

사용 형식

c
void entity_init();

반환값

없음(void).

사용 조건과 제한

풀은 고정 배열이며 힙을 동적으로 할당하지 않습니다. ENTITY_MAX의 기본값은 16이고 범위는 1~255입니다. 모든 컴파일 단위에서 같은 값으로 정의하세요. ID는 0부터 시작하며 0xFF는 실패를 나타냅니다.

모든 슬롯의 active,type,x,y,vx,vy,state,timer를 0, sprite를 0xFF로 설정합니다. 하드웨어 스프라이트를 숨기거나 해제하지는 않으므로 렌더링 자원은 별도로 정리하세요.

사용 예

c
entity_init();
if (entity_count_active() != 0) { failures++; }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전체 프로그램은 재사용되는 풀 슬롯의 수명 주기를 보여 줍니다. 숫자는 라벨과 함께 읽으세요. 두 개를 할당하면 CREATED 002, 첫 번째를 해제하면 AFTER FREE 001, 가장 작은 빈 ID를 재사용하면 REUSED ID 000, 전체를 해제하면 AFTER CLEAR 000입니다. 해제 후 조회가 null인지, 재할당 시 필드가 초기화되는지도 검사합니다. FAILED CHECKS 000은 기대값과 일치했다는 뜻입니다.

GB 순회는 활성 엔티티 두 개에 각각 콜백을 호출하므로 UPDATE CALLS 002, DRAW CALLS 002가 됩니다. 예제의 갱신 콜백은 둘을 오른쪽으로 한 타일 이동합니다. 그리기 콜백은 두 객체를 나타내는 A를 타일 (3,12), B를 (7,12)에 놓습니다. 콜백이 그린 배경 글자 타일이며 자동 할당된 스프라이트가 아닙니다.

entity_init: DMG
DMG
entity_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm
구현과 소스

kitaqgb/lib/entity.h:27

선언 주석 원문
Reset every slot before the game starts using the pool.

kitaqgb/lib/entity.c:8

c
void entity_init()
{
    entity_clear_all();
}
entity_update_all

ID 오름차순으로 활성 슬롯을 살펴보고 각각 fn(id)를 한 번 호출합니다. 이동·충돌·타이머 로직은 콜백에 작성하며 풀은 이 로직을 제공하지 않습니다. 콜백이 null이면 아무것도 하지 않습니다.

사용 형식

c
void entity_update_all(EntityFn fn);

매개변수

fn

형식이 void fn(u8 id)인 함수 포인터입니다. 슬롯 ID를 받으므로 필드에 접근하려면 entity_get(id)를 사용하세요. null도 허용되며 이때는 호출하지 않습니다.

반환값

없음(void).

사용 조건과 제한

풀은 고정 배열이며 힙을 동적으로 할당하지 않습니다. ENTITY_MAX의 기본값은 16이고 범위는 1~255입니다. 모든 컴파일 단위에서 같은 값으로 정의하세요. ID는 0부터 시작하며 0xFF는 실패를 나타냅니다.

순회가 슬롯에 도달했을 때 활성 상태를 검사합니다. 콜백이 뒤쪽 슬롯을 비활성화하면 건너뛰고, 활성화하면 이번 순회에서 처리할 수 있습니다. 시작 시점의 활성 목록을 고정한 스냅샷이 아닙니다.

사용 예

c
void demo_update(u8 id) {
    Entity* entity;
    entity = entity_get(id);
    if (entity != 0) { entity->x = entity->x + 1; update_calls++; }
}

// From main(), after creating two entities:
update_calls = 0;
entity_update_all(demo_update);
automatic_updates = update_calls;
if (automatic_updates != 2) { failures++; }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전체 프로그램은 재사용되는 풀 슬롯의 수명 주기를 보여 줍니다. 숫자는 라벨과 함께 읽으세요. 두 개를 할당하면 CREATED 002, 첫 번째를 해제하면 AFTER FREE 001, 가장 작은 빈 ID를 재사용하면 REUSED ID 000, 전체를 해제하면 AFTER CLEAR 000입니다. 해제 후 조회가 null인지, 재할당 시 필드가 초기화되는지도 검사합니다. FAILED CHECKS 000은 기대값과 일치했다는 뜻입니다.

GB 순회는 활성 엔티티 두 개에 각각 콜백을 호출하므로 UPDATE CALLS 002, DRAW CALLS 002가 됩니다. 예제의 갱신 콜백은 둘을 오른쪽으로 한 타일 이동합니다. 그리기 콜백은 두 객체를 나타내는 A를 타일 (3,12), B를 (7,12)에 놓습니다. 콜백이 그린 배경 글자 타일이며 자동 할당된 스프라이트가 아닙니다.

entity_update_all: DMG
DMG
entity_update_all: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\entity.c .\kitaq-docs\samples\api-examples\gb\entity_pool.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\entity_pool.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm
구현과 소스

kitaqgb/lib/entity.h:37

선언 주석 원문
Call fn for each slot that is active when the scan reaches it; null is a no-op.
Callbacks may change the pool, so newly activated later slots can run in this pass.

kitaqgb/lib/entity.c:74

c
void entity_update_all(EntityFn fn)
{
    u8 i = 0;
    if (fn == 0) return;
    while (i < ENTITY_MAX) {
        if (entity_pool[i].active != 0) {
            fn(i);
        }
        i++;
    }
}

fixed.h — Q8.8 고정소수점 연산과 사각형

Q8.8 연산은 정수로 소수 좌표와 속도를 표현하며, 사각형 및 점의 충돌 검사도 제공합니다. 각 연산의 정밀도와 범위 제한을 확인하세요.

fix_div

피연산자의 정밀도를 줄인 뒤 Q8.8 나눗셈을 수행합니다.

사용 형식

c
fix8 fix_div(fix8 a, fix8 b);

매개변수

a

Q8.8 형식의 왼쪽 피연산자입니다.

b

Q8.8 형식의 오른쪽 피연산자입니다.

반환값

Q8.8 몫을 반환합니다. b == 0이면 0을 반환합니다.

사용 조건과 제한

계산식은 ((a >> 4) * 256) / (b >> 4)입니다. 0이 아닌 제수는 비트 이동 후에도 0이 아니어야 하므로 양의 원시값 1~15를 전달하면 안 됩니다. 배율을 적용한 분자도 16비트 안에 들어가야 합니다.

사용 예

c
result[3]=fix_div(768,512);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

3.0을 2.0으로 나누면 1.5(원시값 384)가 됩니다. 제수가 정확히 0인 경우의 반환값도 별도로 검사합니다.

fix_div: DMG
DMG
fix_div: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:32

선언 주석 원문
Scale the reduced-precision quotient back to 8.8 and return zero for b == 0.
Callers must also ensure (b >> 4) is nonzero; the explicit check only tests b.
The intermediate product must fit the compiler's integer arithmetic.

kitaqgb/lib/fixed.c:26

c
fix8 fix_div(fix8 a, fix8 b)
{
    if (b == 0) return 0;
    return (fix8)(((a >> 4) * 256) / (b >> 4));
}
fix_from_int

정수 좌표나 속도를 Q8.8로 변환하여 이후 계산에서 소수부를 유지할 수 있게 합니다.

사용 형식

c
fix8 fix_from_int(s16 n);

매개변수

n

변환할 정수이며 범위는 −128~127입니다.

반환값

원시값 n × 256을 반환합니다.

사용 조건과 제한

fix8은 부호 있는 Q8.8 형식입니다. 원시값 256이 1.0을 나타냅니다. 중간값과 결과가 16비트 범위를 벗어나지 않게 하세요.

사용 예

c
result[0]=fix_from_int(-3);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 예제는 −3을 변환합니다. 화면의 −00768은 Q8.8 원시 결과값 −768입니다.

fix_from_int: DMG
DMG
fix_from_int: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:23

선언 주석 원문
Convert an integer to signed 8.8 fixed point by moving it into the high byte.
The caller must keep the result within the representable 16-bit range.

kitaqgb/lib/fixed.c:5

c
fix8 fix_from_int(s16 n)
{
    return (fix8)(n << 8);
}
fix_lerp

8비트 가중치를 사용하여 한 Q8.8 값에서 다른 값 쪽으로 보간합니다.

사용 형식

c
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);

매개변수

a

Q8.8 형식의 왼쪽 피연산자입니다.

b

Q8.8 형식의 오른쪽 피연산자입니다.

t_q8

보간 가중치이며 범위는 0~255입니다.

반환값

근사 보간 결과를 Q8.8로 반환합니다.

사용 조건과 제한

차이값과 가중치를 각각 오른쪽으로 4비트 이동합니다. 가중치는 16단계가 되므로 255를 주어도 끝값에 도달하지 않을 수 있습니다. b - a와 최종 결과를 16비트 범위 안에 두세요.

사용 예

c
result[4]=fix_lerp(0,1024,128);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

0과 4.0 사이에서 가중치 128을 쓰면 2.0(원시값 512)이 됩니다. 가중치 255에서는 3.75(원시값 960)가 되어 끝값에 도달하지 않음을 보여 줍니다.

fix_lerp: DMG
DMG
fix_lerp: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:35

선언 주석 원문
Interpolate toward b using a quantized Q0.8 weight. Both shifts discard low
bits, so small changes may vanish and a weight of 255 need not reach b.

kitaqgb/lib/fixed.c:34

c
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8)
{
    // The endpoint difference must fit s16 before the reduced-precision multiplication.
    fix8 d = (fix8)(b - a);
    return (fix8)(a + (fix8)((d >> 4) * (s16)(t_q8 >> 4)));
}
fix_mul

연산 비용이 낮은 근사 방식으로 Q8.8 값 두 개를 곱합니다.

사용 형식

c
fix8 fix_mul(fix8 a, fix8 b);

매개변수

a

Q8.8 형식의 왼쪽 피연산자입니다.

b

Q8.8 형식의 오른쪽 피연산자입니다.

반환값

곱을 Q8.8 형식으로 반환합니다.

사용 조건과 제한

곱셈 전에 각 피연산자를 오른쪽으로 4비트 이동하여 하위 4비트를 버립니다. 따라서 완전한 16×16비트 곱셈보다 정밀도가 낮습니다. fix8은 부호 있는 Q8.8이며 원시값 256이 1.0을 나타냅니다. 중간값과 결과는 16비트 범위 안에 두세요.

사용 예

c
result[2]=fix_mul(384,512);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

1.5와 2.0을 곱하면 3.0(원시값 768)이 됩니다. 원시값 271끼리 곱했을 때 256이 나오는 양자화 사례도 검사합니다.

fix_mul: DMG
DMG
fix_mul: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:28

선언 주석 원문
Approximate 8.8 multiplication by discarding four low bits from each operand
before multiplying. This trades precision for a smaller intermediate product.

kitaqgb/lib/fixed.c:18

c
fix8 fix_mul(fix8 a, fix8 b)
{
    return (fix8)((a >> 4) * (b >> 4));
}
fix_to_int

Q8.8의 소수 비트를 버려 정수 좌표를 추출합니다. 음수는 음의 무한대 방향으로 내림합니다.

사용 형식

c
s16 fix_to_int(fix8 x);

매개변수

x

정수로 변환할 Q8.8 값입니다.

반환값

부호 있는 정수를 반환합니다.

사용 조건과 제한

fix8은 부호 있는 Q8.8 형식입니다. 원시값 256이 1.0을 나타냅니다. 중간값과 결과가 16비트 범위를 벗어나지 않게 하세요.

사용 예

c
result[1]=fix_to_int(-384);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

원시값 −384(−1.5)를 전달하면 −2가 되어 −00002로 표시됩니다. 경계값 검사에서는 원시값 −1도 −1이 되는지 확인합니다.

fix_to_int: DMG
DMG
fix_to_int: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:25

선언 주석 원문
Discard the eight fractional bits using a signed right shift.

kitaqgb/lib/fixed.c:11

c
s16 fix_to_int(fix8 x)
{
    return (s16)(x >> 8);
}
kq_abs_s16

부호 있는 16비트 값의 절댓값을 구합니다.

사용 형식

c
s16 kq_abs_s16(s16 v);

매개변수

v

절댓값을 구할 부호 있는 16비트 값입니다.

반환값

−32768의 절댓값처럼 표현할 수 없는 경우를 제외하고, 0 이상의 절댓값을 반환합니다.

사용 조건과 제한

양의 값 32768은 s16에 들어가지 않습니다. 0 이상의 결과가 필요하다면 입력에서 −32768을 제외하세요.

사용 예

c
result[0]=kq_abs_s16(-123);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 −123을 123으로 바꿉니다. 좌표 차이의 크기를 구할 때와 같은 사용법입니다.

kq_abs_s16: DMG
DMG
kq_abs_s16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math_limits.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:38

선언 주석 원문
Return the magnitude in s16. The most-negative s16 has no positive s16
representation and must be excluded by callers needing a nonnegative result.

kitaqgb/lib/fixed.c:43

c
s16 kq_abs_s16(s16 v)
{
    if (v < 0) return (s16)(0 - v);
    return v;
}
kq_clamp_s16

좌표나 속도를 양 끝값을 포함한 구간 안으로 제한합니다.

사용 형식

c
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);

매개변수

v

제한할 부호 있는 값입니다.

lo

포함되는 하한값입니다.

hi

포함되는 상한값입니다.

반환값

구간보다 작으면 lo, 크면 hi, 구간 안이면 v를 반환합니다.

사용 조건과 제한

lo <= hi를 만족하는 유효한 구간을 지정하세요.

사용 예

c
result[3]=kq_clamp_s16(25,-10,10);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

25를 −10~10으로 제한하면 10이 됩니다. 하한에서 −11→−10, 구간 안에서 3→3인 경우도 검사합니다.

kq_clamp_s16: DMG
DMG
kq_clamp_s16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math_limits.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:44

선언 주석 원문
Clamp to an inclusive interval; callers must provide lo <= hi.

kitaqgb/lib/fixed.c:64

c
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi)
{
    if (v < lo) return lo;
    if (v > hi) return hi;
    return v;
}
kq_max_s16

부호 있는 16비트 값 두 개 중 큰 값을 선택합니다.

사용 형식

c
s16 kq_max_s16(s16 a, s16 b);

매개변수

a

비교할 첫 번째 부호 있는 값입니다.

b

비교할 두 번째 부호 있는 값입니다.

반환값

선택한 피연산자를 반환합니다.

사용 조건과 제한

부호를 고려하여 비교합니다. 두 피연산자가 같으면 그 값을 반환하며, 입력값은 수정하지 않습니다.

사용 예

c
result[2]=kq_max_s16(-7,4);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

−7과 4를 비교하면 4가 나옵니다. 음수 결과에는 마이너스 기호가 표시됩니다.

kq_max_s16: DMG
DMG
kq_max_s16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math_limits.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:42

선언 주석 원문
Select the larger signed value.

kitaqgb/lib/fixed.c:57

c
s16 kq_max_s16(s16 a, s16 b)
{
    if (a > b) return a;
    return b;
}
kq_min_s16

부호 있는 16비트 값 두 개 중 작은 값을 선택합니다.

사용 형식

c
s16 kq_min_s16(s16 a, s16 b);

매개변수

a

비교할 첫 번째 부호 있는 값입니다.

b

비교할 두 번째 부호 있는 값입니다.

반환값

선택한 피연산자를 반환합니다.

사용 조건과 제한

부호를 고려하여 비교합니다. 두 피연산자가 같으면 그 값을 반환하며, 입력값은 수정하지 않습니다.

사용 예

c
result[1]=kq_min_s16(-7,4);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

−7과 4를 비교하면 -7이 나옵니다. 음수 결과에는 마이너스 기호가 표시됩니다.

kq_min_s16: DMG
DMG
kq_min_s16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_math_limits.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_math_limits.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:40

선언 주석 원문
Select the smaller signed value.

kitaqgb/lib/fixed.c:50

c
s16 kq_min_s16(s16 a, s16 b)
{
    if (a < b) return a;
    return b;
}
kq_point_in_rect

점이 사각형 안에 있는지 검사하며, 왼쪽과 위쪽 경계는 포함합니다.

사용 형식

c
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);

매개변수

x

사각형과 같은 좌표계에서의 점 X 좌표입니다.

y

점의 Y 좌표입니다.

r

검사할 사각형이며 값으로 전달합니다.

반환값

안에 있으면 1, 밖에 있으면 0을 반환합니다.

사용 조건과 제한

너비와 높이는 양수여야 하며, 좌표와 크기의 합을 s16으로 표현할 수 있어야 합니다. 오른쪽과 아래쪽 경계는 포함하지 않습니다. 면적이 0인 사각형을 명시적으로 거부하지는 않습니다.

사용 예

c
result[1]=kq_point_in_rect(9,1,a);
for(gy=0;gy<11;gy++){for(gx=0;gx<15;gx++){
inside_a=kq_point_in_rect(gx,gy,a);inside_b=kq_point_in_rect(gx,gy,b);
tile=0;if(inside_a){tile=65;result[3]=result[3]+1;}if(inside_b)tile=66;if(inside_a && inside_b){tile=79;result[4]=result[4]+1;}
m_put(1+gx,2+gy,tile);if(tile!=0)vram_example_color(1+gx,2+gy,1,1,tile==65?1:(tile==66?2:3));
}}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

좌표 1단위는 타일 하나입니다. (1,1)의 사각형 A와 (5,4)의 사각형 B는 모두 8×6 크기입니다. A만 차지하는 칸은 A, B만 차지하는 칸은 B로 표시하고, 4×3 겹침 영역의 12칸은 O로 표시합니다. A의 오른쪽 가장자리 x=9는 포함하지 않습니다. CGB에서는 A가 빨간색, B가 파란색, O가 초록색입니다.

kq_point_in_rect: DMG
DMG
kq_point_in_rect: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_geometry.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:51

선언 주석 원문
Test a half-open rectangle: left/top edges are included, right/bottom excluded.
The coordinate-plus-size sums must remain representable as s16.

kitaqgb/lib/fixed.c:85

c
u8 kq_point_in_rect(s16 x, s16 y, KQRect r)
{
    if (x < r.x) return 0;
    if (y < r.y) return 0;
    if (x >= (s16)(r.x + r.w)) return 0;
    if (y >= (s16)(r.y + r.h)) return 0;
    return 1;
}
kq_rect_intersect

축에 정렬된 두 사각형이 면적을 가지며 겹치는지 검사합니다.

사용 형식

c
u8 kq_rect_intersect(KQRect a, KQRect b);

매개변수

a

값으로 전달하는 첫 번째 사각형입니다. x, y는 왼쪽 위 모서리, w, h는 너비와 높이입니다.

b

A와 같은 좌표계를 사용하는 두 번째 사각형입니다.

반환값

겹치면 1, 떨어져 있거나 가장자리만 닿으면 0을 반환합니다.

사용 조건과 제한

너비와 높이는 양수여야 하며, 좌표와 크기의 합을 s16으로 표현할 수 있어야 합니다. 오른쪽과 아래쪽 경계는 포함하지 않습니다. 면적이 0인 사각형을 명시적으로 거부하지는 않습니다.

사용 예

c
result[0]=kq_rect_intersect(a,b);result[2]=kq_rect_intersect(a,touch);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

좌표 1단위는 타일 하나입니다. (1,1)의 사각형 A와 (5,4)의 사각형 B는 모두 8×6 크기입니다. A만 차지하는 칸은 A, B만 차지하는 칸은 B로 표시하고, 4×3 겹침 영역의 12칸은 O로 표시합니다. A의 오른쪽 가장자리 x=9는 포함하지 않습니다. CGB에서는 A가 빨간색, B가 파란색, O가 초록색입니다.

kq_rect_intersect: DMG
DMG
kq_rect_intersect: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_geometry.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_geometry.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/fixed.h:48

선언 주석 원문
Test overlap using exclusive right/bottom edges; touching edges do not collide.
Require positive dimensions and edge sums that fit s16; zero-sized rectangles
are not explicitly rejected and may be reported as overlapping.

kitaqgb/lib/fixed.c:74

c
u8 kq_rect_intersect(KQRect a, KQRect b)
{
    if ((s16)(a.x + a.w) <= b.x) return 0;
    if ((s16)(b.x + b.w) <= a.x) return 0;
    if ((s16)(a.y + a.h) <= b.y) return 0;
    if ((s16)(b.y + b.h) <= a.y) return 0;
    return 1;
}

input.h — 버튼 상태, 누름, 놓음, 반복 입력

연속 이동에는 input_down, 한 번 실행할 동작에는 input_pressed, 버튼을 뗄 때의 정지에는 input_released, 메뉴 반복에는 input_repeat를 사용합니다. 한 번 초기화하고 입력 틱마다 한 번 갱신한 뒤 필요한 만큼 조회하세요. btn_down, btn_pressed, btn_released, btn_repeat는 네 조회 함수의 별칭입니다.

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

반복 시간은 밀리초가 아니라 갱신 횟수입니다. 새로 누르면 즉시 출력하며 기본값 INPUT_REPEAT_DELAY=18, INPUT_REPEAT_RATE=5에서는 19번 뒤, 이후 6번마다 펄스가 나옵니다. 버튼별 카운터는 독립적입니다. 값을 바꾸려면 input.c를 컴파일할 때도 같은 매크로 값을 적용해야 합니다. 호출자 헤더만 바꿔서는 라이브러리 설정이 바뀌지 않습니다.

btn_down

btn_down은 input_down의 별칭입니다. 선택한 버튼 중 하나라도 현재 눌려 있는지 확인합니다.

mask에 지정한 버튼 중 현재 누르고 있는 버튼이 있는지 반환합니다.

사용 형식

c
u8 btn_down(u8 mask);

매개변수

mask

BTN_* 하나 또는 여러 값을 |로 결합한 마스크입니다. 선택한 버튼 중 하나라도 해당하면 참이므로 BTN_A | BTN_B가 두 버튼의 동시 누름을 요구하지는 않습니다. 마스크 0은 항상 0을 반환합니다. 모두 눌렸는지는 (input_current() & mask) == mask로 확인하세요.

반환값

선택한 버튼 중 하나라도 조회 조건에 맞으면 정확히 1, 아니면 0입니다. 반환값은 버튼 비트 마스크가 아닙니다。

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

input_down

사용 예

c
if (btn_down(BTN_A)!=0) held_ticks++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

btn_down: DMG
DMG
btn_down: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_aliases.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:48

c
#define btn_down input_down

kitaqgb/lib/input.c:68

c
u8 input_down(u8 mask)
{
    return (u8)((kq_input_keys & mask) != 0);
}
btn_pressed

btn_pressed는 input_pressed의 별칭입니다. 최근 입력 갱신에서 선택한 버튼 중 하나라도 새로 눌렸는지 확인합니다.

최근 입력 갱신에서 마스크에 해당하는 버튼이 눌리지 않은 상태에서 눌린 상태로 바뀌었는지 반환합니다.

사용 형식

c
u8 btn_pressed(u8 mask);

매개변수

mask

BTN_* 하나 또는 여러 값을 |로 결합한 마스크입니다. 선택한 버튼 중 하나라도 해당하면 참이므로 BTN_A | BTN_B가 두 버튼의 동시 누름을 요구하지는 않습니다. 마스크 0은 항상 0을 반환합니다. 모두 눌렸는지는 (input_current() & mask) == mask로 확인하세요.

반환값

선택한 버튼 중 하나라도 조회 조건에 맞으면 정확히 1, 아니면 0입니다. 반환값은 버튼 비트 마스크가 아닙니다。

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

input_pressed

사용 예

c
if (btn_pressed(BTN_A)!=0) {
        press_count++; seen_press=1;
        first_down=btn_down(BTN_A); first_press=btn_pressed(BTN_A);
        first_repeat=btn_repeat(BTN_A);
        first_current=input_current(); // Only A held: BTN_A, or decimal 16.
        first_previous=input_previous(); // No buttons in the preceding sample: 0.
        if (first_down!=1 || first_press!=1 || first_repeat!=1) failures++;
        if (first_current!=BTN_A || first_previous!=0) failures++;
        if (btn_down(BTN_A|BTN_B)!=1 || btn_down(0)!=0) failures++;
    }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

btn_pressed: DMG
DMG
btn_pressed: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_aliases.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:49

c
#define btn_pressed input_pressed

kitaqgb/lib/input.c:74

c
u8 input_pressed(u8 mask)
{
    return (u8)((kq_input_press_keys & mask) != 0);
}
btn_released

btn_released는 input_released의 별칭입니다. 최근 입력 갱신에서 선택한 버튼 중 하나라도 놓였는지 확인합니다.

최근 입력 갱신에서 마스크에 해당하는 버튼이 눌린 상태에서 놓인 상태로 바뀌었는지 반환합니다.

사용 형식

c
u8 btn_released(u8 mask);

매개변수

mask

BTN_* 하나 또는 여러 값을 |로 결합한 마스크입니다. 선택한 버튼 중 하나라도 해당하면 참이므로 BTN_A | BTN_B가 두 버튼의 동시 누름을 요구하지는 않습니다. 마스크 0은 항상 0을 반환합니다. 모두 눌렸는지는 (input_current() & mask) == mask로 확인하세요.

반환값

선택한 버튼 중 하나라도 조회 조건에 맞으면 정확히 1, 아니면 0입니다. 반환값은 버튼 비트 마스크가 아닙니다。

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

input_released

사용 예

c
if (btn_released(BTN_A)!=0) {
        release_result=btn_released(BTN_A);
        last_current=input_current(); last_previous=input_previous();
        if (btn_down(BTN_A)!=0 || btn_pressed(BTN_A)!=0 || btn_repeat(BTN_A)!=0) failures++;
        break;
    }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

btn_released: DMG
DMG
btn_released: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_aliases.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:50

c
#define btn_released input_released

kitaqgb/lib/input.c:80

c
u8 input_released(u8 mask)
{
    return (u8)((kq_input_release_keys & mask) != 0);
}
btn_repeat

btn_repeat는 input_repeat의 별칭입니다. 최초 누름이나 누르고 있는 동안 정해진 시점에 발생하는 반복 신호를 확인합니다.

마스크에 해당하는 버튼의 첫 누름 또는 반복 입력 발생 여부를 반환합니다.

사용 형식

c
u8 btn_repeat(u8 mask);

매개변수

mask

BTN_* 하나 또는 여러 값을 |로 결합한 마스크입니다. 선택한 버튼 중 하나라도 해당하면 참이므로 BTN_A | BTN_B가 두 버튼의 동시 누름을 요구하지는 않습니다. 마스크 0은 항상 0을 반환합니다. 모두 눌렸는지는 (input_current() & mask) == mask로 확인하세요.

반환값

선택한 버튼 중 하나라도 조회 조건에 맞으면 정확히 1, 아니면 0입니다. 반환값은 버튼 비트 마스크가 아닙니다。

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

반복 시간은 밀리초가 아니라 갱신 횟수입니다. 새로 누르면 즉시 출력하며 기본값 INPUT_REPEAT_DELAY=18, INPUT_REPEAT_RATE=5에서는 19번 뒤, 이후 6번마다 펄스가 나옵니다. 버튼별 카운터는 독립적입니다. 값을 바꾸려면 input.c를 컴파일할 때도 같은 매크로 값을 적용해야 합니다. 호출자 헤더만 바꿔서는 라이브러리 설정이 바뀌지 않습니다.

input_repeat

사용 예

c
if (btn_repeat(BTN_A)!=0) {
        // The initial press is pulse 1. Defaults then wait 19 updates, followed by 6.
        if (repeat_count==1 && held_ticks-previous_pulse!=19) failures++;
        if (repeat_count>1 && held_ticks-previous_pulse!=6) failures++;
        previous_pulse=held_ticks; repeat_count++;
        if (btn_repeat(BTN_A)!=1) failures++; // Reading again does not consume it.
    }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

btn_repeat: DMG
DMG
btn_repeat: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_aliases.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:51

c
#define btn_repeat input_repeat

kitaqgb/lib/input.c:86

c
u8 input_repeat(u8 mask)
{
    return (u8)((kq_input_repeat_keys & mask) != 0);
}
input_current

최근 입력 갱신에서 얻은 전체 버튼 유지 마스크를 반환합니다.

사용 형식

c
u8 input_current();

반환값

공통 BTN_* 형식의 8비트 마스크입니다. 여러 버튼 비트가 동시에 설정될 수 있으며 0은 해당 버튼이 없음을 뜻합니다.

사용 조건과 제한

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

사용 예

c
first_current=input_current(); // Only A held: BTN_A, or decimal 16.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

input_current: DMG
DMG
input_current: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:44

선언 주석 원문
Return the complete held-button mask from the latest update.

kitaqgb/lib/input.c:92

c
u8 input_current()
{
    return kq_input_keys;
}
input_down

mask에 지정한 버튼 중 현재 누르고 있는 버튼이 있는지 반환합니다.

사용 형식

c
u8 input_down(u8 mask);

매개변수

mask

BTN_* 하나 또는 여러 값을 |로 결합한 마스크입니다. 선택한 버튼 중 하나라도 해당하면 참이므로 BTN_A | BTN_B가 두 버튼의 동시 누름을 요구하지는 않습니다. 마스크 0은 항상 0을 반환합니다. 모두 눌렸는지는 (input_current() & mask) == mask로 확인하세요.

반환값

선택한 버튼 중 하나라도 조회 조건에 맞으면 정확히 1, 아니면 0입니다. 반환값은 버튼 비트 마스크가 아닙니다。

사용 조건과 제한

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

사용 예

c
if (input_down(BTN_A)!=0) held_ticks++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

input_down: DMG
DMG
input_down: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:36

선언 주석 원문
Return whether any masked button is currently held.

kitaqgb/lib/input.c:68

c
u8 input_down(u8 mask)
{
    return (u8)((kq_input_keys & mask) != 0);
}
input_init

현재·이전·누름·뗌·반복 마스크를 모두 0으로 만들고 8개 반복 타이머를 INPUT_REPEAT_DELAY로 초기화합니다. 컨트롤러를 읽지는 않습니다. 다음 첫 갱신에서 눌려 있는 버튼은 새로 누른 것으로 처리합니다.

사용 형식

c
void input_init();

반환값

없음(void).

사용 조건과 제한

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

반복 시간은 밀리초가 아니라 갱신 횟수입니다. 새로 누르면 즉시 출력하며 기본값 INPUT_REPEAT_DELAY=18, INPUT_REPEAT_RATE=5에서는 19번 뒤, 이후 6번마다 펄스가 나옵니다. 버튼별 카운터는 독립적입니다. 값을 바꾸려면 input.c를 컴파일할 때도 같은 매크로 값을 적용해야 합니다. 호출자 헤더만 바꿔서는 라이브러리 설정이 바뀌지 않습니다.

사용 예

c
input_init();
if (input_current()!=0 || input_previous()!=0) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

input_init: DMG
DMG
input_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:31

선언 주석 원문
Clear sampled/edge state and initialize an independent repeat timer for each button.

kitaqgb/lib/input.c:18

c
void input_init()
{
    u8 i;
    kq_input_prev_keys = 0;
    kq_input_keys = 0;
    kq_input_press_keys = 0;
    kq_input_release_keys = 0;
    kq_input_repeat_keys = 0;
    i = 0;
    while (i < 8) {
        input_repeat_timer[i] = INPUT_REPEAT_DELAY;
        i++;
    }
}
input_pressed

최근 입력 갱신에서 마스크에 해당하는 버튼이 눌리지 않은 상태에서 눌린 상태로 바뀌었는지 반환합니다.

사용 형식

c
u8 input_pressed(u8 mask);

매개변수

mask

BTN_* 하나 또는 여러 값을 |로 결합한 마스크입니다. 선택한 버튼 중 하나라도 해당하면 참이므로 BTN_A | BTN_B가 두 버튼의 동시 누름을 요구하지는 않습니다. 마스크 0은 항상 0을 반환합니다. 모두 눌렸는지는 (input_current() & mask) == mask로 확인하세요.

반환값

선택한 버튼 중 하나라도 조회 조건에 맞으면 정확히 1, 아니면 0입니다. 반환값은 버튼 비트 마스크가 아닙니다。

사용 조건과 제한

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

사용 예

c
if (input_pressed(BTN_A)!=0) {
        press_count++; seen_press=1;
        first_down=input_down(BTN_A); first_press=input_pressed(BTN_A);
        first_repeat=input_repeat(BTN_A);
        first_current=input_current(); // Only A held: BTN_A, or decimal 16.
        first_previous=input_previous(); // No buttons in the preceding sample: 0.
        if (first_down!=1 || first_press!=1 || first_repeat!=1) failures++;
        if (first_current!=BTN_A || first_previous!=0) failures++;
        if (input_down(BTN_A|BTN_B)!=1 || input_down(0)!=0) failures++;
    }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

input_pressed: DMG
DMG
input_pressed: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:38

선언 주석 원문
Return whether any masked button became pressed in the latest sample.

kitaqgb/lib/input.c:74

c
u8 input_pressed(u8 mask)
{
    return (u8)((kq_input_press_keys & mask) != 0);
}
input_previous

최근 입력 갱신 직전에 저장된 버튼 유지 마스크를 반환합니다.

사용 형식

c
u8 input_previous();

반환값

공통 BTN_* 형식의 8비트 마스크입니다. 여러 버튼 비트가 동시에 설정될 수 있으며 0은 해당 버튼이 없음을 뜻합니다.

사용 조건과 제한

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

사용 예

c
first_previous=input_previous(); // No buttons in the preceding sample: 0.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

input_previous: DMG
DMG
input_previous: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:46

선언 주석 원문
Return the held-button mask that preceded the latest update.

kitaqgb/lib/input.c:98

c
u8 input_previous()
{
    return kq_input_prev_keys;
}
input_released

최근 입력 갱신에서 마스크에 해당하는 버튼이 눌린 상태에서 놓인 상태로 바뀌었는지 반환합니다.

사용 형식

c
u8 input_released(u8 mask);

매개변수

mask

BTN_* 하나 또는 여러 값을 |로 결합한 마스크입니다. 선택한 버튼 중 하나라도 해당하면 참이므로 BTN_A | BTN_B가 두 버튼의 동시 누름을 요구하지는 않습니다. 마스크 0은 항상 0을 반환합니다. 모두 눌렸는지는 (input_current() & mask) == mask로 확인하세요.

반환값

선택한 버튼 중 하나라도 조회 조건에 맞으면 정확히 1, 아니면 0입니다. 반환값은 버튼 비트 마스크가 아닙니다。

사용 조건과 제한

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

사용 예

c
if (input_released(BTN_A)!=0) {
        release_result=input_released(BTN_A);
        last_current=input_current(); last_previous=input_previous();
        if (input_down(BTN_A)!=0 || input_pressed(BTN_A)!=0 || input_repeat(BTN_A)!=0) failures++;
        break;
    }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

input_released: DMG
DMG
input_released: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:40

선언 주석 원문
Return whether any masked button became released in the latest sample.

kitaqgb/lib/input.c:80

c
u8 input_released(u8 mask)
{
    return (u8)((kq_input_release_keys & mask) != 0);
}
input_repeat

마스크에 해당하는 버튼의 첫 누름 또는 반복 입력 발생 여부를 반환합니다.

사용 형식

c
u8 input_repeat(u8 mask);

매개변수

mask

BTN_* 하나 또는 여러 값을 |로 결합한 마스크입니다. 선택한 버튼 중 하나라도 해당하면 참이므로 BTN_A | BTN_B가 두 버튼의 동시 누름을 요구하지는 않습니다. 마스크 0은 항상 0을 반환합니다. 모두 눌렸는지는 (input_current() & mask) == mask로 확인하세요.

반환값

선택한 버튼 중 하나라도 조회 조건에 맞으면 정확히 1, 아니면 0입니다. 반환값은 버튼 비트 마스크가 아닙니다。

사용 조건과 제한

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

조회 함수는 마지막 input_update()가 저장한 값을 읽습니다. 다시 폴링하거나 에지를 소비하거나 반복 타이머를 진행하지 않습니다. 같은 틱에서 여러 번 조회해도 결과는 같습니다. 버튼을 누른 채 input_update()를 두 번 호출하면 두 번째 호출에서는 새 누름 에지가 사라집니다.

반복 시간은 밀리초가 아니라 갱신 횟수입니다. 새로 누르면 즉시 출력하며 기본값 INPUT_REPEAT_DELAY=18, INPUT_REPEAT_RATE=5에서는 19번 뒤, 이후 6번마다 펄스가 나옵니다. 버튼별 카운터는 독립적입니다. 값을 바꾸려면 input.c를 컴파일할 때도 같은 매크로 값을 적용해야 합니다. 호출자 헤더만 바꿔서는 라이브러리 설정이 바뀌지 않습니다.

사용 예

c
if (input_repeat(BTN_A)!=0) {
        // The initial press is pulse 1. Defaults then wait 19 updates, followed by 6.
        if (repeat_count==1 && held_ticks-previous_pulse!=19) failures++;
        if (repeat_count>1 && held_ticks-previous_pulse!=6) failures++;
        previous_pulse=held_ticks; repeat_count++;
        if (input_repeat(BTN_A)!=1) failures++; // Reading again does not consume it.
    }

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

input_repeat: DMG
DMG
input_repeat: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:42

선언 주석 원문
Return whether any masked button produced a fresh press or scheduled repeat pulse.

kitaqgb/lib/input.c:86

c
u8 input_repeat(u8 mask)
{
    return (u8)((kq_input_repeat_keys & mask) != 0);
}
input_update

현재 마스크를 이전 값으로 저장하고 __readpadex로 게임보이 버튼을 읽어 뗀 버튼을 계산합니다. 버튼별 반복 타이머도 한 단계씩 진행합니다. 게임의 입력 틱마다 한 번 호출한 다음 저장된 상태를 조회하세요.

사용 형식

c
void input_update();

반환값

없음(void).

사용 조건과 제한

공통 마스크는 BTN_RIGHT=0x01, BTN_LEFT=0x02, BTN_UP=0x04, BTN_DOWN=0x08, BTN_A=0x10, BTN_B=0x20, BTN_SELECT=0x40, BTN_START=0x80입니다. 1인 비트가 눌림을 뜻합니다. GB와 FC의 input_*는 이 형식을 쓰지만 FC의 원시 패드 함수는 비트 순서가 다릅니다.

반복 시간은 밀리초가 아니라 갱신 횟수입니다. 새로 누르면 즉시 출력하며 기본값 INPUT_REPEAT_DELAY=18, INPUT_REPEAT_RATE=5에서는 19번 뒤, 이후 6번마다 펄스가 나옵니다. 버튼별 카운터는 독립적입니다. 값을 바꾸려면 input.c를 컴파일할 때도 같은 매크로 값을 적용해야 합니다. 호출자 헤더만 바꿔서는 라이브러리 설정이 바뀌지 않습니다.

사용 예

c
input_update(); // One update per input tick, followed by any number of queries.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

버튼을 누르고 있는 상태, 처음 누른 순간, 뗀 순간, 자동 반복의 차이를 보여 주는 프로그램입니다. A를 40회 갱신 동안 누른 뒤 놓습니다. FIRST DOWN, FIRST PRESS, FIRST REPEAT는 1이고 FIRST CURRENT는 16입니다. HELD TICKS는 40, PRESS COUNT는 1, REPEAT COUNT는 5입니다. 버튼을 놓으면 RELEASE는 1, LAST CURRENT는 0, LAST PREVIOUS는 16이 됩니다. FAILED CHECKS는 0이어야 합니다. 누르는 시간을 바꾸면 횟수도 달라지며, 프로그램은 실제로 관측한 시간을 기준으로 반복 간격을 검사합니다.

input_update: DMG
DMG
input_update: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\input.c .\kitaq-docs\samples\api-examples\gb\input_edges.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\input_edges.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-disasm --no-cache
구현과 소스

kitaqgb/lib/input.h:34

선언 주석 원문
Sample input once per game tick and derive press, release and repeat masks.
Repeat delays are measured in calls to this function, not elapsed wall-clock time.

kitaqgb/lib/input.c:35

c
void input_update()
{
    u8 i;
    u16 kt;

    kq_input_prev_keys = kq_input_keys;
    // The intrinsic packs held buttons in the low byte and new presses in the high byte.
    kt = __readpadex(kq_input_prev_keys);
    kq_input_keys = (u8)kt;
    kq_input_press_keys = (u8)(kt >> 8);
    kq_input_release_keys = (u8)(kq_input_prev_keys & (u8)(kq_input_keys ^ 0xFF));
    kq_input_repeat_keys = kq_input_press_keys;

    i = 0;
    while (i < 8) {
        u8 mask = input_mask_for_index(i);
        if ((kq_input_keys & mask) != 0) {
            if ((kq_input_press_keys & mask) != 0) {
                input_repeat_timer[i] = INPUT_REPEAT_DELAY;
            } else if (input_repeat_timer[i] != 0) {
                input_repeat_timer[i]--;
            } else {
                kq_input_repeat_keys = (u8)(kq_input_repeat_keys | mask);
                input_repeat_timer[i] = INPUT_REPEAT_RATE;
            }
        } else {
            input_repeat_timer[i] = INPUT_REPEAT_DELAY;
        }
        i++;
    }
}

라이브러리는 바이트 교환, 최대 24바이트 패킷, 상대별 큐의 세 계층을 제공합니다. BYTE MASTER/SLAVE부터 PACKET, LINK4 순으로 진행하여 클록 공급 주체와 수신 준비 상태를 익히세요. 한 프로그램에서 하드웨어 레지스터 단위, link.c, link_packet.c를 각각 정확히 한 번 포함해야 하며 gb_link_example.h가 이 순서를 제공합니다.

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

양쪽 끝에서 계속 폴링하세요. 시간 초과는 하드웨어 프레임이 아니라 진행 없이 90번 호출한 횟수로 셉니다. ACK용 클록만 공급하려고 0xFF를 보내도 기한이 늘어나지 않습니다. 전송은 최대 세 번 시도합니다. 재시도로 중복 수신할 수 있으므로 명령이 정확히 한 번만 실행되어야 한다면 애플리케이션 수준의 식별자를 추가하세요.

Link4_BeginTransferTo

목적지를 선택하고 바이트 교환 하나를 시작합니다.

사용 형식

c
u8 __stackcall Link4_BeginTransferTo(u8 peer_slot, u8 out);

매개변수

peer_slot

설정된 원격 슬롯입니다. 호스트에서는 1~slot_count−1, 상대에서는 0입니다.

out

송신할 8비트 값입니다.

반환값

선택·시작 중 처음 발생한 오류를 반환하며 성공하면 0입니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

오류 코드는 0=없음, 1=사용 중, 2=시간 초과, 3=수신 오버플로, 4=잘못된 설정·프로토콜, 5=연결 해제와 비슷한 응답이 동반된 ACK 시간 초과입니다. 시작·설정 호출의 성공값은 0, 수신·꺼내기 호출의 성공값은 1입니다. 성공한 호출도 저장된 오류를 지우지 않습니다.

Link4는 수신 바이트를 일반 링과 상대별 링 양쪽에 복사합니다. 한쪽을 읽어도 다른 쪽의 데이터는 줄지 않습니다. 패킷 폴링은 일반 링을 소비하므로 오버플로를 막으려면 쓰지 않는 상대별 원시 바이트도 주기적으로 버리세요.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[6+slot]=Link4_BeginTransferTo(slot,16+slot);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_BeginTransferTo: DMG
DMG
Link4_BeginTransferTo: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:129

선언 주석 원문
Select the logical peer and start a byte exchange, returning the first error.

kitaqgb/lib/link.c:584

c
u8 __stackcall Link4_BeginTransferTo(u8 peer_slot, u8 out) {
    u8 err = Link4_SelectPeer(peer_slot);
    if (err != LINK_ERR_NONE) return err;
    return Link_BeginTransfer(out);
}
Link4_GetLastRxPeer

마지막으로 수신 완료한 바이트의 상대를 읽습니다.

사용 형식

c
u8 Link4_GetLastRxPeer();

반환값

호스트는 선택된 상대, 상대는 0을 반환합니다. 수신 전에는 255입니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

설정과 이력을 읽는 함수들입니다. 물리 연결을 탐지하거나 모든 상대를 조회하거나 전송 완료를 기다리지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[19]=Link4_GetLastRxPeer();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_GetLastRxPeer: DMG
DMG
Link4_GetLastRxPeer: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:121

선언 주석 원문
Return the peer attributed to the last completed byte transfer.

kitaqgb/lib/link.c:540

c
u8 Link4_GetLastRxPeer() {
    return Link4_LastRxPeer;
}
Link4_GetLastTxPeer

마지막 바이트 전송이 시작될 때 기록된 목적지를 읽습니다.

사용 형식

c
u8 Link4_GetLastTxPeer();

반환값

기록된 목적지를 반환하며 한 번도 시작하지 않았으면 255입니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

설정과 이력을 읽는 함수들입니다. 물리 연결을 탐지하거나 모든 상대를 조회하거나 전송 완료를 기다리지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[20]=Link4_GetLastTxPeer();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_GetLastTxPeer: DMG
DMG
Link4_GetLastTxPeer: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:123

선언 주석 원문
Return the peer attributed when the last byte transfer was started.

kitaqgb/lib/link.c:545

c
u8 Link4_GetLastTxPeer() {
    return Link4_LastTxPeer;
}
Link4_GetLocalSlot

이 기기에 설정된 슬롯을 읽습니다.

사용 형식

c
u8 Link4_GetLocalSlot();

반환값

호스트는 0, 상대는 1~3입니다. 미설정 상태도 0을 반환합니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

설정과 이력을 읽는 함수들입니다. 물리 연결을 탐지하거나 모든 상대를 조회하거나 전송 완료를 기다리지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[2]=Link4_GetLocalSlot();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_GetLocalSlot: DMG
DMG
Link4_GetLocalSlot: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:115

선언 주석 원문
Return the configured zero-based local slot.

kitaqgb/lib/link.c:525

c
u8 Link4_GetLocalSlot() {
    return Link4_LocalSlot;
}
Link4_GetMode

설정된 논리 역할을 읽습니다.

사용 형식

c
u8 Link4_GetMode();

반환값

0=미설정, 1=호스트, 2=상대입니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

설정과 이력을 읽는 함수들입니다. 물리 연결을 탐지하거나 모든 상대를 조회하거나 전송 완료를 기다리지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[1]=Link4_GetMode();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_GetMode: DMG
DMG
Link4_GetMode: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:113

선언 주석 원문
Return the configured cooperative role; this is not a hardware connection probe.

kitaqgb/lib/link.c:520

c
u8 Link4_GetMode() {
    return Link4_ModeState;
}
Link4_GetSelectedPeer

현재 선택된 논리 목적지를 읽습니다.

사용 형식

c
u8 Link4_GetSelectedPeer();

반환값

호스트는 선택한 상대를, 상대는 0을, 미설정 상태는 255를 반환합니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

설정과 이력을 읽는 함수들입니다. 물리 연결을 탐지하거나 모든 상대를 조회하거나 전송 완료를 기다리지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[4]=Link4_GetSelectedPeer();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_GetSelectedPeer: DMG
DMG
Link4_GetSelectedPeer: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:119

선언 주석 원문
Return the current logical destination, or the invalid-slot sentinel when unset.

kitaqgb/lib/link.c:535

c
u8 Link4_GetSelectedPeer() {
    return Link4_SelectedPeer;
}
Link4_GetSlotCount

설정된 전체 슬롯 수를 읽습니다.

사용 형식

c
u8 Link4_GetSlotCount();

반환값

유효한 설정에서는 2~4, 미설정에서는 0을 반환합니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

설정과 이력을 읽는 함수들입니다. 물리 연결을 탐지하거나 모든 상대를 조회하거나 전송 완료를 기다리지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[3]=Link4_GetSlotCount();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_GetSlotCount: DMG
DMG
Link4_GetSlotCount: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:117

선언 주석 원문
Return the configured number of logical slots, not a live connection count.

kitaqgb/lib/link.c:530

c
u8 Link4_GetSlotCount() {
    return Link4_SlotCount;
}
Link4_HasByteFrom

특정 상대의 수신 링에서 읽지 않은 데이터가 있는지 확인합니다.

사용 형식

c
u8 __stackcall Link4_HasByteFrom(u8 peer_slot);

매개변수

peer_slot

설정된 원격 슬롯입니다. 호스트에서는 1~slot_count−1, 상대에서는 0입니다.

반환값

큐에 데이터가 있으면 1, 비어 있거나 상대가 잘못되었으면 0입니다.

사용 조건과 제한

8개 항목의 수신 링 버퍼에는 7바이트를 담을 수 있습니다. 가득 차면 새 바이트를 버리고 오류 3을 저장합니다. 수신한 0바이트도 유효한 데이터입니다.

Link4는 수신 바이트를 일반 링과 상대별 링 양쪽에 복사합니다. 한쪽을 읽어도 다른 쪽의 데이터는 줄지 않습니다. 패킷 폴링은 일반 링을 소비하므로 오버플로를 막으려면 쓰지 않는 상대별 원시 바이트도 주기적으로 버리세요.

하드웨어를 폴링하지 않는 조회입니다. 잘못된 상대를 지정해도 저장된 오류는 바뀌지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[9+slot]=Link4_HasByteFrom(slot);value=0;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_HasByteFrom: DMG
DMG
Link4_HasByteFrom: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:131

선언 주석 원문
Inspect a valid peer ring without polling the hardware.

kitaqgb/lib/link.c:591

c
u8 __stackcall Link4_HasByteFrom(u8 peer_slot) {
    if (Link4_IsValidRemoteSlotInternal(peer_slot) == 0) return 0;
    if (Link4_RxHead[(__safe_index u8)peer_slot] == Link4_RxTail[(__safe_index u8)peer_slot]) return 0;
    return 1;
}
Link4_HasPacketFrom

원격 슬롯 하나의 수신 완료 패킷 메일박스를 확인합니다.

사용 형식

c
u8 __stackcall Link4_HasPacketFrom(u8 peer_slot);

매개변수

peer_slot

설정된 원격 슬롯입니다. 호스트에서는 1~slot_count−1, 상대에서는 0입니다.

반환값

읽지 않은 패킷이 있으면 1, 비어 있거나 상대가 잘못되었으면 0입니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

패킷은 0xA5, 명령, 길이, 0~24바이트의 페이로드, XOR 체크섬으로 구성됩니다. 응답은 0x79(ACK, 수락) 또는 0x1F(NAK, 거부)입니다. 체크섬은 명령·길이·페이로드의 XOR입니다. 기기마다 공유 패킷 메일박스가 하나 있으며 Link4에는 상대별 메일박스도 하나씩 있습니다.

하드웨어를 폴링하지 않는 조회입니다. 잘못된 상대를 지정해도 저장된 오류는 바뀌지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[9]=Link4_HasPacketFrom(0);result[10]=Link4_ReadPacketFrom(0,&cmd,&len,data);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

4개 슬롯 중 상대 1이면 HOST BYTE=17, COMMAND=65, LENGTH=3, PAYLOAD 2=42가 예상값입니다. CONSUMED=0은 소비 후의 호스트 메일박스 플래그입니다.

Link4_HasPacketFrom: DMG
DMG
Link4_HasPacketFrom: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:142

선언 주석 원문
Inspect the one-packet mailbox for a valid remote slot without consuming it.

kitaqgb/lib/link_packet.c:484

c
u8 __stackcall Link4_HasPacketFrom(u8 peer_slot) {
    return Link4_PacketPeerReady(peer_slot);
}
Link4_InitHost

2~4개 슬롯의 논리 호스트를 초기화하고 상대 1을 선택합니다.

사용 형식

c
u8 __stackcall Link4_InitHost(u8 slot_count);

매개변수

slot_count

호스트를 포함한 슬롯 수로 2~4입니다.

반환값

설정이 유효하면 0, 슬롯 수가 잘못되었으면 4를 반환합니다.

사용 조건과 제한

초기화는 바이트 큐, 패킷, 상대 선택, 오류를 버리고 전송과 시리얼 IRQ 소스를 비활성화합니다. 진행 중인 교환은 보존하지 않습니다.

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

내부 임계 구역은 소프트웨어 중첩 깊이를 추적합니다. 가장 바깥 구역을 나올 때 CPU 인터럽트를 활성화하므로 이전에 비활성화되어 있던 IME 상태가 유지된다고 가정하지 마세요.

검사 전에 초기화합니다. 호출에 실패해도 이전 토폴로지와 읽지 않은 데이터를 버립니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[0]=Link4_InitHost(4);result[1]=Link4_GetMode();result[2]=Link4_GetLocalSlot();result[3]=Link4_GetSlotCount();result[4]=Link4_GetSelectedPeer();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_InitHost: DMG
DMG
Link4_InitHost: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:108

선언 주석 원문
Cooperative 4-player adapter helpers.

This layer models the common host-selected adapter pattern:
- Slot 0 is always the host.
- The host selects one active peer slot at a time.
- Packet mailboxes stay one-deep per peer.
- The original Link_* API remains available for normal 2-player projects.
Reset as master, validate slot count and select logical peer one. Invalid configuration still discards old link state.

kitaqgb/lib/link.c:489

c
u8 __stackcall Link4_InitHost(u8 slot_count) {
    u8 err;

    Link_InitMaster();
    err = Link4_ValidateConfig(LINK4_MODE_HOST, LINK4_HOST_SLOT, slot_count);
    if (err != LINK_ERR_NONE) {
        Link_SetErrorInternal(err);
        return err;
    }

    Link4_ApplyConfig(LINK4_MODE_HOST, LINK4_HOST_SLOT, slot_count);
    return LINK_ERR_NONE;
}
Link4_InitPeer

외부 클록을 사용하는 상대를 초기화하고 호스트 슬롯 0을 선택합니다.

사용 형식

c
u8 __stackcall Link4_InitPeer(u8 local_slot, u8 slot_count);

매개변수

local_slot

로컬 슬롯으로 1~slot_count−1입니다.

slot_count

호스트를 포함한 전체 슬롯 수로 2~4입니다.

반환값

설정이 유효하면 0, 슬롯 수나 로컬 슬롯이 잘못되었으면 4를 반환합니다.

사용 조건과 제한

초기화는 바이트 큐, 패킷, 상대 선택, 오류를 버리고 전송과 시리얼 IRQ 소스를 비활성화합니다. 진행 중인 교환은 보존하지 않습니다.

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

내부 임계 구역은 소프트웨어 중첩 깊이를 추적합니다. 가장 바깥 구역을 나올 때 CPU 인터럽트를 활성화하므로 이전에 비활성화되어 있던 IME 상태가 유지된다고 가정하지 마세요.

검사 전에 초기화합니다. 호출에 실패해도 이전 토폴로지와 읽지 않은 데이터를 버립니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[0]=Link4_InitPeer(1,4);result[1]=Link4_GetMode();result[2]=Link4_GetLocalSlot();result[3]=Link4_GetSlotCount();result[4]=Link4_GetSelectedPeer();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

4개 슬롯 중 상대 1이면 HOST BYTE=17, COMMAND=65, LENGTH=3, PAYLOAD 2=42가 예상값입니다. CONSUMED=0은 소비 후의 호스트 메일박스 플래그입니다.

Link4_InitPeer: DMG
DMG
Link4_InitPeer: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:111

선언 주석 원문
Reset as slave and validate the local nonzero slot and total slot count.
An invalid configuration still discards the previous link state.

kitaqgb/lib/link.c:505

c
u8 __stackcall Link4_InitPeer(u8 local_slot, u8 slot_count) {
    u8 err;

    Link_InitSlave();
    err = Link4_ValidateConfig(LINK4_MODE_PEER, local_slot, slot_count);
    if (err != LINK_ERR_NONE) {
        Link_SetErrorInternal(err);
        return err;
    }

    Link4_ApplyConfig(LINK4_MODE_PEER, local_slot, slot_count);
    return LINK_ERR_NONE;
}
Link4_PollPacket

현재 선택된 상대에 대해 공유 패킷 처리기를 한 번 진행합니다.

사용 형식

c
void Link4_PollPacket();

반환값

반환값은 없습니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

패킷은 0xA5, 명령, 길이, 0~24바이트의 페이로드, XOR 체크섬으로 구성됩니다. 응답은 0x79(ACK, 수락) 또는 0x1F(NAK, 거부)입니다. 체크섬은 명령·길이·페이로드의 XOR입니다. 기기마다 공유 패킷 메일박스가 하나 있으며 Link4에는 상대별 메일박스도 하나씩 있습니다.

양쪽 끝에서 계속 폴링하세요. 시간 초과는 하드웨어 프레임이 아니라 진행 없이 90번 호출한 횟수로 셉니다. ACK용 클록만 공급하려고 0xFF를 보내도 기한이 늘어나지 않습니다. 전송은 최대 세 번 시도합니다. 재시도로 중복 수신할 수 있으므로 명령이 정확히 한 번만 실행되어야 한다면 애플리케이션 수준의 식별자를 추가하세요.

Link4는 수신 바이트를 일반 링과 상대별 링 양쪽에 복사합니다. 한쪽을 읽어도 다른 쪽의 데이터는 줄지 않습니다. 패킷 폴링은 일반 링을 소비하므로 오버플로를 막으려면 쓰지 않는 상대별 원시 바이트도 주기적으로 버리세요.

모든 슬롯을 순환하지 않습니다. 교환이 끝나서 선택이 허용될 때만 상대를 바꾸세요.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
for(i=0;i<50;i++){Link4_PollPacket();while(Link4_TryReadByteFrom(slot,0)){}m_wait();}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_PollPacket: DMG
DMG
Link4_PollPacket: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:140

선언 주석 원문
Advance the shared packet engine; this does not poll every logical peer in turn.

kitaqgb/lib/link_packet.c:479

c
void Link4_PollPacket() {
    Link_PollPacket();
}
Link4_ReadPacketFrom

지정한 상대의 패킷을 복사하고 해당 메일박스에서 소비합니다.

사용 형식

c
u8 __stackcall Link4_ReadPacketFrom(u8 peer_slot, u8 *cmd, u8 *len, u8 *dst);

매개변수

peer_slot

설정된 원격 슬롯입니다. 호스트에서는 1~slot_count−1, 상대에서는 0입니다.

cmd

쓰기 가능한 명령 바이트입니다. null이면 이 출력을 생략합니다.

len

쓰기 가능한 길이 바이트(0~24)입니다. null이면 이 출력을 생략합니다.

dst

24바이트를 담을 수 있는 쓰기 가능한 페이로드 버퍼입니다. null이면 페이로드를 버립니다.

반환값

소비했으면 1, 비어 있거나 상대가 잘못되었으면 0을 반환합니다.

사용 조건과 제한

대상 용량을 지정하는 매개변수는 없습니다. dst를 사용한다면 쓰기 가능한 24바이트를 제공하세요. cmd, len, dst는 각각 독립적으로 null일 수 있습니다. 메일박스 검사와 소비가 다른 코드나 인터럽트와 동시에 진행되지 않도록 직렬화하세요.

공유 메일박스가 같은 상대의 패킷을 가리킬 때만 비웁니다. 다른 상대의 읽지 않은 패킷은 그대로 사용할 수 있습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[9]=Link4_HasPacketFrom(0);result[10]=Link4_ReadPacketFrom(0,&cmd,&len,data);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

4개 슬롯 중 상대 1이면 HOST BYTE=17, COMMAND=65, LENGTH=3, PAYLOAD 2=42가 예상값입니다. CONSUMED=0은 소비 후의 호스트 메일박스 플래그입니다.

Link4_ReadPacketFrom: DMG
DMG
Link4_ReadPacketFrom: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:146

선언 주석 원문
Consume a peer mailbox, copying to optional outputs. A nonnull destination
needs room for the entire payload. Clear the shared mailbox only when it
refers to this same peer.

kitaqgb/lib/link_packet.c:491

c
u8 __stackcall Link4_ReadPacketFrom(u8 peer_slot, u8 *cmd, u8 *len, u8 *dst) {
    u8 i;
    u8 offset;

    if (Link4_PacketPeerReady(peer_slot) == 0) return 0;

    if (cmd != 0) *cmd = Link4_ReceivedPacketCmd[(__safe_index u8)peer_slot];
    if (len != 0) *len = Link4_ReceivedPacketLen[(__safe_index u8)peer_slot];

    if (dst != 0) {
        for (i = 0; i < Link4_ReceivedPacketLen[(__safe_index u8)peer_slot]; ++i) {
            offset = Link4_PacketOffset(peer_slot, i);
            dst[(__safe_index u8)i] = Link4_ReceivedPacketBuf[(__safe_index u8)offset];
        }
    }

    Link4_ReceivedPacketReady[(__safe_index u8)peer_slot] = 0;
    if (Link4_LastPacketPeer == peer_slot) {
        Link_ReceivedPacketReady = 0;
        Link4_LastPacketPeer = LINK4_INVALID_SLOT;
    }
    return 1;
}
Link4_SelectPeer

완료를 폴링하고 유휴 상태일 때만 논리 목적지를 바꿉니다.

사용 형식

c
u8 __stackcall Link4_SelectPeer(u8 peer_slot);

매개변수

peer_slot

설정된 원격 슬롯입니다. 호스트에서는 1~slot_count−1, 상대에서는 0입니다.

반환값

선택하면 0, 바이트·패킷·ACK 상태가 사용 중이면 1, 미설정이거나 잘못된 상대면 4를 반환합니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

오류 코드는 0=없음, 1=사용 중, 2=시간 초과, 3=수신 오버플로, 4=잘못된 설정·프로토콜, 5=연결 해제와 비슷한 응답이 동반된 ACK 시간 초과입니다. 시작·설정 호출의 성공값은 0, 수신·꺼내기 호출의 성공값은 1입니다. 성공한 호출도 저장된 오류를 지우지 않습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[25]=Link4_SelectPeer(1);result[26]=Link_LastError();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_SelectPeer: DMG
DMG
Link4_SelectPeer: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:127

선언 주석 원문
Poll completion, then change the logical destination only while byte and
packet state are idle. A peer can select only the host. No adapter-routing
command is sent here; the transport must provide the matching physical route.

kitaqgb/lib/link.c:552

c
u8 __stackcall Link4_SelectPeer(u8 peer_slot) {
    Link_Poll();

    if (Link4_IsEnabledInternal() == 0) {
        Link_SetErrorInternal(LINK_ERR_PROTOCOL);
        return LINK_ERR_PROTOCOL;
    }

    if (Link_Busy != 0 || Link_PacketState != LINK_PKT_STATE_IDLE || Link_PendingAck != 0) {
        Link_SetErrorInternal(LINK_ERR_BUSY);
        return LINK_ERR_BUSY;
    }

    if (Link4_ModeState == LINK4_MODE_HOST) {
        if (Link4_IsValidRemoteSlotInternal(peer_slot) == 0) {
            Link_SetErrorInternal(LINK_ERR_PROTOCOL);
            return LINK_ERR_PROTOCOL;
        }
        Link4_SelectedPeer = peer_slot;
        return LINK_ERR_NONE;
    }

    if (Link4_ModeState == LINK4_MODE_PEER && peer_slot == LINK4_HOST_SLOT) {
        Link4_SelectedPeer = LINK4_HOST_SLOT;
        return LINK_ERR_NONE;
    }

    Link_SetErrorInternal(LINK_ERR_PROTOCOL);
    return LINK_ERR_PROTOCOL;
}
Link4_SendPacketTo

논리 상대를 선택하고 패킷을 복사하여 전송을 예약합니다.

사용 형식

c
u8 __stackcall Link4_SendPacketTo(u8 peer_slot, const u8 *data, u8 len, u8 cmd);

매개변수

peer_slot

설정된 원격 슬롯입니다. 호스트에서는 1~slot_count−1, 상대에서는 0입니다.

data

len바이트를 읽을 수 있는 원본입니다. len이 0일 때만 null을 허용합니다.

len

페이로드 길이이며 바이트 단위로 0~24입니다.

cmd

애플리케이션이 정의하는 8비트 명령입니다.

반환값

선택·큐 등록 중 처음 발생한 오류를 반환합니다. 0은 수락을 뜻합니다.

사용 조건과 제한

Link4는 논리 호스트 슬롯 0과 상대 슬롯 1~3을 관리합니다. SelectPeer는 물리 배선을 바꾸는 명령을 전송하지 않습니다. KOKURA의 link4 토폴로지는 컴파일러 메타데이터를 통해 선택한 상대를 따릅니다. 실제 DMG-07 프로토콜에는 LinkDmg07을 사용하세요.

오류 코드는 0=없음, 1=사용 중, 2=시간 초과, 3=수신 오버플로, 4=잘못된 설정·프로토콜, 5=연결 해제와 비슷한 응답이 동반된 ACK 시간 초과입니다. 시작·설정 호출의 성공값은 0, 수신·꺼내기 호출의 성공값은 1입니다. 성공한 호출도 저장된 오류를 지우지 않습니다.

패킷은 0xA5, 명령, 길이, 0~24바이트의 페이로드, XOR 체크섬으로 구성됩니다. 응답은 0x79(ACK, 수락) 또는 0x1F(NAK, 거부)입니다. 체크섬은 명령·길이·페이로드의 XOR입니다. 기기마다 공유 패킷 메일박스가 하나 있으며 Link4에는 상대별 메일박스도 하나씩 있습니다.

양쪽 끝에서 계속 폴링하세요. 시간 초과는 하드웨어 프레임이 아니라 진행 없이 90번 호출한 횟수로 셉니다. ACK용 클록만 공급하려고 0xFF를 보내도 기한이 늘어나지 않습니다. 전송은 최대 세 번 시도합니다. 재시도로 중복 수신할 수 있으므로 명령이 정확히 한 번만 실행되어야 한다면 애플리케이션 수준의 식별자를 추가하세요.

Link4는 수신 바이트를 일반 링과 상대별 링 양쪽에 복사합니다. 한쪽을 읽어도 다른 쪽의 데이터는 줄지 않습니다. 패킷 폴링은 일반 링을 소비하므로 오버플로를 막으려면 쓰지 않는 상대별 원시 바이트도 주기적으로 버리세요.

페이로드 검사 전에 상대를 선택합니다. 페이로드가 거부되어도 새 목적지가 선택된 상태로 남을 수 있습니다.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[21+slot]=Link4_SendPacketTo(slot,data,3,64+slot);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_SendPacketTo: DMG
DMG
Link4_SendPacketTo: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:138

선언 주석 원문
Select a logical peer, then copy and schedule a packet; return the first error.

kitaqgb/lib/link_packet.c:472

c
u8 __stackcall Link4_SendPacketTo(u8 peer_slot, const u8 *data, u8 len, u8 cmd) {
    u8 err = Link4_SelectPeer(peer_slot);
    if (err != LINK_ERR_NONE) return err;
    return Link_SendPacket(data, len, cmd);
}
Link4_TryReadByteAny

원격 슬롯을 번호 오름차순으로 검사하여 처음 사용 가능한 바이트를 꺼냅니다.

사용 형식

c
u8 __stackcall Link4_TryReadByteAny(u8 *peer_slot, u8 *out);

매개변수

peer_slot

송신 원본 슬롯을 저장할 쓰기 가능한 바이트입니다. null이면 출처 출력을 생략합니다.

out

쓰기 가능한 바이트 대상입니다. null이면 바이트를 버립니다.

반환값

수신했으면 1, 아니면 0을 반환합니다.

사용 조건과 제한

8개 항목의 수신 링 버퍼에는 7바이트를 담을 수 있습니다. 가득 차면 새 바이트를 버리고 오류 3을 저장합니다. 수신한 0바이트도 유효한 데이터입니다.

Link4는 수신 바이트를 일반 링과 상대별 링 양쪽에 복사합니다. 한쪽을 읽어도 다른 쪽의 데이터는 줄지 않습니다. 패킷 폴링은 일반 링을 소비하므로 오버플로를 막으려면 쓰지 않는 상대별 원시 바이트도 주기적으로 버리세요.

내부 임계 구역은 소프트웨어 중첩 깊이를 추적합니다. 가장 바깥 구역을 나올 때 CPU 인터럽트를 활성화하므로 이전에 비활성화되어 있던 IME 상태가 유지된다고 가정하지 마세요.

자기 슬롯은 건너뜁니다. 낮은 슬롯에 데이터가 계속 쌓이면 그쪽이 우선됩니다. 순환 방식의 공정성이 필요하면 상대별 읽기를 사용하세요.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
else {other=255;Link4_TryReadByteAny(&other,&value);result[12+slot]=other;}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_TryReadByteAny: DMG
DMG
Link4_TryReadByteAny: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:136

선언 주석 원문
Scan remote rings in increasing slot order and return the first available
byte. Null output pointers are allowed; lower slots have polling priority.

kitaqgb/lib/link.c:604

c
u8 __stackcall Link4_TryReadByteAny(u8 *peer_slot, u8 *out) {
    u8 slot;

    if (Link4_IsEnabledInternal() == 0) return 0;

    for (slot = 0; slot < Link4_SlotCount; ++slot) {
        if (slot != Link4_LocalSlot) {
            if (Link4_PopRxByte(slot, out) != 0) {
                if (peer_slot != 0) *peer_slot = slot;
                return 1;
            }
        }
    }

    return 0;
}
Link4_TryReadByteFrom

지정한 상대의 수신 링에서 바이트 하나를 꺼냅니다.

사용 형식

c
u8 __stackcall Link4_TryReadByteFrom(u8 peer_slot, u8 *out);

매개변수

peer_slot

설정된 원격 슬롯입니다. 호스트에서는 1~slot_count−1, 상대에서는 0입니다.

out

쓰기 가능한 바이트 대상입니다. null이면 바이트를 버립니다.

반환값

꺼냈으면 1을 반환합니다. 비어 있거나 상대가 잘못되었으면 out을 유지하고 0을 반환합니다.

사용 조건과 제한

8개 항목의 수신 링 버퍼에는 7바이트를 담을 수 있습니다. 가득 차면 새 바이트를 버리고 오류 3을 저장합니다. 수신한 0바이트도 유효한 데이터입니다.

Link4는 수신 바이트를 일반 링과 상대별 링 양쪽에 복사합니다. 한쪽을 읽어도 다른 쪽의 데이터는 줄지 않습니다. 패킷 폴링은 일반 링을 소비하므로 오버플로를 막으려면 쓰지 않는 상대별 원시 바이트도 주기적으로 버리세요.

내부 임계 구역은 소프트웨어 중첩 깊이를 추적합니다. 가장 바깥 구역을 나올 때 CPU 인터럽트를 활성화하므로 이전에 비활성화되어 있던 IME 상태가 유지된다고 가정하지 마세요.

화면은 KOKURA에서 얻었습니다. 여러 끝점을 사용하는 예제는 연결된 에뮬레이터 인스턴스의 값을 확인하고 마지막으로 저장한 상태에서 화면을 캡처합니다. 이 검증은 실제 케이블이나 4인용 어댑터 동작을 입증하지 않습니다.

kitaqgb, kokura, kitaq-docs가 들어 있는 상위 폴더에서 이 PowerShell 명령을 실행하세요. 연결 세션을 시작하기 전에 참여하는 모든 ROM을 빌드하세요. Link4에서는 생성된 심벌 메타데이터를 ROM 옆에 유지하세요. DMG로 실행하려면 모든 명령의 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
if(slot==1)result[13]=Link4_TryReadByteFrom(slot,&value);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

ROM 4개를 모두 KOKURA의 link4 토폴로지로 연결하세요. 호스트는 상대 1/2/3에서 161/162/163을 받고 LAST PEER=3을 표시합니다. 이어서 명령 65/66/67과 페이로드 7/42/255를 보냅니다. 각 상대의 화면에서도 이 값을 확인하세요.

Link4_TryReadByteFrom: DMG
DMG
Link4_TryReadByteFrom: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_host.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_host.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer1.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer1.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer2.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\link_four_peer3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\link_four_peer3.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology link4 --run-frames 360 --link-session "name=four_host|slot=0|rom=.\out\link_four_host.gb|save_state=.\out\four_host.kqs" --link-session "name=four_peer1|slot=1|rom=.\out\link_four_peer1.gb|save_state=.\out\four_peer1.kqs" --link-session "name=four_peer2|slot=2|rom=.\out\link_four_peer2.gb|save_state=.\out\four_peer2.kqs" --link-session "name=four_peer3|slot=3|rom=.\out\link_four_peer3.gb|save_state=.\out\four_peer3.kqs"
.\kokura\kokura-cli.exe .\out\link_four_host.gb --hardware cgb --load-state .\out\four_host.kqs --run-frames 2 --png .\out\four_host.png
.\kokura\kokura-cli.exe .\out\link_four_peer1.gb --hardware cgb --load-state .\out\four_peer1.kqs --run-frames 2 --png .\out\four_peer1.png
.\kokura\kokura-cli.exe .\out\link_four_peer2.gb --hardware cgb --load-state .\out\four_peer2.kqs --run-frames 2 --png .\out\four_peer2.png
.\kokura\kokura-cli.exe .\out\link_four_peer3.gb --hardware cgb --load-state .\out\four_peer3.kqs --run-frames 2 --png .\out\four_peer3.png
구현과 소스

kitaqgb/lib/link.h:133

선언 주석 원문
Pop one byte from the selected peer ring; null output discards it.

kitaqgb/lib/link.c:598

c
u8 __stackcall Link4_TryReadByteFrom(u8 peer_slot, u8 *out) {
    return Link4_PopRxByte(peer_slot, out);
}

DMG-07은 각 콘솔이 제출한 한 바이트를 네 플레이어 모두에게 브로드캐스트합니다. 이 라이브러리는 발견, 플레이어 1의 시작, 지연된 패킷 브로드캐스트, 정렬된 재시작 제어를 처리합니다. EXCHANGE로 4대 교환, NO ADAPTER로 시간 초과, OVERFLOW로 읽지 않은 데이터, RESTART로 복구를 익히세요.

라이브러리 플레이어 번호는 1~4이며 0은 미발견입니다. 연결 마스크 비트 0~3은 플레이어 1~4에 대응합니다. KOKURA --link-session의 slot 값 0~3은 ROM API와 별개의 번호 체계입니다.

이 드라이버는 직렬 포트를 독점합니다. 일반 Link나 Link4를 동시에 실행하지 말고 link_hwregs_gb.c와 link_dmg07.c를 각각 한 번 포함하세요. 외부 클록은 어댑터가 제공하며, 드라이버는 CGB 고속 직렬 모드를 선택하지 않습니다.

프레임 전체에 걸쳐 Poll을 반복 호출하고 TickFrame은 프레임마다 정확히 한 번 호출하세요. VBlank마다 Poll 한 번으로는 어댑터 바이트 사이에 포트를 재준비할 수 없습니다. 공통 헤더의 d_poll은 LY >= 144 진입을 감지하여 TickFrame을 한 번 호출합니다. ISR과 메인 루프가 경쟁하지 않도록 두 작업을 순차 실행하세요.

SIZE=1이면 각 콘솔이 한 바이트를 제출하며 4바이트 브로드캐스트는 플레이어 1~4 순서입니다. 첫 브로드캐스트는 버립니다. 이후 브로드캐스트에는 이전 패킷에서 제출한 값이 들어갑니다. 네 바이트가 모두 0xFF인 브로드캐스트는 재시작 표식으로 예약되어 있습니다.

LinkDmg07_ClearError

마지막 오류 코드를 0으로 초기화합니다.

사용 형식

c
void LinkDmg07_ClearError();

반환값

반환값은 없습니다.

사용 조건과 제한

SilenceFrames와 진단 카운터는 255에서 포화됩니다. Init은 모두 초기화하고 일반 프로토콜 재시작은 진단 카운터를 유지합니다. ClearError는 오류 코드만 지웁니다.

수신 데이터, 단계, 연결 정보, 시간 초과 래치를 유지합니다. 이 호출만으로 다시 연결하거나 수신을 재개하지 않습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
LinkDmg07_ClearError();result[21]=LinkDmg07_LastError();result[22]=LinkDmg07_GetErrorCount();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

다음 패킷이 올 때까지 첫 유효 패킷을 읽지 않습니다. SENT SEQ=3, PACKET SEQ=2, ERROR=6을 기대하며 읽기는 최신 33/34/35/36을 반환합니다. ClearError는 CLEAR ERROR를 0으로 바꾸지만 ErrorCount는 1을 유지합니다.

LinkDmg07_ClearError: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_ClearError: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_overflow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_overflow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_overflow.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_overflow.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_overflow.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_overflow.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:125

선언 주석 원문
Clear only the latest error code, preserving counters and protocol state.

kitaqgb/lib/link_dmg07.c:541

c
void LinkDmg07_ClearError() {
    LinkDmg07_LastErrorCode = LINK_DMG07_ERR_NONE;
}
LinkDmg07_ConsumePingStatus

발견 완료 알림을 소비하고 지웁니다.

사용 형식

c
u8 LinkDmg07_ConsumePingStatus();

반환값

소비했으면 1, 아니면 0을 반환합니다.

사용 조건과 제한

알림만 지우고 슬롯, 마스크, LastStatus는 유지합니다. 새 알림이 올 때까지 이후 호출은 0을 반환합니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[3]=LinkDmg07_ConsumePingStatus();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_ConsumePingStatus: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_ConsumePingStatus: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:71

선언 주석 원문
Clear and report the completed-discovery flag; return zero if no new status exists.

kitaqgb/lib/link_dmg07.c:418

c
u8 LinkDmg07_ConsumePingStatus() {
    if (LinkDmg07_PingStatusReady == 0) return 0;
    LinkDmg07_PingStatusReady = 0;
    return 1;
}
LinkDmg07_GetConnectedMask

마지막으로 수락한 상태의 4비트 플레이어 집합을 읽습니다.

사용 형식

c
u8 LinkDmg07_GetConnectedMask();

반환값

비트 0~3이 연결된 플레이어를 나타냅니다. 미발견은 0, 네 명 연결은 15입니다.

사용 조건과 제한

라이브러리 플레이어 번호는 1~4이며 0은 미발견입니다. 연결 마스크 비트 0~3은 플레이어 1~4에 대응합니다. KOKURA --link-session의 slot 값 0~3은 ROM API와 별개의 번호 체계입니다.

물리 배선을 검사하는 것이 아니라 캐시된 발견 상태를 반환합니다. 전송 중에는 가장 최근에 수락한 알림을 반영합니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[1]=LinkDmg07_GetConnectedMask();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_GetConnectedMask: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetConnectedMask: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:65

선언 주석 원문
Normalized mask: bit 0 is player 1, ..., bit 3 is player 4.

kitaqgb/lib/link_dmg07.c:403

c
u8 LinkDmg07_GetConnectedMask() {
    return LinkDmg07_ConnectedMask;
}
LinkDmg07_GetDisconnectCount

어댑터 관측 후 무응답 또는 발견 상태에서 플레이어가 사라지는 연결 손실 기록을 읽습니다.

사용 형식

c
u8 LinkDmg07_GetDisconnectCount();

반환값

잃은 플레이어 수가 아닌 0~255의 이벤트 수를 반환합니다.

사용 조건과 제한

SilenceFrames와 진단 카운터는 255에서 포화됩니다. Init은 모두 초기화하고 일반 프로토콜 재시작은 진단 카운터를 유지합니다. ClearError는 오류 코드만 지웁니다.

어댑터를 한 번도 관측하지 못한 상태의 제한 만료는 횟수를 증가시키지 않습니다. 상태 변화 한 번으로 여러 플레이어가 사라져도 이벤트는 하나로 셉니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[8]=LinkDmg07_GetDisconnectCount();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

어댑터 없이 실행합니다. 기대값은 PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1, ERROR=4입니다. 어댑터를 한 번도 발견하지 않았으므로 DISCONNECTS는 0입니다. 빈 읽기는 EMPTY BUFFER=77을 유지하고 ClearError 후 CLEARED=0이 됩니다.

LinkDmg07_GetDisconnectCount: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetDisconnectCount: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png
구현과 소스

kitaqgb/lib/link_dmg07.h:118

선언 주석 원문
Return the saturating count of removed-player and previously-seen-adapter timeout events.

kitaqgb/lib/link_dmg07.c:525

c
u8 LinkDmg07_GetDisconnectCount() {
    return LinkDmg07_DisconnectCount;
}
LinkDmg07_GetErrorCount

수신 프로토콜 오류와 미읽음 패킷 덮어쓰기 횟수를 읽습니다.

사용 형식

c
u8 LinkDmg07_GetErrorCount();

반환값

0~255를 반환합니다. 요청 검증·상태 오류와 시간 초과는 포함하지 않습니다.

사용 조건과 제한

SilenceFrames와 진단 카운터는 255에서 포화됩니다. Init은 모두 초기화하고 일반 프로토콜 재시작은 진단 카운터를 유지합니다. ClearError는 오류 코드만 지웁니다.

수신 메일박스는 최신 패킷 하나만 보관합니다. 다음 패킷이 완료되면 읽지 않은 데이터를 덮어쓰고 오류 6을 기록하며 ErrorCount를 증가시킵니다. 어댑터는 애플리케이션이 메일박스를 읽을 때까지 기다리지 않습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[19]=LinkDmg07_GetErrorCount();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

다음 패킷이 올 때까지 첫 유효 패킷을 읽지 않습니다. SENT SEQ=3, PACKET SEQ=2, ERROR=6을 기대하며 읽기는 최신 33/34/35/36을 반환합니다. ClearError는 CLEAR ERROR를 0으로 바꾸지만 ErrorCount는 1을 유지합니다.

LinkDmg07_GetErrorCount: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetErrorCount: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_overflow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_overflow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_overflow.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_overflow.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_overflow.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_overflow.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_overflow.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:121

선언 주석 원문
Return the saturating protocol/overflow error count. Timeout and request
validation paths use separate counters or latches and do not increment this value.

kitaqgb/lib/link_dmg07.c:531

c
u8 LinkDmg07_GetErrorCount() {
    return LinkDmg07_ErrorCount;
}
LinkDmg07_GetLastStatus

마지막으로 검증한 원시 어댑터 상태 바이트를 읽습니다.

사용 형식

c
u8 LinkDmg07_GetLastStatus();

반환값

상위 니블은 연결 마스크, 하위 3비트는 로컬 플레이어 번호입니다. 초기값은 0입니다.

사용 조건과 제한

라이브러리 플레이어 번호는 1~4이며 0은 미발견입니다. 연결 마스크 비트 0~3은 플레이어 1~4에 대응합니다. KOKURA --link-session의 slot 값 0~3은 ROM API와 별개의 번호 체계입니다.

비트 3이 켜졌거나 플레이어 번호가 0 또는 4 초과이거나 발견 후 로컬 번호가 달라진 상태는 거부합니다. 거부하면 오류 5를 기록하며 그 값을 LastStatus에 저장하지 않습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[2]=LinkDmg07_GetLastStatus();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_GetLastStatus: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetLastStatus: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:67

선언 주석 원문
Return the last validated raw adapter status byte.

kitaqgb/lib/link_dmg07.c:408

c
u8 LinkDmg07_GetLastStatus() {
    return LinkDmg07_LastStatus;
}
LinkDmg07_GetLocalSlot

어댑터 상태에서 얻은 이 콘솔의 플레이어 번호를 읽습니다.

사용 형식

c
u8 LinkDmg07_GetLocalSlot();

반환값

발견되었으면 1~4, 발견 전이나 발견 초기화 직후에는 0을 반환합니다.

사용 조건과 제한

라이브러리 플레이어 번호는 1~4이며 0은 미발견입니다. 연결 마스크 비트 0~3은 플레이어 1~4에 대응합니다. KOKURA --link-session의 slot 값 0~3은 ROM API와 별개의 번호 체계입니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
slot=LinkDmg07_GetLocalSlot();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_GetLocalSlot: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetLocalSlot: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:62

선언 주석 원문
Return the one-based player slot, or LINK_DMG07_NO_SLOT before discovery.

kitaqgb/lib/link_dmg07.c:398

c
u8 LinkDmg07_GetLocalSlot() {
    return LinkDmg07_LocalSlot;
}
LinkDmg07_GetPacketSequence

가장 최근에 게시된 패킷에 부여한 시퀀스를 읽습니다.

사용 형식

c
u8 LinkDmg07_GetPacketSequence();

반환값

준비 상태를 바꾸지 않고 8비트 패킷 시퀀스를 반환합니다.

사용 조건과 제한

시퀀스 번호는 255 다음 0으로 돌아갑니다. 패킷을 게시하는 시점의 PacketSequence는 SentSequence−1입니다. 이후 송신 시작은 SentSequence를 증가시키므로 나중에 두 getter로 읽은 값은 차이가 1이 아닐 수 있습니다.

수신 메일박스는 최신 패킷 하나만 보관합니다. 다음 패킷이 완료되면 읽지 않은 데이터를 덮어쓰고 오류 6을 기록하며 ErrorCount를 증가시킵니다. 어댑터는 애플리케이션이 메일박스를 읽을 때까지 기다리지 않습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[7]=LinkDmg07_GetPacketSequence();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_GetPacketSequence: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetPacketSequence: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:109

선언 주석 원문
Return the modulo-256 sequence associated with the most recently published packet.

kitaqgb/lib/link_dmg07.c:510

c
u8 LinkDmg07_GetPacketSequence() {
    return LinkDmg07_PacketSequence;
}
LinkDmg07_GetPacketSlot

캐시된 패킷 저장 공간에서 플레이어 한 명의 바이트를 읽습니다.

사용 형식

c
u8 __stackcall LinkDmg07_GetPacketSlot(u8 player_slot);

매개변수

player_slot

물리 플레이어 번호 1~4입니다.

반환값

플레이어 1~4의 캐시 바이트를 반환하며 잘못된 번호는 0입니다.

사용 조건과 제한

라이브러리 플레이어 번호는 1~4이며 0은 미발견입니다. 연결 마스크 비트 0~3은 플레이어 1~4에 대응합니다. KOKURA --link-session의 slot 값 0~3은 ROM API와 별개의 번호 체계입니다.

준비 상태를 검사하거나 소비하지 않습니다. 초기화 직후에는 0을 반환하며, 소비 또는 발견 초기화 후에는 남은 바이트를 반환할 수 있습니다. 새 데이터 검사로 사용하지 마세요.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[16]=LinkDmg07_GetPacketSlot(4);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_GetPacketSlot: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetPacketSlot: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:102

선언 주석 원문
Read one cached player byte using a one-based slot. Invalid slots return
zero; the function neither requires readiness nor consumes the packet.

kitaqgb/lib/link_dmg07.c:499

c
u8 __stackcall LinkDmg07_GetPacketSlot(u8 player_slot) {
    if ((player_slot == 0) || (player_slot > LINK_DMG07_MAX_PLAYERS)) return 0;
    return LinkDmg07_RxPacket[(__safe_index u8)(player_slot - 1)];
}
LinkDmg07_GetPhase

현재 발견, 시작 요청, 확인 또는 전송 단계를 읽습니다.

사용 형식

c
u8 LinkDmg07_GetPhase();

반환값

0=PING, 1=REQUEST_AA, 2=WAIT_CC, 3=TRANSFER입니다.

사용 조건과 제한

폴링하거나 기다리지 않습니다. 시작 요청이 수락되어도 TRANSFER에는 아직 충분하지 않으며 연속된 0xCC 네 바이트가 필요합니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[8]=LinkDmg07_GetPhase();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_GetPhase: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetPhase: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:60

선언 주석 원문
Return the discovery, start-handshake or transfer phase without polling.

kitaqgb/lib/link_dmg07.c:393

c
u8 LinkDmg07_GetPhase() {
    return LinkDmg07_Phase;
}
LinkDmg07_GetRestartState

재시작 제어가 없음, 보류, 송신 중 중 어느 상태인지 읽습니다.

사용 형식

c
u8 LinkDmg07_GetRestartState();

반환값

0=없음, 1=경계 대기, 2=제어 통신 송신 중입니다.

사용 조건과 제한

통신 단계와 별개입니다. 0만으로 연결이 성립되었거나 사용 가능하다고 볼 수 없습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[4]=LinkDmg07_GetRestartState();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

플레이어 2가 재시작을 요청합니다. 해당 콘솔은 PENDING=1, SENT FF=1을 기록합니다. 네 콘솔 모두 DATA VALID=1, RESET PHASE=0, SLOT AFTER=0, RESET PRIME=0을 표시합니다. 드라이버는 어댑터 표식이 발견 단계로 되돌릴 때까지 진행 중인 교환을 유지합니다.

LinkDmg07_GetRestartState: DMG / 플레이어 2
DMG / 플레이어 2
LinkDmg07_GetRestartState: CGB / 플레이어 2
CGB / 플레이어 2

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_restart.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_restart.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_restart.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_restart.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_restart.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_restart.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:85

선언 주석 원문
Return whether aligned recovery is absent, pending or sending control traffic.

kitaqgb/lib/link_dmg07.c:457

c
u8 LinkDmg07_GetRestartState() {
    return LinkDmg07_RestartState;
}
LinkDmg07_GetSentSequence

실제로 클록에 맞춰 송신된 애플리케이션 제출 바이트 수를 읽습니다.

사용 형식

c
u8 LinkDmg07_GetSentSequence();

반환값

8비트 송신 시퀀스를 반환합니다. 첫 제출은 세지만 재시작 제어 통신은 제외합니다.

사용 조건과 제한

시퀀스 번호는 255 다음 0으로 돌아갑니다. 패킷을 게시하는 시점의 PacketSequence는 SentSequence−1입니다. 이후 송신 시작은 SentSequence를 증가시키므로 나중에 두 getter로 읽은 값은 차이가 1이 아닐 수 있습니다.

SIZE=1이면 각 콘솔이 한 바이트를 제출하며 4바이트 브로드캐스트는 플레이어 1~4 순서입니다. 첫 브로드캐스트는 버립니다. 이후 브로드캐스트에는 이전 패킷에서 제출한 값이 들어갑니다. 네 바이트가 모두 0xFF인 브로드캐스트는 재시작 표식으로 예약되어 있습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[6]=LinkDmg07_GetSentSequence();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_GetSentSequence: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetSentSequence: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:107

선언 주석 원문
SentSequence increments when this console's packet byte is clocked out.
PacketSequence labels the returned four-byte packet.  For a valid packet it
is one less than SentSequence, making the DMG-07 one-packet delay explicit.

kitaqgb/lib/link_dmg07.c:505

c
u8 LinkDmg07_GetSentSequence() {
    return LinkDmg07_SentSequence;
}
LinkDmg07_GetSilenceFrames

마지막 직렬 완료를 처리한 이후 센 프레임 수를 읽습니다.

사용 형식

c
u8 LinkDmg07_GetSilenceFrames();

반환값

0~255입니다. 완료 처리 시 초기화하며 TickFrame마다 증가합니다.

사용 조건과 제한

프레임 전체에 걸쳐 Poll을 반복 호출하고 TickFrame은 프레임마다 정확히 한 번 호출하세요. VBlank마다 Poll 한 번으로는 어댑터 바이트 사이에 포트를 재준비할 수 없습니다. 공통 헤더의 d_poll은 LY >= 144 진입을 감지하여 TickFrame을 한 번 호출합니다. ISR과 메인 루프가 경쟁하지 않도록 두 작업을 순차 실행하세요.

SilenceFrames와 진단 카운터는 255에서 포화됩니다. Init은 모두 초기화하고 일반 프로토콜 재시작은 진단 카운터를 유지합니다. ClearError는 오류 코드만 지웁니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[6]=LinkDmg07_GetSilenceFrames();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

어댑터 없이 실행합니다. 기대값은 PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1, ERROR=4입니다. 어댑터를 한 번도 발견하지 않았으므로 DISCONNECTS는 0입니다. 빈 읽기는 EMPTY BUFFER=77을 유지하고 ClearError 후 CLEARED=0이 됩니다.

LinkDmg07_GetSilenceFrames: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetSilenceFrames: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png
구현과 소스

kitaqgb/lib/link_dmg07.h:114

선언 주석 원문
SilenceFrames is reset by every completed serial byte.  TimeoutCount counts
distinct serial-silence or AA/CC/restart handshake timeouts. DisconnectCount counts
adapter-silence outages and ping-status membership drops.  All saturate.

kitaqgb/lib/link_dmg07.c:515

c
u8 LinkDmg07_GetSilenceFrames() {
    return LinkDmg07_SilenceFrames;
}
LinkDmg07_GetTimeoutCount

무응답 또는 핸드셰이크 제한 만료 횟수를 읽습니다.

사용 형식

c
u8 LinkDmg07_GetTimeoutCount();

반환값

0~255의 누적값을 반환합니다.

사용 조건과 제한

SilenceFrames와 진단 카운터는 255에서 포화됩니다. Init은 모두 초기화하고 일반 프로토콜 재시작은 진단 카운터를 유지합니다. ClearError는 오류 코드만 지웁니다.

수신이 재개될 때까지 같은 무응답 구간을 매 프레임 중복 계산하지 않습니다. ClearError는 이 억제 래치와 누적 횟수를 유지합니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[7]=LinkDmg07_GetTimeoutCount();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

어댑터 없이 실행합니다. 기대값은 PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1, ERROR=4입니다. 어댑터를 한 번도 발견하지 않았으므로 DISCONNECTS는 0입니다. 빈 읽기는 EMPTY BUFFER=77을 유지하고 ClearError 후 CLEARED=0이 됩니다.

LinkDmg07_GetTimeoutCount: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_GetTimeoutCount: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png
구현과 소스

kitaqgb/lib/link_dmg07.h:116

선언 주석 원문
Return the saturating lifetime timeout count, preserved across protocol restarts.

kitaqgb/lib/link_dmg07.c:520

c
u8 LinkDmg07_GetTimeoutCount() {
    return LinkDmg07_TimeoutCount;
}
LinkDmg07_HasPacket

완료된 4바이트 데이터 패킷이 아직 읽히지 않았는지 검사합니다.

사용 형식

c
u8 LinkDmg07_HasPacket();

반환값

읽지 않은 데이터가 있으면 1, 아니면 0을 반환합니다.

사용 조건과 제한

SIZE=1이면 각 콘솔이 한 바이트를 제출하며 4바이트 브로드캐스트는 플레이어 1~4 순서입니다. 첫 브로드캐스트는 버립니다. 이후 브로드캐스트에는 이전 패킷에서 제출한 값이 들어갑니다. 네 바이트가 모두 0xFF인 브로드캐스트는 재시작 표식으로 예약되어 있습니다.

수신 메일박스는 최신 패킷 하나만 보관합니다. 다음 패킷이 완료되면 읽지 않은 데이터를 덮어쓰고 오류 6을 기록하며 ErrorCount를 증가시킵니다. 어댑터는 애플리케이션이 메일박스를 읽을 때까지 기다리지 않습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[15]=LinkDmg07_HasPacket();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_HasPacket: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_HasPacket: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:96

선언 주석 원문
Inspect the one-packet receive mailbox without consuming it.

kitaqgb/lib/link_dmg07.c:473

c
u8 LinkDmg07_HasPacket() {
    return LinkDmg07_PacketReady;
}
LinkDmg07_HasPingStatus

완료된 4바이트 발견 교환이 확인 대기 중인지 검사합니다.

사용 형식

c
u8 LinkDmg07_HasPingStatus();

반환값

소비하지 않은 알림이 있으면 1, 아니면 0을 반환합니다.

사용 조건과 제한

플래그만 읽습니다. 상태 바이트가 거부되어도 발견 교환이 진행될 수 있으므로 이 플래그만으로 데이터가 모두 유효하거나 시작이 끝났다고 판단하지 마세요. 슬롯, 마스크, LastError도 확인하세요.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[4]=LinkDmg07_HasPingStatus();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_HasPingStatus: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_HasPingStatus: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:69

선언 주석 원문
Read the completed-discovery status flag without clearing it.

kitaqgb/lib/link_dmg07.c:413

c
u8 LinkDmg07_HasPingStatus() {
    return LinkDmg07_PingStatusReady;
}
LinkDmg07_Init

발견 상태, 수신 저장 공간, 진단을 초기화하고 어댑터 클록을 받을 준비를 합니다.

사용 형식

c
void __stackcall LinkDmg07_Init(u8 rate);

매개변수

rate

어댑터에 보낼 8비트 RATE 응답입니다. 0은 기본값 0x10을 선택합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

이 드라이버는 직렬 포트를 독점합니다. 일반 Link나 Link4를 동시에 실행하지 말고 link_hwregs_gb.c와 link_dmg07.c를 각각 한 번 포함하세요. 외부 클록은 어댑터가 제공하며, 드라이버는 CGB 고속 직렬 모드를 선택하지 않습니다.

라이브러리 플레이어 번호는 1~4이며 0은 미발견입니다. 연결 마스크 비트 0~3은 플레이어 1~4에 대응합니다. KOKURA --link-session의 slot 값 0~3은 ROM API와 별개의 번호 체계입니다.

SC를 0x80, SB를 0x88로 설정하고 IE와 IF의 직렬 비트만 지웁니다. 다른 인터럽트 활성 비트나 CPU IME 상태는 바꾸지 않습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
LinkDmg07_Init(0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_Init: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_Init: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:50

선언 주석 원문
Initializes polling-only external-clock operation.  A zero RATE is replaced
with LINK_DMG07_DEFAULT_RATE.  This driver disables only the serial IRQ bit.

kitaqgb/lib/link_dmg07.c:282

c
void __stackcall LinkDmg07_Init(u8 rate) {
    u8 i;

    LinkDmg07_Rate = rate;
    if (LinkDmg07_Rate == 0) LinkDmg07_Rate = LINK_DMG07_DEFAULT_RATE;
    LinkDmg07_LocalByte = 0;
    LinkDmg07_SentSequence = 0;
    LinkDmg07_PacketSequence = 0;
    LinkDmg07_RestartState = LINK_DMG07_RESTART_NONE;
    LinkDmg07_SilenceFrames = 0;
    LinkDmg07_TimeoutCount = 0;
    LinkDmg07_DisconnectCount = 0;
    LinkDmg07_ErrorCount = 0;
    LinkDmg07_LastErrorCode = LINK_DMG07_ERR_NONE;
    LinkDmg07_SeenAdapter = 0;
    LinkDmg07_TimeoutLatched = 0;
    for (i = 0; i < LINK_DMG07_PACKET_BYTES; ++i) {
        LinkDmg07_RxBuild[(__safe_index u8)i] = 0;
        LinkDmg07_RxPacket[(__safe_index u8)i] = 0;
    }
    LinkDmg07_ResetToPingInternal();

    LinkHw_WriteIE((u8)(LinkHw_ReadIE() & LINK_DMG07_IRQ_SERIAL_CLEAR));
    LinkHw_WriteIF((u8)(LinkHw_ReadIF() & LINK_DMG07_IRQ_SERIAL_CLEAR));
    LinkDmg07_ArmInternal(LINK_DMG07_ACK);
}
LinkDmg07_IsPipelinePrimed

초기의 정의되지 않은 브로드캐스트를 버렸는지 검사합니다.

사용 형식

c
u8 LinkDmg07_IsPipelinePrimed();

반환값

첫 브로드캐스트 후 1을 반환합니다. 초기화, 발견 초기화, 시작 확인 시 지웁니다.

사용 조건과 제한

SIZE=1이면 각 콘솔이 한 바이트를 제출하며 4바이트 브로드캐스트는 플레이어 1~4 순서입니다. 첫 브로드캐스트는 버립니다. 이후 브로드캐스트에는 이전 패킷에서 제출한 값이 들어갑니다. 네 바이트가 모두 0xFF인 브로드캐스트는 재시작 표식으로 예약되어 있습니다.

파이프라인이 준비되었어도 완료된 패킷이 없을 수 있습니다. 읽기 가능 여부는 HasPacket으로 확인하세요.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[9]=LinkDmg07_IsPipelinePrimed();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_IsPipelinePrimed: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_IsPipelinePrimed: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:94

선언 주석 원문
The first incoming adapter data packet is discarded.  Thereafter ReadPacket
copies four bytes in physical slot order (players 1..4).

kitaqgb/lib/link_dmg07.c:468

c
u8 LinkDmg07_IsPipelinePrimed() {
    return LinkDmg07_PipelinePrimed;
}
LinkDmg07_LastError

가장 최근에 기록된 오류 코드를 읽습니다.

사용 형식

c
u8 LinkDmg07_LastError();

반환값

오류 코드 0~6을 반환합니다.

사용 조건과 제한

오류 코드는 0=없음, 1=잘못된 단계, 2=플레이어 1이 아님, 3=준비 안 됨, 4=시간 초과, 5=프로토콜 오류, 6=읽지 않은 패킷 덮어쓰기입니다. 요청은 0으로 성공하고 수신·pop 작업은 1로 성공합니다. 요청 성공은 이전 오류를 지우지 않습니다.

읽어도 지워지지 않습니다. 모든 오류 이력 대신 가장 최근 코드만 저장합니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[9]=LinkDmg07_LastError();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

어댑터 없이 실행합니다. 기대값은 PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1, ERROR=4입니다. 어댑터를 한 번도 발견하지 않았으므로 DISCONNECTS는 0입니다. 빈 읽기는 EMPTY BUFFER=77을 유지하고 ClearError 후 CLEARED=0이 됩니다.

LinkDmg07_LastError: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_LastError: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png
구현과 소스

kitaqgb/lib/link_dmg07.h:123

선언 주석 원문
Return the latest error latch without clearing counters or restarting the protocol.

kitaqgb/lib/link_dmg07.c:536

c
u8 LinkDmg07_LastError() {
    return LinkDmg07_LastErrorCode;
}
LinkDmg07_Poll

현재 단계에서 완료된 직렬 바이트 하나를 처리하고 즉시 다음 응답을 준비합니다.

사용 형식

c
void LinkDmg07_Poll();

반환값

반환값은 없습니다.

사용 조건과 제한

이 드라이버는 직렬 포트를 독점합니다. 일반 Link나 Link4를 동시에 실행하지 말고 link_hwregs_gb.c와 link_dmg07.c를 각각 한 번 포함하세요. 외부 클록은 어댑터가 제공하며, 드라이버는 CGB 고속 직렬 모드를 선택하지 않습니다.

프레임 전체에 걸쳐 Poll을 반복 호출하고 TickFrame은 프레임마다 정확히 한 번 호출하세요. VBlank마다 Poll 한 번으로는 어댑터 바이트 사이에 포트를 재준비할 수 없습니다. 공통 헤더의 d_poll은 LY >= 144 진입을 감지하여 TickFrame을 한 번 호출합니다. ISR과 메인 루프가 경쟁하지 않도록 두 작업을 순차 실행하세요.

SC의 시작 비트가 켜져 있으면 아무 동작도 하지 않습니다. 완료 처리 시 SilenceFrames와 시간 초과 래치를 초기화합니다. 폴링 전에 초기화하세요.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
void d_poll(){LinkDmg07_Poll();if(D_LY>=144){if(d_vblank==0){d_vblank=1;LinkDmg07_TickFrame();}}else d_vblank=0;}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_Poll: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_Poll: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:54

선언 주석 원문
Services at most one completed serial byte and immediately re-arms SC=$80.
Call continuously from the main loop, including between VBlanks.

kitaqgb/lib/link_dmg07.c:311

c
void LinkDmg07_Poll() {
    u8 value;
    u8 next;

    if ((LinkHw_ReadSC() & LINK_DMG07_SC_EXTERNAL_START) != 0) return;

    value = LinkHw_ReadSB();
    LinkDmg07_SilenceFrames = 0;
    LinkDmg07_TimeoutLatched = 0;
    LinkDmg07_SeenAdapter = 1;

    next = 0;
    if (LinkDmg07_Phase == LINK_DMG07_PHASE_PING) {
        next = LinkDmg07_ProcessPingInternal(value);
    } else if (LinkDmg07_Phase == LINK_DMG07_PHASE_REQUEST_AA) {
        next = LinkDmg07_ProcessRequestInternal(value);
    } else if (LinkDmg07_Phase == LINK_DMG07_PHASE_WAIT_CC) {
        next = LinkDmg07_ProcessWaitCcInternal(value);
    } else if (LinkDmg07_Phase == LINK_DMG07_PHASE_TRANSFER) {
        next = LinkDmg07_ProcessTransferInternal(value);
    } else {
        LinkDmg07_SetRuntimeErrorInternal(LINK_DMG07_ERR_PROTOCOL);
        LinkDmg07_ResetToPingInternal();
        next = LINK_DMG07_ACK;
    }

    LinkDmg07_ArmInternal(next);
}
LinkDmg07_ReadPacket

가장 최근에 완료된 패킷을 복사하고 미읽음 플래그를 지웁니다.

사용 형식

c
u8 __stackcall LinkDmg07_ReadPacket(u8 *dst);

매개변수

dst

쓰기 가능한 4바이트입니다. null이면 패킷을 버립니다.

반환값

소비하면 1, 비어 있으면 0을 반환합니다. 빈 읽기는 dst를 바꾸지 않습니다.

사용 조건과 제한

SIZE=1이면 각 콘솔이 한 바이트를 제출하며 4바이트 브로드캐스트는 플레이어 1~4 순서입니다. 첫 브로드캐스트는 버립니다. 이후 브로드캐스트에는 이전 패킷에서 제출한 값이 들어갑니다. 네 바이트가 모두 0xFF인 브로드캐스트는 재시작 표식으로 예약되어 있습니다.

수신 메일박스는 최신 패킷 하나만 보관합니다. 다음 패킷이 완료되면 읽지 않은 데이터를 덮어쓰고 오류 6을 기록하며 ErrorCount를 증가시킵니다. 어댑터는 애플리케이션이 메일박스를 읽을 때까지 기다리지 않습니다.

소비 후에도 GetPacketSlot으로 캐시 바이트를 읽을 수 있습니다. 비어 있는 ReadPacket은 그 바이트를 다시 복사하지 않습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[10]=LinkDmg07_ReadPacket(packet);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_ReadPacket: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_ReadPacket: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:99

선언 주석 원문
Consume the latest four-byte packet. A nonnull destination must hold four
bytes; null discards the packet. Packet storage remains after the flag clears.

kitaqgb/lib/link_dmg07.c:479

c
u8 __stackcall LinkDmg07_ReadPacket(u8 *dst) {
    if (LinkDmg07_PacketReady == 0) return 0;
    if (dst != 0) {
        // Keep this as a sequential pointer copy.  Besides being smaller for a
        // fixed four-byte packet, it avoids making a serial hot-path copy
        // depend on general variable-index pointer lowering.
        *dst = LinkDmg07_RxPacket[0];
        dst++;
        *dst = LinkDmg07_RxPacket[1];
        dst++;
        *dst = LinkDmg07_RxPacket[2];
        dst++;
        *dst = LinkDmg07_RxPacket[3];
    }
    LinkDmg07_PacketReady = 0;
    return 1;
}
LinkDmg07_RequestRestart

전송 패킷 경계에서 시작하는 재시작 제어 통신을 예약합니다.

사용 형식

c
u8 LinkDmg07_RequestRestart();

반환값

TRANSFER에서는 0, 아니면 1을 반환합니다. 보류·송신 중 반복 요청도 0을 반환합니다.

사용 조건과 제한

SIZE=1이면 각 콘솔이 한 바이트를 제출하며 4바이트 브로드캐스트는 플레이어 1~4 순서입니다. 첫 브로드캐스트는 버립니다. 이후 브로드캐스트에는 이전 패킷에서 제출한 값이 들어갑니다. 네 바이트가 모두 0xFF인 브로드캐스트는 재시작 표식으로 예약되어 있습니다.

오류 코드는 0=없음, 1=잘못된 단계, 2=플레이어 1이 아님, 3=준비 안 됨, 4=시간 초과, 5=프로토콜 오류, 6=읽지 않은 패킷 덮어쓰기입니다. 요청은 0으로 성공하고 수신·pop 작업은 1로 성공합니다. 요청 성공은 이전 오류를 지우지 않습니다.

어느 플레이어든 요청할 수 있습니다. 현재 바이트 위치를 유지하며 정렬된 0xFF 통신을 보내고, 어댑터의 전체 0xFF 표식 후 발견 단계로 돌아갑니다. 요청만으로 로컬 슬롯이나 수신 파이프라인을 지우지는 않습니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[3]=LinkDmg07_RequestRestart();result[4]=LinkDmg07_GetRestartState();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

플레이어 2가 재시작을 요청합니다. 해당 콘솔은 PENDING=1, SENT FF=1을 기록합니다. 네 콘솔 모두 DATA VALID=1, RESET PHASE=0, SLOT AFTER=0, RESET PRIME=0을 표시합니다. 드라이버는 어댑터 표식이 발견 단계로 되돌릴 때까지 진행 중인 교환을 유지합니다.

LinkDmg07_RequestRestart: DMG / 플레이어 2
DMG / 플레이어 2
LinkDmg07_RequestRestart: CGB / 플레이어 2
CGB / 플레이어 2

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_restart.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_restart.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_restart.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_restart.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_restart.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_restart.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_restart.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:83

선언 주석 원문
Any physical slot may schedule FF FF FF FF at the next four-byte packet
boundary while remaining in TRANSFER phase.  The driver keeps sending aligned
FF bytes until it sees the adapter's complete all-FF indicator packet, then
returns to PING.  A transfer-phase silence timeout schedules the same recovery
automatically and preserves the current byte position for clocks that resume.

kitaqgb/lib/link_dmg07.c:445

c
u8 LinkDmg07_RequestRestart() {
    if (LinkDmg07_Phase != LINK_DMG07_PHASE_TRANSFER) {
        LinkDmg07_LastErrorCode = LINK_DMG07_ERR_STATE;
        return LINK_DMG07_ERR_STATE;
    }
    if (LinkDmg07_RestartState == LINK_DMG07_RESTART_NONE) {
        LinkDmg07_RestartState = LINK_DMG07_RESTART_PENDING;
    }
    return LINK_DMG07_ERR_NONE;
}
LinkDmg07_RequestTransmission

물리 플레이어 1의 시작 요청을 다음 발견 패킷 경계에 예약합니다.

사용 형식

c
u8 LinkDmg07_RequestTransmission();

반환값

예약하면 0, 잘못된 단계는 1, 플레이어 1이 아니면 2, 로컬 연결 비트가 없으면 3을 반환합니다.

사용 조건과 제한

라이브러리 플레이어 번호는 1~4이며 0은 미발견입니다. 연결 마스크 비트 0~3은 플레이어 1~4에 대응합니다. KOKURA --link-session의 slot 값 0~3은 ROM API와 별개의 번호 체계입니다.

오류 코드는 0=없음, 1=잘못된 단계, 2=플레이어 1이 아님, 3=준비 안 됨, 4=시간 초과, 5=프로토콜 오류, 6=읽지 않은 패킷 덮어쓰기입니다. 요청은 0으로 성공하고 수신·pop 작업은 1로 성공합니다. 요청 성공은 이전 오류를 지우지 않습니다.

PING에서만 예약할 수 있습니다. 자체적으로 네 명을 기다리지 않으며 예제는 애플리케이션 코드에서 마스크 15를 확인합니다. 예약은 비동기식으로, 정렬된 0xAA 통신 뒤에 0xCC 확인이 옵니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
result[5]=LinkDmg07_RequestTransmission();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_RequestTransmission: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_RequestTransmission: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:76

선언 주석 원문
Only physical player 1 may request AA AA AA AA.  The bytes are aligned to
the next FE/status/status/status ping packet.  All consoles enter transfer
mode only after receiving four consecutive CC bytes.

kitaqgb/lib/link_dmg07.c:426

c
u8 LinkDmg07_RequestTransmission() {
    if (LinkDmg07_Phase != LINK_DMG07_PHASE_PING) {
        LinkDmg07_LastErrorCode = LINK_DMG07_ERR_STATE;
        return LINK_DMG07_ERR_STATE;
    }
    if (LinkDmg07_LocalSlot != 1) {
        LinkDmg07_LastErrorCode = LINK_DMG07_ERR_NOT_PLAYER1;
        return LINK_DMG07_ERR_NOT_PLAYER1;
    }
    if ((LinkDmg07_ConnectedMask & (u8)0x01) == 0) {
        LinkDmg07_LastErrorCode = LINK_DMG07_ERR_NOT_READY;
        return LINK_DMG07_ERR_NOT_READY;
    }
    LinkDmg07_StartRequested = 1;
    return LINK_DMG07_ERR_NONE;
}
LinkDmg07_SetLocalByte

이후 송신 패킷에 넣을 애플리케이션 값 한 바이트를 설정합니다.

사용 형식

c
void __stackcall LinkDmg07_SetLocalByte(u8 value);

매개변수

value

제출할 8비트 애플리케이션 값입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

SIZE=1이면 각 콘솔이 한 바이트를 제출하며 4바이트 브로드캐스트는 플레이어 1~4 순서입니다. 첫 브로드캐스트는 버립니다. 이후 브로드캐스트에는 이전 패킷에서 제출한 값이 들어갑니다. 네 바이트가 모두 0xFF인 브로드캐스트는 재시작 표식으로 예약되어 있습니다.

패킷의 바이트 0을 준비할 때 읽습니다. 이미 준비된 SB 바이트는 바꾸지 않습니다. 시작을 요청하기 전에 첫 제출값을 설정하세요.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
LinkDmg07_SetLocalByte(32+slot);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 ROM을 네 콘솔에서 실행하고 각 콘솔은 32+자기 플레이어 번호를 보냅니다. 모든 콘솔이 PLAYER 1..4 = 33/34/35/36을 받습니다. 첫 유효 브로드캐스트는 SENT SEQ=2, PACKET SEQ=1을 기록하여 한 패킷 지연을 보여 줍니다. 화면은 그 시점에서 멈추지만 게임에서는 이후에도 폴링을 계속합니다.

LinkDmg07_SetLocalByte: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_SetLocalByte: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_exchange.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_exchange.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe --link-topology dmg07 --run-frames 90 --link-session "name=player1|slot=0|rom=.\out\dmg07_exchange.gb|save_state=.\out\player1.kqs" --link-session "name=player2|slot=1|rom=.\out\dmg07_exchange.gb|save_state=.\out\player2.kqs" --link-session "name=player3|slot=2|rom=.\out\dmg07_exchange.gb|save_state=.\out\player3.kqs" --link-session "name=player4|slot=3|rom=.\out\dmg07_exchange.gb|save_state=.\out\player4.kqs"
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player1.kqs --run-frames 2 --png .\out\player1.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player2.kqs --run-frames 2 --png .\out\player2.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player3.kqs --run-frames 2 --png .\out\player3.png
.\kokura\kokura-cli.exe .\out\dmg07_exchange.gb --hardware cgb --load-state .\out\player4.kqs --run-frames 2 --png .\out\player4.png
구현과 소스

kitaqgb/lib/link_dmg07.h:90

선언 주석 원문
Sets the byte sampled when byte 0 of the next adapter packet is armed.
Set it before the current packet completes (and before requesting start for
the first submission).  During normal transfer, bytes 1..3 are sent as zero.

kitaqgb/lib/link_dmg07.c:463

c
void __stackcall LinkDmg07_SetLocalByte(u8 value) {
    LinkDmg07_LocalByte = value;
}
LinkDmg07_TickFrame

무응답 및 시작·재시작 감시를 한 프레임 진행하고 제한에 도달하면 복구를 요청합니다.

사용 형식

c
void LinkDmg07_TickFrame();

반환값

반환값은 없습니다.

사용 조건과 제한

프레임 전체에 걸쳐 Poll을 반복 호출하고 TickFrame은 프레임마다 정확히 한 번 호출하세요. VBlank마다 Poll 한 번으로는 어댑터 바이트 사이에 포트를 재준비할 수 없습니다. 공통 헤더의 d_poll은 LY >= 144 진입을 감지하여 TickFrame을 한 번 호출합니다. ISR과 메인 루프가 경쟁하지 않도록 두 작업을 순차 실행하세요.

SilenceFrames와 진단 카운터는 255에서 포화됩니다. Init은 모두 초기화하고 일반 프로토콜 재시작은 진단 카운터를 유지합니다. ClearError는 오류 코드만 지웁니다.

기본 제한은 12회 호출입니다. 다른 값을 쓰려면 포함 전에 LINK_DMG07_TIMEOUT_FRAMES를 1~255로 정의하세요. 무응답 구간은 다른 바이트가 래치를 지울 때까지 한 번만 셉니다. 전송 복구는 바이트 정렬을 유지하며 발견·시작 복구는 발견 단계로 돌아갑니다.

화면은 KOKURA의 DMG-07 모델에서 캡처합니다. 각 콘솔은 독립적으로 실행하고 송수신 값을 비교합니다. 실제 어댑터·케이블의 전기적 동작과 타이밍은 검증하지 않았습니다. CGB 화면은 숫자를 파란색으로 표시합니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 디렉터리 아래에 놓고 그 상위 디렉터리에서 PowerShell을 여세요. 4대 콘솔 예제는 같은 ROM을 네 세션에서 실행합니다. DMG 검사에서는 모든 --cgb=cgb를 --cgb=dmg로, --hardware cgb를 --hardware dmg로 바꾸세요.

사용 예

c
void d_poll(){LinkDmg07_Poll();if(D_LY>=144){if(d_vblank==0){d_vblank=1;LinkDmg07_TickFrame();}}else d_vblank=0;}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

어댑터 없이 실행합니다. 기대값은 PLAYER=0, START ERROR=2, SILENT FRAME=12, TIMEOUTS=1, ERROR=4입니다. 어댑터를 한 번도 발견하지 않았으므로 DISCONNECTS는 0입니다. 빈 읽기는 EMPTY BUFFER=77을 유지하고 ClearError 후 CLEARED=0이 됩니다.

LinkDmg07_TickFrame: DMG / 플레이어 1
DMG / 플레이어 1
LinkDmg07_TickFrame: CGB / 플레이어 1
CGB / 플레이어 1

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dmg07_absent.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dmg07_absent.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\dmg07_absent.gb --hardware cgb --run-frames 90 --png .\out\absent.png
구현과 소스

kitaqgb/lib/link_dmg07.h:57

선언 주석 원문
Advances saturating frame-based silence and handshake timeout counters.

kitaqgb/lib/link_dmg07.c:369

c
void LinkDmg07_TickFrame() {
    LinkDmg07_SilenceFrames = LinkDmg07_IncrementSaturatingInternal(LinkDmg07_SilenceFrames);

    if ((LinkDmg07_Phase == LINK_DMG07_PHASE_REQUEST_AA) ||
        (LinkDmg07_Phase == LINK_DMG07_PHASE_WAIT_CC) ||
        (LinkDmg07_RestartState == LINK_DMG07_RESTART_SENDING)) {
        LinkDmg07_HandshakeFrames = LinkDmg07_IncrementSaturatingInternal(LinkDmg07_HandshakeFrames);
    } else {
        LinkDmg07_HandshakeFrames = 0;
    }

    if ((LinkDmg07_SilenceFrames >= LINK_DMG07_TIMEOUT_FRAMES) &&
        (LinkDmg07_TimeoutLatched == 0)) {
        LinkDmg07_TimeoutInternal(1);
        return;
    }

    if ((LinkDmg07_HandshakeFrames >= LINK_DMG07_TIMEOUT_FRAMES) &&
        (LinkDmg07_TimeoutLatched == 0)) {
        LinkDmg07_TimeoutInternal(0);
    }
}

physics2d.h — 2D 이동과 충돌

박스 적분과 AABB 접촉 처리, 선택적으로 사용할 수 있는 표면 반응 솔버를 제공합니다. 물체는 중심과 반크기로 표현합니다. active=0이면 해당 슬롯을 제외하고 inv_mass_q8<=0이면 정적 물체로 취급합니다. KQRect는 왼쪽 위 좌표와 너비·높이를 사용합니다. 박스 쌍의 접촉에는 물체의 restitution 필드를 사용하지 않으며, 표면 반응은 KQSurface2D의 계수를 사용합니다.

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

월드는 호출자가 소유한 배열을 빌려 사용합니다. 호출자가 물체 저장 공간을 할당하고 소유하며, 사용하는 동안 유효하게 유지해야 합니다. 월드를 초기화해도 배열 원소는 초기화되지 않습니다.

kq2d_body_apply_friction

위치나 활성 상태를 확인하지 않고 두 속도 성분에 부호 있는 바이트 계수를 256으로 나눈 배율을 적용합니다.

사용 형식

c
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

friction_q8

이 함수가 사용하는 속도 배율입니다. s8로 변환하므로 128..255는 음수 계수가 됩니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

0..127은 0..127/256의 배율입니다. 128..255는 s8 변환 후 음수가 되어 속도 방향을 뒤집습니다. 0..255 전체 범위에서 양의 감쇠를 적용하려면 각 속도에 kq2d_scale_q8을 사용하세요. 곱셈 결과는 0 방향으로 버림합니다. NULL은 무시합니다.

사용 예

c
kq2d_body_apply_friction(&temp,64);
    result[11]=temp.vx; result[12]=temp.vy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_body_apply_friction: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_body_apply_friction: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:66

선언 주석 원문
Scale both velocities through the signed 8-bit coefficient intrinsic.
Despite the unsigned parameter, values 128..255 become negative coefficients;
this is not a full-range unsigned Q8 damping helper. Null is ignored.

kitaqgb/lib/physics2d.c:654

c
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8)
{
    if (body == 0) return;
    body->vx = (s16)__smul16x8(body->vx, (s8)friction_q8);
    body->vy = (s16)__smul16x8(body->vy, (s8)friction_q8);
}
kq2d_body_apply_gravity

활성 동적 물체에 중력을 더하고 각 축 속도를 +/-max_speed로 제한합니다. 위치는 갱신하지 않습니다.

사용 형식

c
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

gravity_x

이번 호출에서 X 속도에 더하는 가속도입니다.

gravity_y

이번 호출에서 Y 속도에 더하는 가속도입니다.

max_speed

속도 제한값입니다. 각 축을 제한하는지 전체 벡터를 제한하는지는 해당 항목의 설명을 참조하세요.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

박스 적분 및 충돌 함수는 임시 저장 공간을 공유합니다. 인터럽트에서 이 물리 함수들을 재진입 호출하지 마세요.

NULL, 비활성 물체, 역질량이 0 이하인 물체는 무시합니다. 속도 제한에는 0 이상의 값을 지정하세요.

사용 예

c
kq2d_body_apply_gravity(&temp,5,-10,32);
    result[9]=temp.vx; result[10]=temp.vy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_body_apply_gravity: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_body_apply_gravity: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:62

선언 주석 원문
Add gravity and clamp each velocity axis separately for an active dynamic
body. Null, inactive and static bodies are ignored. Supply a nonnegative limit
and avoid overflow in the additions before clamping; position is unchanged.

kitaqgb/lib/physics2d.c:630

c
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed)
{
    if (body == 0) return;
    if (body->active == 0) return;
    if (body->inv_mass_q8 <= 0) return;

    kq2d_asm_value = body->vx;
    kq2d_asm_operand = gravity_x;
    kq2d_add_s16_asm();
    kq2d_asm_limit = max_speed;
    kq2d_clamp_abs_s16_asm();
    body->vx = kq2d_asm_value;

    kq2d_asm_value = body->vy;
    kq2d_asm_operand = gravity_y;
    kq2d_add_s16_asm();
    kq2d_asm_limit = max_speed;
    kq2d_clamp_abs_s16_asm();
    body->vy = kq2d_asm_value;
}
kq2d_body_init

주어진 반크기로 중심 기준 박스를 초기화하고 속도 0, 역질량 256, 활성 상태로 설정합니다.

사용 형식

c
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

x

중심 또는 점의 X 좌표입니다. 샘플에서는 픽셀 단위입니다.

y

중심 또는 점의 Y 좌표입니다. 샘플에서는 아래쪽이 양의 방향입니다.

half_x

X축 반크기입니다. 박스의 전체 너비는 이 값의 두 배입니다.

half_y

Y축 반크기입니다. 박스의 전체 높이는 이 값의 두 배입니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

restitution_q8을 0으로 설정합니다. body가 NULL이면 무시합니다. 양의 반크기를 지정하세요.

사용 예

c
kq2d_body_init(&temp,10,20,8,8);
    result[3]=temp.inv_mass_q8; result[4]=temp.active;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_body_init: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_body_init: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:54

선언 주석 원문
Initialize an active unit-inverse-mass body at the supplied center and half
extents, with zero velocity and reserved restitution set to zero. Null is ignored.

kitaqgb/lib/physics2d.c:597

c
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y)
{
    if (body == 0) return;
    body->x = x;
    body->y = y;
    body->vx = 0;
    body->vy = 0;
    body->half_x = half_x;
    body->half_y = half_y;
    body->inv_mass_q8 = 256;
    body->restitution_q8 = 0;
    body->active = 1;
}
kq2d_body_limit_speed

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

벡터 길이를 보수적으로 추정하고 두 축에 같은 배율을 적용해 전체 속력을 제한합니다.

사용 형식

c
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

max_speed

속도 제한값입니다. 각 축을 제한하는지 전체 벡터를 제한하는지는 해당 항목의 설명을 참조하세요.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

속도 성분의 절댓값과 양의 max_speed를 16383 이하로 유지하세요. 제한값이 0 이하이면 속도를 0으로 만듭니다. NULL은 무시하지만 활성 상태나 질량은 변경 여부에 영향을 주지 않습니다. 정수 양자화로 결과가 제한값보다 작아질 수 있으며, 배율이 매우 작으면 0이 될 수 있습니다.

사용 예

c
kq2d_body_limit_speed(&body,250);
    result[2]=body.vx; result[3]=body.vy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.

kq2d_body_limit_speed: DMG — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
kq2d_body_limit_speed: CGB — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_surface.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_surface.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:92

선언 주석 원문
Conservative circular bound, with a shared Q8 scale for both components.
Quantizes toward zero; very small limits relative to input may yield zero.
Components and positive max_speed must be <= 16383 in magnitude.

kitaqgb/lib/physics2d.c:260

c
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed)
{
    u16 x;
    u16 y;
    u16 swap;
    u16 ratio;
    u16 length;
    if (body == 0) return;
    if (max_speed <= 0) { body->vx = 0; body->vy = 0; return; }
    x = (u16)body->vx;
    y = (u16)body->vy;
    if (body->vx < 0) x = (u16)(0 - body->vx);
    if (body->vy < 0) y = (u16)(0 - body->vy);
    if (x + y <= (u16)max_speed) return;
    if (x < y) { swap = x; x = y; y = swap; }
    // major + minor/2 bounds hypot from above for 0 <= minor <= major.
    if (x + (y >> 1) + 1 <= (u16)max_speed) return;
    // Round the minor/major ratio upward for the 65-entry upper-bound table.
    // The extra unit covers truncation when converting the estimate back to speed.
    ratio = (kq2d__fraction_q8(y, x) + 4) >> 2;
    if (ratio > 64) ratio = 64;
    length = x + (u16)kq2d_scale_q8((s16)x, (s16)kq2d_hypot_extra[(__safe_index u8)ratio]) + 1;
    if (length <= (u16)max_speed) return;
    ratio = kq2d__fraction_q8((u16)max_speed, length);
    body->vx = kq2d_scale_q8(body->vx, (s16)ratio);
    body->vy = kq2d_scale_q8(body->vy, (s16)ratio);
}
kq2d_body_resolve_surface

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

움직이는 표면에 대한 상대 속도로 법선 방향 반발, 최소 반발 속력, 접선 방향 마찰을 적용합니다.

사용 형식

c
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

surface

법선, 속도, 반발, 마찰 설정을 담은 KQSurface2D의 포인터입니다.

반환값

법선 방향 입사 속력을 양수로 반환합니다. 입력이 NULL이거나 서로 멀어지는 운동이면 0을 반환합니다.

사용 조건과 제한

길이가 256인 Q8 단위 법선을 사용하세요. 상대 속도 성분은 +/-8191 이내, threshold/kick은 0 이상, 계수는 0..255로 유지하세요. 입사 속력이 임계값을 엄격히 초과할 때만 반발을 적용하며 kick은 최소 반발 속력입니다. 입력이 NULL이거나 서로 멀어지는 운동이면 속도를 바꾸지 않습니다. 접촉 감지와 침투 보정은 별도이며, 활성 상태와 질량은 검사하지 않습니다.

사용 예

c
result[6]=kq2d_body_resolve_surface(&body,&surface);
    result[7]=body.vx; result[8]=body.vy; result[9]=body.y;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.

kq2d_body_resolve_surface: DMG — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
kq2d_body_resolve_surface: CGB — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_surface.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_surface.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:95

선언 주석 원문
Kinematic surface response; returns incoming normal speed, or zero if separating.
Caller resolves penetration separately. Relative components must fit +/-8191.

kitaqgb/lib/physics2d.c:314

c
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface)
{
    s16 vx;
    s16 vy;
    s16 speed;
    s16 tangent;
    s16 bounce = 0;
    s16 impulse;
    s16 friction;
    if (body == 0 || surface == 0) return 0;
    vx = (s16)(body->vx - surface->vx);
    vy = (s16)(body->vy - surface->vy);
    speed = (s16)(kq2d_scale_q8(vx,surface->nx_q8) + kq2d_scale_q8(vy,surface->ny_q8));
    if (speed >= 0) return 0;
    speed = (s16)(0 - speed);
    if (speed > surface->bounce_threshold) bounce = kq2d_scale_q8(speed,(s16)surface->restitution_q8);
    if (bounce < surface->kick) bounce = surface->kick;
    impulse = (s16)(speed + bounce);
    // A resting contact is a tangent constraint, not a tiny rounded bounce.
    if (bounce == 0) {
        tangent = (s16)(kq2d__rest_component(vy,surface->nx_q8) - kq2d__rest_component(vx,surface->ny_q8));
        friction = kq2d_scale_q8(impulse,(s16)surface->friction_q8);
        if (tangent > friction) tangent = (s16)(tangent - friction);
        else if (tangent < (s16)(0 - friction)) tangent = (s16)(tangent + friction);
        else tangent = 0;
        body->vx = (s16)(surface->vx - kq2d__rest_component(tangent,surface->ny_q8));
        body->vy = (s16)(surface->vy + kq2d__rest_component(tangent,surface->nx_q8));
        return speed;
    }
    body->vx = (s16)(body->vx + kq2d_scale_q8(impulse,surface->nx_q8));
    body->vy = (s16)(body->vy + kq2d_scale_q8(impulse,surface->ny_q8));
    if (surface->friction_q8 != 0) {
        tangent = (s16)(kq2d_scale_q8(vy,surface->nx_q8) - kq2d_scale_q8(vx,surface->ny_q8));
        friction = kq2d_scale_q8(impulse,(s16)surface->friction_q8);
        if (tangent > friction) tangent = friction;
        if (tangent < (s16)(0 - friction)) tangent = (s16)(0 - friction);
        body->vx = (s16)(body->vx + kq2d_scale_q8(tangent,surface->ny_q8));
        body->vy = (s16)(body->vy - kq2d_scale_q8(tangent,surface->nx_q8));
    }
    return speed;
}
kq2d_body_set_pos

물체 중심만 바꾸고 속도, 크기, 활성 상태는 유지합니다.

사용 형식

c
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

x

중심 또는 점의 X 좌표입니다. 샘플에서는 픽셀 단위입니다.

y

중심 또는 점의 Y 좌표입니다. 샘플에서는 아래쪽이 양의 방향입니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

NULL은 무시합니다. 포인터가 유효하면 비활성 물체와 정적 물체도 변경합니다.

사용 예

c
kq2d_body_set_pos(&temp,-12,20);
    result[5]=temp.x; result[6]=temp.y;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_body_set_pos: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_body_set_pos: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:56

선언 주석 원문
Replace the center without altering velocity, extents or activity. Null is ignored.

kitaqgb/lib/physics2d.c:612

c
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y)
{
    if (body == 0) return;
    body->x = x;
    body->y = y;
}
kq2d_body_set_velocity

제한을 적용하거나 위치를 갱신하지 않고 속도를 직접 설정합니다.

사용 형식

c
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

vx

시뮬레이션 1틱당 X 변위이며, 위치와 같은 단위를 사용합니다.

vy

시뮬레이션 1틱당 Y 변위이며, 위치와 같은 단위를 사용합니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

NULL은 무시합니다. 포인터가 유효하면 비활성 물체와 정적 물체도 변경합니다.

사용 예

c
kq2d_body_set_velocity(&temp,40,-30);
    result[7]=temp.vx; result[8]=temp.vy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_body_set_velocity: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_body_set_velocity: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:58

선언 주석 원문
Replace velocity without clamping or checking activity/mass. Null is ignored.

kitaqgb/lib/physics2d.c:620

c
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy)
{
    if (body == 0) return;
    body->vx = vx;
    body->vy = vy;
}
kq2d_integrate_body

동적 물체 하나에 월드의 중력과 축별 속도 제한을 적용한 다음, 속도를 위치에 더합니다.

사용 형식

c
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

박스 적분 및 충돌 함수는 임시 저장 공간을 공유합니다. 인터럽트에서 이 물리 함수들을 재진입 호출하지 마세요.

NULL, 비활성 물체, 역질량이 0 이하인 물체는 무시합니다. 속도 제한에는 0 이상의 값을 지정하세요.

이 호출은 다른 물체와의 접촉을 해결하지 않습니다. world가 NULL인 경우도 무시합니다.

사용 예

c
kq2d_integrate_body(&world,&temp);
    result[18]=temp.x; result[19]=temp.y;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_integrate_body: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_integrate_body: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:47

선언 주석 원문
For one active dynamic body, add gravity, clamp each velocity axis and then
add velocity to position. Null inputs are ignored; no contacts are solved.
Use a nonnegative speed limit and keep additions in signed 16-bit range.

kitaqgb/lib/physics2d.c:664

c
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body)
{
    if (world == 0) return;
    if (body == 0) return;
    if (body->active == 0) return;
    if (body->inv_mass_q8 <= 0) return;

    kq2d_asm_value = body->vx;
    kq2d_asm_operand = world->gravity_x;
    kq2d_add_s16_asm();
    kq2d_asm_limit = world->max_speed;
    kq2d_clamp_abs_s16_asm();
    body->vx = kq2d_asm_value;

    kq2d_asm_value = body->vy;
    kq2d_asm_operand = world->gravity_y;
    kq2d_add_s16_asm();
    kq2d_asm_limit = world->max_speed;
    kq2d_clamp_abs_s16_asm();
    body->vy = kq2d_asm_value;

    kq2d_asm_value = body->x;
    kq2d_asm_operand = body->vx;
    kq2d_add_s16_asm();
    body->x = kq2d_asm_value;

    kq2d_asm_value = body->y;
    kq2d_asm_operand = body->vy;
    kq2d_add_s16_asm();
    body->y = kq2d_asm_value;
}
kq2d_overlap_aabb

중심으로 표현한 두 박스가 X와 Y 양쪽 축에서 엄격히 겹치는지 검사합니다.

사용 형식

c
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);

매개변수

a

유효한 물체 포인터입니다. 이 질의는 활성 상태, 질량, 플래그를 무시합니다.

b

유효한 물체 포인터입니다. 이 질의는 활성 상태, 질량, 플래그를 무시합니다.

반환값

내부가 겹치면 1, 접촉만 하거나 떨어져 있으면 0을 반환합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

사용 예

c
result[20]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);
    bodies[1].x=40; result[21]=kq2d_overlap_aabb(&bodies[0],&bodies[1]);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_overlap_aabb: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_overlap_aabb: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:51

선언 주석 원문
Test strict overlap of two centered boxes; touching edges return false.
Both pointers must be valid. Active/mass flags are ignored, and coordinate
differences and extent sums must fit the signed 16-bit calculations.

kitaqgb/lib/physics2d.c:579

c
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b)
{
    s16 dx = (s16)(b->x - a->x);
    s16 dy = (s16)(b->y - a->y);

    s16 adx = kq2d__abs_s16(dx);
    s16 ady = kq2d__abs_s16(dy);

    s16 sx = (s16)(a->half_x + b->half_x);
    s16 sy = (s16)(a->half_y + b->half_y);

    if (adx >= sx) return 0;
    if (ady >= sy) return 0;
    return 1;
}
kq2d_point_in_rect

점이 사각형 안에 있는지 검사합니다. 왼쪽·위쪽 변은 포함하고 오른쪽·아래쪽 변은 제외합니다.

사용 형식

c
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);

매개변수

x

중심 또는 점의 X 좌표입니다. 샘플에서는 픽셀 단위입니다.

y

중심 또는 점의 Y 좌표입니다. 샘플에서는 아래쪽이 양의 방향입니다.

r

왼쪽 위 위치 x/y와 너비/높이 w/h를 담은 KQRect 값입니다.

반환값

안에 있으면 1, 밖에 있으면 0을 반환합니다.

사용 조건과 제한

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

사용 예

c
result[16]=kq2d_point_in_rect(0,0,r1);
    result[17]=kq2d_point_in_rect(16,0,r1);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_point_in_rect: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_point_in_rect: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:72

선언 주석 원문
Delegate the half-open point test: include left/top and exclude right/bottom.
Coordinate-plus-size sums must remain representable as s16.

kitaqgb/lib/physics2d.c:705

c
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r)
{
    return kq_point_in_rect(x, y, r);
}
kq2d_rect_intersect

왼쪽 위 위치와 크기로 표현한 두 사각형의 내부가 겹치는지 검사합니다.

사용 형식

c
u8 kq2d_rect_intersect(KQRect a, KQRect b);

매개변수

a

왼쪽 위 좌표와 양의 너비·높이를 갖는 KQRect 값입니다.

b

왼쪽 위 좌표와 양의 너비·높이를 갖는 KQRect 값입니다.

반환값

내부가 겹치면 1, 접촉만 하거나 떨어져 있으면 0을 반환합니다.

사용 조건과 제한

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

0 이하의 크기를 명시적으로 거부하지 않습니다. 물체의 중심과 반크기를 KQRect에 그대로 복사하지 마세요.

사용 예

c
result[14]=kq2d_rect_intersect(r1,r2);
    r2.x=16; result[15]=kq2d_rect_intersect(r1,r2);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_rect_intersect: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_rect_intersect: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:69

선언 주석 원문
Delegate strict rectangle overlap to the fixed-point utility; edge-only
contact is false. Coordinate-plus-size sums must remain representable as s16.

kitaqgb/lib/physics2d.c:698

c
u8 kq2d_rect_intersect(KQRect a, KQRect b)
{
    return kq_rect_intersect(a, b);
}
kq2d_scale_q8

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

부호 있는 계수를 곱하고 256으로 나눕니다. 결과의 부호와 관계없이 0 방향으로 버림합니다.

사용 형식

c
s16 kq2d_scale_q8(s16 value, s16 coefficient);

매개변수

value

배율을 적용할 부호 있는 16비트 값입니다.

coefficient

-256..256 범위의 부호 있는 계수이며, 256이 1.0을 나타냅니다.

반환값

0 방향으로 버림한 결과를 부호 있는 16비트 값으로 반환합니다.

사용 조건과 제한

계수는 -256..256 범위에서만 사용하세요. +/-256은 +/-1배입니다. value=-32768, coefficient=-256일 때 수학적 결과는 32768이므로 s16에 담을 수 없습니다.

사용 예

c
result[0]=kq2d_scale_q8(-257,128);
    result[1]=kq2d_scale_q8(300,-256);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.

kq2d_scale_q8: DMG — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
kq2d_scale_q8: CGB — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_surface.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_surface.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:88

선언 주석 원문
Truncates toward zero, including negative values; coefficient is -256..256.

kitaqgb/lib/physics2d.c:8

c
s16 kq2d_scale_q8(s16 value, s16 coefficient)
{
    // Eight-bit shift/add product in HL:C, with sign applied after truncation.
    __asm {
        LD_HL_IMM value
        LD_A_HL
        LD_E_A
        INC_HL
        LD_A_HL
        LD_D_A
        OR_E
        JP_Z kqscale_zero
        LD_HL_IMM coefficient
        LD_A_HL
        LD_C_A
        INC_HL
        LD_A_HL
        LD_B_A
        LD_A_C
        OR_A
        JR_NZ kqscale_fraction
        LD_A_B
        OR_A
        JP_Z kqscale_zero
        LD_H_D
        LD_L_E
        AND_IMM 128
        RET_Z
        JP kqscale_negate
kqscale_fraction:
        LD_A_D
        XOR_B
        AND_IMM 128
        PUSH_AF
        LD_A_D
        AND_IMM 128
        JR_Z kqscale_value_positive
        XOR_A
        SUB_E
        LD_E_A
        LD_A_IMM 0
        SBC_D
        LD_D_A
kqscale_value_positive:
        LD_A_B
        AND_IMM 128
        JR_Z kqscale_coefficient_positive
        XOR_A
        SUB_C
        LD_C_A
kqscale_coefficient_positive:
        LD_HL_IMM 0
        // Unroll eight bits: avoid a loop branch on every fixed-point product.
        LD_A_C
        AND_IMM 1
        JR_Z kqscale_shift_0
        ADD_HL_DE
kqscale_shift_0:
        LD_A_H
        RRA
        LD_H_A
        LD_A_L
        RRA
        LD_L_A
        LD_A_C
        RRA
        LD_C_A
        LD_A_C
        AND_IMM 1
        JR_Z kqscale_shift_1
        ADD_HL_DE
kqscale_shift_1:
        LD_A_H
        RRA
        LD_H_A
        LD_A_L
        RRA
        LD_L_A
        LD_A_C
        RRA
        LD_C_A
        LD_A_C
        AND_IMM 1
        JR_Z kqscale_shift_2
        ADD_HL_DE
kqscale_shift_2:
        LD_A_H
        RRA
        LD_H_A
        LD_A_L
        RRA
        LD_L_A
        LD_A_C
        RRA
        LD_C_A
        LD_A_C
        AND_IMM 1
        JR_Z kqscale_shift_3
        ADD_HL_DE
kqscale_shift_3:
        LD_A_H
        RRA
        LD_H_A
        LD_A_L
        RRA
        LD_L_A
        LD_A_C
        RRA
        LD_C_A
        LD_A_C
        AND_IMM 1
        JR_Z kqscale_shift_4
        ADD_HL_DE
kqscale_shift_4:
        LD_A_H
        RRA
        LD_H_A
        LD_A_L
        RRA
        LD_L_A
        LD_A_C
        RRA
        LD_C_A
        LD_A_C
        AND_IMM 1
        JR_Z kqscale_shift_5
        ADD_HL_DE
kqscale_shift_5:
        LD_A_H
        RRA
        LD_H_A
        LD_A_L
        RRA
        LD_L_A
        LD_A_C
        RRA
        LD_C_A
        LD_A_C
        AND_IMM 1
        JR_Z kqscale_shift_6
        ADD_HL_DE
kqscale_shift_6:
        LD_A_H
        RRA
        LD_H_A
        LD_A_L
        RRA
        LD_L_A
        LD_A_C
        RRA
        LD_C_A
        LD_A_C
        AND_IMM 1
        JR_Z kqscale_shift_7
        ADD_HL_DE
kqscale_shift_7:
        LD_A_H
        RRA
        LD_H_A
        LD_A_L
        RRA
        LD_L_A
        LD_A_C
        RRA
        LD_C_A
        POP_AF
        OR_A
        RET_Z
kqscale_negate:
        XOR_A
        SUB_L
        LD_L_A
        LD_A_IMM 0
        SBC_H
        LD_H_A
        RET
kqscale_zero:
        LD_HL_IMM 0
        RET
    }
}
kq2d_step

활성 동적 물체를 적분한 뒤, 배열의 활성 항목 사이에서 접촉을 해결합니다.

사용 형식

c
void kq2d_step(KQWorld2D* world);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

월드는 호출자가 소유한 배열을 빌려 사용합니다. 호출자가 물체 저장 공간을 할당하고 소유하며, 사용하는 동안 유효하게 유지해야 합니다. 월드를 초기화해도 배열 원소는 초기화되지 않습니다.

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

침투 깊이가 작은 축을 따라 접촉을 해결하며, 같으면 Y축을 선택합니다. 위치 보정은 역질량을 사용하지만, 두 동적 물체의 해당 축 속도는 단순 평균으로 설정됩니다. 정적 물체와 충돌하면 해당 속도 성분은 0이 됩니다. 이 솔버는 restitution_q8을 사용하지 않습니다. 이산 충돌 처리이므로 빠르게 통과하는 물체를 놓칠 수 있습니다.

박스 적분 및 충돌 함수는 임시 저장 공간을 공유합니다. 인터럽트에서 이 물리 함수들을 재진입 호출하지 마세요.

world나 배열이 NULL이면 무시합니다. solver_iterations가 0이어도 접촉 처리를 한 번 수행합니다.

사용 예

c
kq2d_step(&world);
    result[22]=bodies[0].x; result[23]=bodies[0].y;
    result[24]=bodies[0].vx; result[25]=bodies[0].vy;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_step: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_step: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:43

선언 주석 원문
Advance active dynamic bodies, then visit each active unordered pair for
the configured contact passes (zero means one). Static bodies still participate
as obstacles. The world borrows its array and shares non-reentrant ASM scratch.
This is discrete integration; fast bodies can pass through thin obstacles.

kitaqgb/lib/physics2d.c:794

c
void kq2d_step(KQWorld2D* world)
{
    if (world == 0) return;
    if (world->bodies == 0) return;

    KQBody2D* bodies = world->bodies;
    u8 count = world->body_count;

    // Integrate dynamic bodies.
    u8 i;
    for (i = 0; i < count; i++)
    {
        KQBody2D* b = &bodies[(__safe_index u8)i];
        if (b->active == 0) continue;
        if (b->inv_mass_q8 <= 0) continue;

        kq2d_asm_value = b->vx;
        kq2d_asm_operand = world->gravity_x;
        kq2d_add_s16_asm();
        kq2d_asm_limit = world->max_speed;
        kq2d_clamp_abs_s16_asm();
        b->vx = kq2d_asm_value;

        kq2d_asm_value = b->vy;
        kq2d_asm_operand = world->gravity_y;
        kq2d_add_s16_asm();
        kq2d_asm_limit = world->max_speed;
        kq2d_clamp_abs_s16_asm();
        b->vy = kq2d_asm_value;

        kq2d_asm_value = b->x;
        kq2d_asm_operand = b->vx;
        kq2d_add_s16_asm();
        b->x = kq2d_asm_value;

        kq2d_asm_value = b->y;
        kq2d_asm_operand = b->vy;
        kq2d_add_s16_asm();
        b->y = kq2d_asm_value;
    }

    // Solve contacts with a small fixed iteration count.
    u8 iterations = world->solver_iterations;
    if (iterations == 0) iterations = 1;

    u8 it;
    for (it = 0; it < iterations; it++)
    {
        for (i = 0; i < count; i++)
        {
            KQBody2D* a = &bodies[(__safe_index u8)i];
            if (a->active == 0) continue;

            u8 j;
            for (j = (u8)(i + 1); j < count; j++)
            {
                KQBody2D* b = &bodies[(__safe_index u8)j];
                if (b->active == 0) continue;
                kq2d__resolve_pair(a, b);
            }
        }
    }
}
kq2d_surface_toi_q8

선형 운동을 가정하고 시작·끝의 부호 있는 간격으로 틱 내부의 교차 시각을 추정합니다.

사용 형식

c
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);

매개변수

start_gap

틱 시작 시점의 부호 있는 간격입니다. 양수이면 표면 바깥쪽입니다.

end_gap

틱 종료 시점의 부호 있는 간격입니다. 음수이면 표면을 지나 안쪽으로 들어간 상태입니다.

반환값

0..256 범위의 Q8 시각을 반환합니다. 192는 틱의 75%에 해당합니다.

사용 조건과 제한

간격을 +/-8191 이내로 유지하세요. 시작 간격이 0 이하이면 0, 끝 간격이 0 이상이면 256을 반환합니다. 처음부터 겹친 상태와 시각 0은 같은 값을 반환하며, 교차하지 않는 경우와 정확히 끝점에서 접촉하는 경우도 같은 값을 반환합니다. 위치는 변경하지 않습니다.

사용 예

c
result[4]=kq2d_surface_toi_q8(6,-2);
    result[5]=kq2d_surface_toi_q8(6,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.

kq2d_surface_toi_q8: DMG — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
kq2d_surface_toi_q8: CGB — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 빨간색 물체의 위치는 그대로입니다. 초록색 속도선은 왼쪽의 (8,16)에서 오른쪽의 (2,-8)로 바뀌어 파란색 표면에서의 반발과 접선 방향 마찰을 보여 줍니다. 패널 원점은 화면 (8,48)/(88,48), 물체 중심은 패널 내부 (24,40)입니다. 입사 속력은 16이고, 교차 시각 예제는 192/256을 반환합니다. 속력 제한 예제는 (300,400)을 (147,196)으로 줄입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_surface.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_surface.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:98

선언 주석 원문
Linear crossing time in Q8 (0..256); positive separation is outside.
Returns 0 for initial overlap, 256 for no crossing. Gaps must fit +/-8191.

kitaqgb/lib/physics2d.c:291

c
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap)
{
    if (start_gap <= 0) return 0;
    if (end_gap >= 0) return 256;
    return kq2d__fraction_q8((u16)start_gap, (u16)(start_gap - end_gap));
}
kq2d_world_init

배열을 2D 월드에 연결하고 중력을 (0,32), 접촉 반복 횟수를 4, 축별 속도 제한을 512로 설정합니다.

사용 형식

c
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

bodies

body_count개의 원소를 가진 호출자 소유 물체 배열의 시작 주소입니다.

body_count

비활성 항목을 포함한 배열 슬롯 수이며, 범위는 0..255입니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

월드는 호출자가 소유한 배열을 빌려 사용합니다. 호출자가 물체 저장 공간을 할당하고 소유하며, 사용하는 동안 유효하게 유지해야 합니다. 월드를 초기화해도 배열 원소는 초기화되지 않습니다.

사용 예

c
kq2d_world_init(&world,bodies,2);
    result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

kq2d_world_init: DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
DMG — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
kq2d_world_init: CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.
CGB — 왼쪽은 초기 상태, 오른쪽은 1틱 후입니다. 중심 (24,24), 속도 (4,16)인 빨간색 16x16 박스가 (28,36)에 도달하고 파란색 바닥에서 Y 속도가 0이 됩니다. 패널 원점은 화면 좌표 (8,48)과 (88,48)입니다. DMG에서는 모든 표시가 검은색입니다. RAM 검사로 초기화, 설정 함수, 적분, 사각형·점 질의, 부호 있는 배율 연산도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body2d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body2d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d.h:38

선언 주석 원문
Retain the caller-owned body array without initializing its elements.
Set gravity to (0,32), four contact iterations and a per-axis speed limit of 512.
A null world is ignored; the array must outlive subsequent world operations.

kitaqgb/lib/physics2d.c:564

c
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count)
{
    if (world == 0) return;

    world->bodies = bodies;
    world->body_count = body_count;
    world->gravity_x = 0;
    world->gravity_y = 32;
    world->solver_iterations = 4;
    world->max_speed = 512;
}

physics2d_circle.h — 원형 물체의 물리

원의 반지름, 역질량, 반발, 접선 방향 마찰, 월드 감쇠, 경계를 지원합니다. 호출자가 모든 물체 필드를 초기화해야 합니다. 물체의 friction_q8과 wall_friction_q8은 제거되는 접선 운동의 비율이고, linear_damping_q8은 유지되는 속도의 비율입니다. 바이트 계수는 256으로 나누므로 255도 정확히 1.0은 아닙니다.

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

원의 거리와 법선은 정수 근삿값입니다. 각 성분을 255 이하로 줄여도 거리 제곱의 합이 65535 이내라는 보장은 없습니다. 중심 좌표의 차, 반지름의 합, 역질량의 합이 표현 가능한 범위에 들어가야 합니다. 가중치 계산에서 inv_mass_q8 * 255가 32767 이내가 되도록 하세요. 샘플은 64를 사용합니다.

kq2dc_overlap_circle

축소한 중심 간 거리와 반지름의 합으로 내부 겹침을 근사 판정합니다.

사용 형식

c
u8 kq2dc_overlap_circle(const KQCircleBody2D* a, const KQCircleBody2D* b);

매개변수

a

첫 번째 원의 유효한 포인터입니다.

b

두 번째 원의 유효한 포인터입니다.

반환값

내부가 겹치면 1, 접촉만 하거나 떨어져 있으면 0을 반환합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

원의 거리와 법선은 정수 근삿값입니다. 각 성분을 255 이하로 줄여도 거리 제곱의 합이 65535 이내라는 보장은 없습니다. 중심 좌표의 차, 반지름의 합, 역질량의 합이 표현 가능한 범위에 들어가야 합니다. 가중치 계산에서 inv_mass_q8 * 255가 32767 이내가 되도록 하세요. 샘플은 64를 사용합니다.

유효한 두 포인터와 양의 반지름이 필요합니다. 활성 상태와 질량은 무시합니다. 축소 연산과 정수 제곱근 때문에 정확한 기하학적 거리 검사와 결과가 다를 수 있습니다.

사용 예

c
result[4]=kq2dc_overlap_circle(&balls[0],&balls[1]);
    balls[1].x=18; result[5]=kq2dc_overlap_circle(&balls[0],&balls[1]);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.

kq2dc_overlap_circle: DMG — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
DMG — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
kq2dc_overlap_circle: CGB — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
CGB — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_circle.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_circle.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d_circle.h:55

선언 주석 원문
Compare a reduced integer center distance with the reduced radius sum.
Valid pointers and positive radii are required; activity and mass are ignored.
This approximate test requires representable differences, radius sums and
squared-distance sum. Touching at the computed distance returns false.

kitaqgb/lib/physics2d_circle.c:397

c
u8 kq2dc_overlap_circle(const KQCircleBody2D* a, const KQCircleBody2D* b)
{
    s16 dx;
    s16 dy;
    s16 sdx;
    s16 sdy;
    u8 shift;
    u16 adx;
    u16 ady;
    u16 dist_sq;
    u16 dist_scaled;
    s16 radius_sum;
    u16 radius_sum_scaled;

    dx = (s16)(b->x - a->x);
    dy = (s16)(b->y - a->y);
    sdx = dx;
    sdy = dy;
    shift = kq2dc__reduce_vector(&sdx, &sdy);

    adx = (u16)kq2dc__abs_s16(sdx);
    ady = (u16)kq2dc__abs_s16(sdy);
    dist_sq = (u16)((adx * adx) + (ady * ady));
    dist_scaled = kq2dc__isqrt_u16(dist_sq);

    radius_sum = (s16)(a->radius + b->radius);
    radius_sum_scaled = kq2dc__scale_down_positive(radius_sum, shift);

    if (dist_scaled >= radius_sum_scaled) return 0;
    return 1;
}
kq2dc_set_bounds

원형 물체 월드의 경계를 저장하고 활성화합니다. 물체를 즉시 이동시키지는 않습니다.

사용 형식

c
void kq2dc_set_bounds(KQCircleWorld2D* world, s16 min_x, s16 min_y, s16 max_x, s16 max_y);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

min_x

왼쪽 경계입니다. 원 중심의 최솟값은 min_x + radius로 제한됩니다.

min_y

위쪽 경계입니다. 원 중심의 최솟값은 min_y + radius로 제한됩니다.

max_x

오른쪽 경계입니다. 원 중심의 최댓값은 max_x - radius로 제한됩니다.

max_y

아래쪽 경계입니다. 원 중심의 최댓값은 max_y - radius로 제한됩니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

NULL은 무시합니다. 경계의 순서나 원이 들어갈 공간은 검사하지 않으므로 너비와 높이를 원의 지름 이상으로 지정하세요. 실제 위치 보정은 시뮬레이션 단계에서 수행합니다.

사용 예

c
kq2dc_set_bounds(&world,4,4,60,60);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.

kq2dc_set_bounds: DMG — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
DMG — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
kq2dc_set_bounds: CGB — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
CGB — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_circle.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_circle.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d_circle.h:45

선언 주석 원문
Store and enable bounds without validating their order or fitting bodies
immediately. Supply extents large enough for body diameters. Null is ignored.

kitaqgb/lib/physics2d_circle.c:382

c
void kq2dc_set_bounds(KQCircleWorld2D* world, s16 min_x, s16 min_y, s16 max_x, s16 max_y)
{
    if (world == 0) return;

    world->use_bounds = 1;
    world->min_x = min_x;
    world->min_y = min_y;
    world->max_x = max_x;
    world->max_y = max_y;
}
kq2dc_step

원을 적분하고 경계 및 원 사이의 접촉을 해결한 다음 선형 감쇠를 적용합니다.

사용 형식

c
void kq2dc_step(KQCircleWorld2D* world);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

월드는 호출자가 소유한 배열을 빌려 사용합니다. 호출자가 물체 저장 공간을 할당하고 소유하며, 사용하는 동안 유효하게 유지해야 합니다. 월드를 초기화해도 배열 원소는 초기화되지 않습니다.

원의 거리와 법선은 정수 근삿값입니다. 각 성분을 255 이하로 줄여도 거리 제곱의 합이 65535 이내라는 보장은 없습니다. 중심 좌표의 차, 반지름의 합, 역질량의 합이 표현 가능한 범위에 들어가야 합니다. 가중치 계산에서 inv_mass_q8 * 255가 32767 이내가 되도록 하세요. 샘플은 64를 사용합니다.

마지막으로 -1..1인 속도 성분을 0으로 만듭니다. 감쇠가 255여도 속도가 조금 줄어듭니다. 정지한 원 사이의 겹침은 남을 수 있습니다. 경계가 활성화되어 있으면 정적 원도 경계 안으로 이동됩니다. 반복 횟수 0은 1회를 뜻하며, world/배열이 NULL이면 무시합니다. 이산·양자화 솔버이므로 속도 변화에 따라 접촉을 처리하는 순서가 달라질 수 있습니다.

사용 예

c
kq2dc_step(&world);
    result[6]=balls[0].x; result[7]=balls[0].y; result[8]=balls[0].vx;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.

kq2dc_step: DMG — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
DMG — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
kq2dc_step: CGB — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
CGB — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_circle.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_circle.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d_circle.h:50

선언 주석 원문
Integrate active dynamic bodies, apply bounds, solve contacts, then damp
velocity and snap components in -1..1 to zero. Zero solver iterations means one.
Pairs with both velocities zero are skipped, so resting overlaps can remain.
Bounds can reposition static bodies; null world/array inputs are ignored.

kitaqgb/lib/physics2d_circle.c:433

c
void kq2dc_step(KQCircleWorld2D* world)
{
    KQCircleBody2D* bodies;
    u8 count;
    u8 i;
    u8 iterations;
    u8 it;

    if (world == 0) return;
    if (world->bodies == 0) return;

    bodies = world->bodies;
    count = world->body_count;

    for (i = 0; i < count; i++)
    {
        KQCircleBody2D* body = &bodies[(__safe_index u8)i];
        if (body->active == 0) continue;
        if (body->inv_mass_q8 <= 0)
        {
            if (world->use_bounds != 0) kq2dc__resolve_bounds(world, body);
            continue;
        }

        body->vx = (s16)(body->vx + world->gravity_x);
        body->vy = (s16)(body->vy + world->gravity_y);
        body->vx = kq2dc__clamp_abs(body->vx, world->max_speed);
        body->vy = kq2dc__clamp_abs(body->vy, world->max_speed);

        body->x = (s16)(body->x + body->vx);
        body->y = (s16)(body->y + body->vy);

        if (world->use_bounds != 0) kq2dc__resolve_bounds(world, body);
    }

    iterations = world->solver_iterations;
    if (iterations == 0) iterations = 1;

    for (it = 0; it < iterations; it++)
    {
        for (i = 0; i < count; i++)
        {
            KQCircleBody2D* a = &bodies[(__safe_index u8)i];
            if (a->active == 0) continue;
            if (a->vx == 0 && a->vy == 0) continue;

            if (world->use_bounds != 0) kq2dc__resolve_bounds(world, a);

            {
                u8 j;
                for (j = 0; j < count; j++)
                {
                    KQCircleBody2D* b = &bodies[(__safe_index u8)j];
                    s16 radius_sum;
                    if (j == i) continue;
                    if (b->active == 0) continue;
                    // Avoid revisiting an earlier moving body, but still allow a moving body
                    // to resolve against a stationary slot with a lower index. Velocities are live
                    // solver state, so contact ordering can change which later pairs are visited.
                    if (j < i && (b->vx != 0 || b->vy != 0)) continue;
                    radius_sum = (s16)(a->radius + b->radius);
                    if (kq2dc__abs_s16((s16)(b->x - a->x)) >= radius_sum) continue;
                    if (kq2dc__abs_s16((s16)(b->y - a->y)) >= radius_sum) continue;
                    kq2dc__resolve_pair(a, b);
                }
            }
        }
    }

    for (i = 0; i < count; i++)
    {
        KQCircleBody2D* body = &bodies[(__safe_index u8)i];
        if (body->active == 0) continue;
        if (body->inv_mass_q8 <= 0) continue;

        body->vx = kq2dc__mul_q8(body->vx, world->linear_damping_q8);
        body->vy = kq2dc__mul_q8(body->vy, world->linear_damping_q8);

        if (body->vx >= -1 && body->vx <= 1) body->vx = 0;
        if (body->vy >= -1 && body->vy <= 1) body->vy = 0;

        if (world->use_bounds != 0) kq2dc__resolve_bounds(world, body);
    }
}
kq2dc_world_init

원 배열을 연결하고 중력 0, 반복 4회, 축별 속도 제한 768, 감쇠 252/256으로 설정합니다.

사용 형식

c
void kq2dc_world_init(KQCircleWorld2D* world, KQCircleBody2D* bodies, u8 body_count);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

bodies

body_count개의 원소를 가진 호출자 소유 물체 배열의 시작 주소입니다.

body_count

비활성 항목을 포함한 배열 슬롯 수이며, 범위는 0..255입니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

월드는 호출자가 소유한 배열을 빌려 사용합니다. 호출자가 물체 저장 공간을 할당하고 소유하며, 사용하는 동안 유효하게 유지해야 합니다. 월드를 초기화해도 배열 원소는 초기화되지 않습니다.

경계의 초기 좌표는 (0,0)..(159,143)이지만 비활성 상태입니다. 벽 반발 계수는 240, 벽 마찰은 16입니다. 원형 물체 초기화 함수는 없으므로 호출자가 모든 물체 필드를 설정해야 합니다. world가 NULL이면 무시합니다.

사용 예

c
kq2dc_world_init(&world,balls,1);
    result[0]=world.gravity_y; result[1]=world.solver_iterations;
    result[2]=world.max_speed; result[3]=world.linear_damping_q8;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.

kq2dc_world_init: DMG — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
DMG — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
kq2dc_world_init: CGB — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.
CGB — 반지름 6인 빨간색 원이 왼쪽 중심 (24,24)에서 오른쪽 (54,24)로 이동합니다. 패널 내부 경계는 (4,4)..(60,60)입니다. 오른쪽 벽이 중심을 54로 제한하고 X 속도를 32에서 -15로 바꿉니다. 벽 반발 계수 128/256을 적용한 뒤 감쇠 255/256을 적용한 결과입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 원과 경계가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_circle.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_circle.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics2d_circle.h:42

선언 주석 원문
Retain a caller-owned array without initializing bodies. Set zero gravity,
four contact passes, per-axis limit 768 and damping 252/256; bounds start disabled.
A null world is ignored. Keep the array alive for subsequent steps.

kitaqgb/lib/physics2d_circle.c:360

c
void kq2dc_world_init(KQCircleWorld2D* world, KQCircleBody2D* bodies, u8 body_count)
{
    if (world == 0) return;

    world->bodies = bodies;
    world->body_count = body_count;
    world->gravity_x = 0;
    world->gravity_y = 0;
    world->solver_iterations = 4;
    world->max_speed = 768;
    world->linear_damping_q8 = 252;
    world->use_bounds = 0;
    world->min_x = 0;
    world->min_y = 0;
    world->max_x = 159;
    world->max_y = 143;
    world->wall_restitution_q8 = 240;
    world->wall_friction_q8 = 16;
}

physics3d.h — 3D AABB 물리

중심과 축별 반크기로 표현하는, 회전하지 않는 3D 박스용 물리 기능입니다. 질량/역질량으로 접촉 가중치를 정하고 restitution_q8로 반발을 제어하며 ax/ay/az로 지속 가속도를 적용합니다. 렌더링은 별도입니다. 샘플은 같은 물체의 정면도와 평면도를 그려 깊이 방향 이동과 벽 반발을 보여 줍니다.

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

physics3d.c는 ROM 뱅크 2에 배치됩니다. 샘플은 MBC5 128 KB ROM을 사용하며, 이 구현을 먼저 포함하고 main을 뱅크 0에 둡니다. 호출 중에는 외부에서 ROM 매핑을 변경하지 마세요.

last_impact_speed는 접촉 축을 따라 서로 가까워지는 속도의 최댓값을 기록합니다. 적분 시 활성 동적 물체에서는 초기화되지만 정적 물체와 비활성 물체에서는 유지됩니다. break_speed나 KQ3D_BODY_BROKEN은 자동 파괴를 일으키지 않습니다. 파괴 시점은 게임에서 판단하고 flags/active를 직접 변경해야 합니다.

kq3d_body_init

3D 중심, 반크기, 질량을 초기화합니다. 속도, 가속도, 충격값, 플래그를 0으로 만들고 물체를 활성화합니다.

사용 형식

c
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

x

중심 또는 점의 X 좌표입니다. 샘플에서는 픽셀 단위입니다.

y

중심 또는 점의 Y 좌표입니다. 샘플에서는 아래쪽이 양의 방향입니다.

z

중심의 Z 좌표입니다. 샘플의 평면도에서는 세로 방향으로 표시됩니다.

half_x

X축 반크기입니다. 박스의 전체 너비는 이 값의 두 배입니다.

half_y

Y축 반크기입니다. 박스의 전체 높이는 이 값의 두 배입니다.

half_z

Z축 반크기입니다. 전체 깊이는 이 값의 두 배입니다.

mass_q8

256이 1.0을 나타내는 질량값입니다. 0 이하이면 정적 물체가 됩니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

physics3d.c는 ROM 뱅크 2에 배치됩니다. 샘플은 MBC5 128 KB ROM을 사용하며, 이 구현을 먼저 포함하고 main을 뱅크 0에 둡니다. 호출 중에는 외부에서 ROM 매핑을 변경하지 마세요.

반발 계수는 224, break_speed는 0입니다. 질량은 kq3d_body_set_mass의 규칙을 따릅니다. NULL은 무시하며, 호출자가 유효한 반크기를 지정해야 합니다.

사용 예

c
kq3d_body_init(&temp,10,20,30,8,8,8,256);
    result[3]=temp.inv_mass_q8; result[4]=temp.restitution_q8; result[5]=temp.active;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

kq3d_body_init: DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
kq3d_body_init: CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics3d.h:50

선언 주석 원문
Initialize an active centered box with zero velocity/acceleration,
restitution 224, cleared impact/flags and mass set through the weight helper.
The caller supplies valid half extents. Null body is ignored.

kitaqgb/lib/physics3d.c:330

c
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8)
{
    if (body == 0) return;

    body->x = x;
    body->y = y;
    body->z = z;
    body->vx = 0;
    body->vy = 0;
    body->vz = 0;
    body->ax = 0;
    body->ay = 0;
    body->az = 0;
    body->half_x = half_x;
    body->half_y = half_y;
    body->half_z = half_z;
    body->restitution_q8 = 224;
    body->break_speed = 0;
    body->last_impact_speed = 0;
    body->active = 1;
    body->flags = 0;
    kq3d_body_set_mass(body, mass_q8);
}
kq3d_body_set_mass

요청한 질량을 저장하고 위치 보정과 반발에 사용할 역질량 가중치를 계산합니다.

사용 형식

c
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);

매개변수

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

mass_q8

256이 1.0을 나타내는 질량값입니다. 0 이하이면 정적 물체가 됩니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

physics3d.c는 ROM 뱅크 2에 배치됩니다. 샘플은 MBC5 128 KB ROM을 사용하며, 이 구현을 먼저 포함하고 main을 뱅크 0에 둡니다. 호출 중에는 외부에서 ROM 매핑을 변경하지 마세요.

질량이 0 이하이면 역질량은 0이 되어 정적 물체가 됩니다. 양의 질량에는 정수식 32767/max(mass,64)를 사용하며 최솟값은 1입니다. 저장된 질량은 요청값 그대로이므로 이 가중치는 정확한 Q8 역수가 아닙니다. 질량 256의 역질량은 127입니다. 속도와 활성 상태는 유지하며 NULL은 무시합니다.

사용 예

c
kq3d_body_set_mass(&temp,32); result[6]=temp.mass_q8; result[7]=temp.inv_mass_q8;
    kq3d_body_set_mass(&temp,0); result[8]=temp.inv_mass_q8;
    kq3d_body_set_mass(&temp,256);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

kq3d_body_set_mass: DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
kq3d_body_set_mass: CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics3d.h:55

선언 주석 원문
Store the requested mass; nonpositive mass makes the body static.
For positive mass compute inverse weight as max(1,32767/max(mass,64)).
The stored mass retains the original input; this is a relative solver weight,
not an exact Q8 reciprocal. Null body is ignored.

kitaqgb/lib/physics3d.c:311

c
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8)
{
    if (body == 0) return;

    body->mass_q8 = mass_q8;
    if (mass_q8 <= 0)
    {
        body->inv_mass_q8 = 0;
        return;
    }

    if (mass_q8 < 64) mass_q8 = 64;
    body->inv_mass_q8 = (s16)(32767 / mass_q8);
    if (body->inv_mass_q8 <= 0) body->inv_mass_q8 = 1;
}
kq3d_dot_q8_8

부호 있는 곱 세 개를 각각 256으로 나누고 각 항을 0 방향으로 버림한 다음 더합니다.

사용 형식

c
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);

매개변수

x

대응하는 계수를 곱할 부호 있는 16비트 성분입니다. 위치나 속도를 나타낼 수 있습니다.

y

대응하는 계수를 곱할 부호 있는 16비트 성분입니다. 위치나 속도를 나타낼 수 있습니다.

z

대응하는 계수를 곱할 부호 있는 16비트 성분입니다. 위치나 속도를 나타낼 수 있습니다.

ax

이 축의 부호 있는 바이트 계수(-128..127)이며, 1/256 배율로 적용합니다.

ay

이 축의 부호 있는 바이트 계수(-128..127)이며, 1/256 배율로 적용합니다.

az

이 축의 부호 있는 바이트 계수(-128..127)이며, 1/256 배율로 적용합니다.

반환값

양자화한 세 항의 합을 s16으로 반환합니다.

사용 조건과 제한

physics3d.c는 ROM 뱅크 2에 배치됩니다. 샘플은 MBC5 128 KB ROM을 사용하며, 이 구현을 먼저 포함하고 main을 뱅크 0에 둡니다. 호출 중에는 외부에서 ROM 매핑을 변경하지 마세요.

각 항을 먼저 0 방향으로 버림하면 전체 합을 한 번 시프트하는 것과 결과가 다를 수 있습니다. 계수에는 1.0=256을 저장할 수 없습니다. 최종 합은 포화 처리하지 않습니다.

사용 예

c
result[13]=kq3d_dot_q8_8(256,128,0,64,-64,127);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

kq3d_dot_q8_8: DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
kq3d_dot_q8_8: CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics3d.h:74

선언 주석 원문
Sum three signed products, shifting each by eight bits before addition.
Coefficients are signed bytes scaled by 1/256; the 16-bit sum is not saturated.

kitaqgb/lib/physics3d.c:576

c
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az)
{
    return __sdot3_q8_8(x, y, z, ax, ay, az);
}
kq3d_integrate_body

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

활성 동적 물체 하나의 충격값을 초기화하고 월드 중력과 물체 가속도를 더합니다. 각 축 속도를 제한한 다음 위치를 갱신합니다.

사용 형식

c
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

body

수정할 물체의 포인터입니다. 이 연산에서 사용하지 않는 필드는 유지됩니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

박스 적분 및 충돌 함수는 임시 저장 공간을 공유합니다. 인터럽트에서 이 물리 함수들을 재진입 호출하지 마세요.

physics3d.c는 ROM 뱅크 2에 배치됩니다. 샘플은 MBC5 128 KB ROM을 사용하며, 이 구현을 먼저 포함하고 main을 뱅크 0에 둡니다. 호출 중에는 외부에서 ROM 매핑을 변경하지 마세요.

last_impact_speed는 접촉 축을 따라 서로 가까워지는 속도의 최댓값을 기록합니다. 적분 시 활성 동적 물체에서는 초기화되지만 정적 물체와 비활성 물체에서는 유지됩니다. break_speed나 KQ3D_BODY_BROKEN은 자동 파괴를 일으키지 않습니다. 파괴 시점은 게임에서 판단하고 flags/active를 직접 변경해야 합니다.

ax/ay/az는 유지되며 다음 적분에서도 다시 적용됩니다. 이 함수만으로는 접촉을 해결하지 않습니다. NULL, 비활성 물체, 정적 물체는 변경하지 않습니다.

사용 예

c
kq3d_integrate_body(&world,&temp);
    result[9]=temp.x; result[10]=temp.y; result[11]=temp.z; result[12]=temp.last_impact_speed;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

kq3d_integrate_body: DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
kq3d_integrate_body: CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics3d.h:66

선언 주석 원문
Reset impact for one active dynamic body, add gravity and persistent body
acceleration, clamp velocity per axis and advance position. Static/inactive
bodies retain impact state. Null inputs are ignored; no contacts are solved.
Use a nonnegative speed limit and avoid overflow before clamping.

kitaqgb/lib/physics3d.c:436

c
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body)
{
    if (world == 0) return;
    if (body == 0) return;
    if (body->active == 0) return;
    if (body->inv_mass_q8 <= 0) return;

    body->last_impact_speed = 0;
    kq3d_asm_value = body->vx;
    kq3d_asm_operand = world->gravity_x;
    kq3d_add_s16_asm();
    kq3d_asm_operand = body->ax;
    kq3d_add_s16_asm();
    kq3d_asm_limit = world->max_speed;
    kq3d_clamp_abs_s16_asm();
    body->vx = kq3d_asm_value;

    kq3d_asm_value = body->vy;
    kq3d_asm_operand = world->gravity_y;
    kq3d_add_s16_asm();
    kq3d_asm_operand = body->ay;
    kq3d_add_s16_asm();
    kq3d_asm_limit = world->max_speed;
    kq3d_clamp_abs_s16_asm();
    body->vy = kq3d_asm_value;

    kq3d_asm_value = body->vz;
    kq3d_asm_operand = world->gravity_z;
    kq3d_add_s16_asm();
    kq3d_asm_operand = body->az;
    kq3d_add_s16_asm();
    kq3d_asm_limit = world->max_speed;
    kq3d_clamp_abs_s16_asm();
    body->vz = kq3d_asm_value;

    kq3d_asm_value = body->x;
    kq3d_asm_operand = body->vx;
    kq3d_add_s16_asm();
    body->x = kq3d_asm_value;

    kq3d_asm_value = body->y;
    kq3d_asm_operand = body->vy;
    kq3d_add_s16_asm();
    body->y = kq3d_asm_value;

    kq3d_asm_value = body->z;
    kq3d_asm_operand = body->vz;
    kq3d_add_s16_asm();
    body->z = kq3d_asm_value;
}
kq3d_overlap_aabb

중심으로 표현한 두 박스가 세 축 모두에서 엄격히 겹치는지 검사합니다.

사용 형식

c
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);

매개변수

a

유효한 물체 포인터입니다. 이 질의는 활성 상태, 질량, 플래그를 무시합니다.

b

유효한 물체 포인터입니다. 이 질의는 활성 상태, 질량, 플래그를 무시합니다.

반환값

내부가 겹치면 1, 접촉만 하거나 떨어져 있으면 0을 반환합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

physics3d.c는 ROM 뱅크 2에 배치됩니다. 샘플은 MBC5 128 KB ROM을 사용하며, 이 구현을 먼저 포함하고 main을 뱅크 0에 둡니다. 호출 중에는 외부에서 ROM 매핑을 변경하지 마세요.

사용 예

c
result[14]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);
    bodies[1].z=32; result[15]=kq3d_overlap_aabb(&bodies[0],&bodies[1]);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

kq3d_overlap_aabb: DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
kq3d_overlap_aabb: CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics3d.h:70

선언 주석 원문
Test strict overlap on all three axes; face-only contact returns false.
Valid pointers are required and flags are ignored. Center differences and
extent sums must fit the signed 16-bit magnitude calculations.

kitaqgb/lib/physics3d.c:357

c
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b)
{
    s16 dx = kq3d__abs_s16((s16)(b->x - a->x));
    s16 dy = kq3d__abs_s16((s16)(b->y - a->y));
    s16 dz = kq3d__abs_s16((s16)(b->z - a->z));

    s16 sx = (s16)(a->half_x + b->half_x);
    s16 sy = (s16)(a->half_y + b->half_y);
    s16 sz = (s16)(a->half_z + b->half_z);

    if (dx >= sx) return 0;
    if (dy >= sy) return 0;
    if (dz >= sz) return 0;
    return 1;
}
kq3d_step

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

활성 동적 물체를 적분하고, 월드의 활성 항목 사이에서 접촉 위치 보정, 반발, 충격 기록을 처리합니다.

사용 형식

c
void kq3d_step(KQWorld3D* world);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

월드는 호출자가 소유한 배열을 빌려 사용합니다. 호출자가 물체 저장 공간을 할당하고 소유하며, 사용하는 동안 유효하게 유지해야 합니다. 월드를 초기화해도 배열 원소는 초기화되지 않습니다.

합, 차, 반크기의 합, 접촉 위치 보정에 쓰는 곱이 부호 있는 16비트 범위 안에 들어가도록 하세요. 속도 제한은 덧셈 후에 적용되므로 덧셈 도중의 오버플로를 막지 못합니다.

박스 적분 및 충돌 함수는 임시 저장 공간을 공유합니다. 인터럽트에서 이 물리 함수들을 재진입 호출하지 마세요.

physics3d.c는 ROM 뱅크 2에 배치됩니다. 샘플은 MBC5 128 KB ROM을 사용하며, 이 구현을 먼저 포함하고 main을 뱅크 0에 둡니다. 호출 중에는 외부에서 ROM 매핑을 변경하지 마세요.

접촉에는 침투 깊이가 가장 작은 축을 사용하며, 같으면 X, Y, Z 순으로 우선합니다. 서로 가까워지는 운동일 때만 반발을 적용합니다. 역질량과 두 반발 계수의 평균을 사용하며, 평균은 0..256으로 제한합니다. 빠른 관통, 회전, 각운동량, 마찰은 처리하지 않습니다.

last_impact_speed는 접촉 축을 따라 서로 가까워지는 속도의 최댓값을 기록합니다. 적분 시 활성 동적 물체에서는 초기화되지만 정적 물체와 비활성 물체에서는 유지됩니다. break_speed나 KQ3D_BODY_BROKEN은 자동 파괴를 일으키지 않습니다. 파괴 시점은 게임에서 판단하고 flags/active를 직접 변경해야 합니다.

world나 배열이 NULL이면 무시합니다. solver_iterations가 0이어도 접촉 처리를 한 번 수행합니다.

중간 연산 impact*(256+restitution)과 correction*inverse-mass도 s16입니다. 곱이 32767 이내가 되도록 하세요. 예를 들어 restitution이 256이면 impact는 63 이하여야 합니다.

사용 예

c
kq3d_step(&world);
    result[16]=bodies[0].x; result[17]=bodies[0].y; result[18]=bodies[0].z;
    result[19]=bodies[0].vx; result[20]=bodies[0].vz;
    result[21]=bodies[0].last_impact_speed; result[22]=bodies[0].flags;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

kq3d_step: DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
kq3d_step: CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics3d.h:61

선언 주석 원문
Integrate active dynamic bodies and reset their impact values, then solve
each active unordered pair for the configured passes (zero means one).
Static bodies retain previous impact maxima until the game clears them.
Acceleration persists; flags and break thresholds remain game-owned.
This discrete solver shares non-reentrant ASM scratch and can miss fast crossings.

kitaqgb/lib/physics3d.c:492

c
void kq3d_step(KQWorld3D* world)
{
    if (world == 0) return;
    if (world->bodies == 0) return;

    KQBody3D* bodies = world->bodies;
    u8 count = world->body_count;

    u8 i;
    for (i = 0; i < count; i++)
    {
        KQBody3D* b = &bodies[(__safe_index u8)i];
        if (b->active == 0) continue;
        if (b->inv_mass_q8 <= 0) continue;

        b->last_impact_speed = 0;
        kq3d_asm_value = b->vx;
        kq3d_asm_operand = world->gravity_x;
        kq3d_add_s16_asm();
        kq3d_asm_operand = b->ax;
        kq3d_add_s16_asm();
        kq3d_asm_limit = world->max_speed;
        kq3d_clamp_abs_s16_asm();
        b->vx = kq3d_asm_value;

        kq3d_asm_value = b->vy;
        kq3d_asm_operand = world->gravity_y;
        kq3d_add_s16_asm();
        kq3d_asm_operand = b->ay;
        kq3d_add_s16_asm();
        kq3d_asm_limit = world->max_speed;
        kq3d_clamp_abs_s16_asm();
        b->vy = kq3d_asm_value;

        kq3d_asm_value = b->vz;
        kq3d_asm_operand = world->gravity_z;
        kq3d_add_s16_asm();
        kq3d_asm_operand = b->az;
        kq3d_add_s16_asm();
        kq3d_asm_limit = world->max_speed;
        kq3d_clamp_abs_s16_asm();
        b->vz = kq3d_asm_value;

        kq3d_asm_value = b->x;
        kq3d_asm_operand = b->vx;
        kq3d_add_s16_asm();
        b->x = kq3d_asm_value;

        kq3d_asm_value = b->y;
        kq3d_asm_operand = b->vy;
        kq3d_add_s16_asm();
        b->y = kq3d_asm_value;

        kq3d_asm_value = b->z;
        kq3d_asm_operand = b->vz;
        kq3d_add_s16_asm();
        b->z = kq3d_asm_value;
    }

    u8 iterations = world->solver_iterations;
    if (iterations == 0) iterations = 1;

    u8 it;
    for (it = 0; it < iterations; it++)
    {
        for (i = 0; i < count; i++)
        {
            KQBody3D* a = &bodies[(__safe_index u8)i];
            if (a->active == 0) continue;

            u8 j;
            for (j = (u8)(i + 1); j < count; j++)
            {
                KQBody3D* b = &bodies[(__safe_index u8)j];
                if (b->active == 0) continue;
                kq3d__resolve_pair(a, b);
            }
        }
    }
}
kq3d_world_init

물체 배열을 3D 월드에 연결하고 중력을 (0,24,0), 반복 횟수를 4, 축별 속도 제한을 512로 설정합니다.

사용 형식

c
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);

매개변수

world

물체 배열과 시뮬레이션 설정을 보관하는 월드의 포인터입니다.

bodies

body_count개의 원소를 가진 호출자 소유 물체 배열의 시작 주소입니다.

body_count

비활성 항목을 포함한 배열 슬롯 수이며, 범위는 0..255입니다.

반환값

반환값은 없습니다. 이 항목에서는 갱신되는 필드와 변경이 적용되는 시점을 설명합니다.

사용 조건과 제한

위치, 반지름, 반크기, 속도, 중력에는 일관된 정수 단위를 사용하세요. 한 단계는 시뮬레이션 1틱입니다. 샘플에서는 1단위가 1픽셀입니다. 이 함수들은 위치를 Q8.8로 자동 변환하거나 화면에 그리지 않습니다.

월드는 호출자가 소유한 배열을 빌려 사용합니다. 호출자가 물체 저장 공간을 할당하고 소유하며, 사용하는 동안 유효하게 유지해야 합니다. 월드를 초기화해도 배열 원소는 초기화되지 않습니다.

physics3d.c는 ROM 뱅크 2에 배치됩니다. 샘플은 MBC5 128 KB ROM을 사용하며, 이 구현을 먼저 포함하고 main을 뱅크 0에 둡니다. 호출 중에는 외부에서 ROM 매핑을 변경하지 마세요.

사용 예

c
kq3d_world_init(&world,bodies,2);
    result[0]=world.gravity_y; result[1]=world.solver_iterations; result[2]=world.max_speed;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

kq3d_world_init: DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
DMG — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
kq3d_world_init: CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.
CGB — 왼쪽은 X/Y 정면도, 오른쪽은 X/Z 평면도입니다. 초록색 윤곽은 초기 위치 (24,24,16), 빨간색 박스는 1틱 후의 (36,24,24), 파란색 영역은 정적 장애물을 나타냅니다. X 속도는 반발로 16에서 -14가 되고 Z 속도는 8을 유지합니다. 충격값은 16이지만 break_speed=1이어도 flags는 0입니다. 패널 원점은 화면 (8,48)/(88,48)입니다. DMG에서는 모든 표시가 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\physics_body3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\physics_body3d.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=128k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/physics3d.h:46

선언 주석 원문
Borrow the body array without initializing it. Set gravity (0,24,0), four
contact passes and a per-axis speed limit of 512. Null world is ignored;
the caller retains ownership and must keep the array alive.

kitaqgb/lib/physics3d.c:294

c
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count)
{
    if (world == 0) return;

    world->bodies = bodies;
    world->body_count = body_count;
    world->gravity_x = 0;
    world->gravity_y = 24;
    world->gravity_z = 0;
    world->solver_iterations = 4;
    world->max_speed = 512;
}

raster.h — 구간·주사선별 스크롤 테이블

Raster 라이브러리는 8항목 밴드 테이블과 144개 가시 줄 모두에서 X를 바꾸는 LineX 렌더러를 제공합니다. 밴드는 고정 HUD, 시차 스크롤, 윈도우 변경, CGB 색 영역에 적합합니다. LineX는 물결치는 타이틀과 화면 효과에 적합합니다. 드라이버 하나를 선택하고 두 가지를 함께 실행하지 마세요.

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

주사선 물결 효과와 애니메이션으로 등장하는 타이틀

주사선마다 배경 X 좌표를 바꾸면 기둥과 글자가 물결처럼 휘어집니다. 워프, 보스 등장 또는 타이틀 연출에 사용할 수 있습니다. 아래 미리보기는 캡처 이미지 8장을 순환하며, ROM에서는 매 프레임 파동의 위상을 진행시킵니다.

Raster_Push 연산은 최대 8개 밴드를 예약합니다. 모든 주사선에 서로 다른 가로 오프셋을 주려면 Raster_LineXRunFrame을 사용하세요. 스프라이트와 윈도우는 휘어지지 않습니다. 렌더러는 보이는 144개 주사선 전체에서 CPU를 점유하고 인터럽트를 마스킹하므로 게임 로직과 오디오는 호출 사이에 갱신하세요.

CGB 캡처: 각 주사선에서 기둥의 가장자리가 휘어집니다. 64라인 길이의 파동이 장면을 지나가며, 좌우로 최대 24픽셀씩 변위가 생깁니다.
CGB 캡처: 각 주사선에서 기둥의 가장자리가 휘어집니다. 64라인 길이의 파동이 장면을 지나가며, 좌우로 최대 24픽셀씩 변위가 생깁니다.

연속 파동 예제

타이틀 등장 예제

타이틀이 큰 물결과 함께 오른쪽에서 들어온 뒤 작은 잔물결로 바뀌고 멈춥니다. 같은 디렉터리의 raster_wave.c를 포함하므로 두 소스 파일을 함께 두세요. 아래 API 항목에 빌드 명령과 개별 사용 설명이 있습니다.

Raster 라이브러리는 8항목 밴드 테이블과 144개 가시 줄 모두에서 X를 바꾸는 LineX 렌더러를 제공합니다. 밴드는 고정 HUD, 시차 스크롤, 윈도우 변경, CGB 색 영역에 적합합니다. LineX는 물결치는 타이틀과 화면 효과에 적합합니다. 드라이버 하나를 선택하고 두 가지를 함께 실행하지 마세요.

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

Raster_BuildHudBottom

위쪽은 스크롤하는 플레이 영역, 아래쪽은 고정 HUD로 구성합니다. LY=0에서 카메라 좌표를 사용하고 hud_y에서 배경 (0,0)으로 전환합니다.

사용 형식

c
u8 Raster_BuildHudBottom(u8 hud_y, u8 camera_x, u8 camera_y);

매개변수

hud_y

분할 줄 1..143입니다. 0 또는 144 이상은 BAD_RANGE를 반환합니다.

camera_x

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

camera_y

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

매개변수가 유효하면 기존 화면 분할을 멈추고 테이블을 지운 뒤 새 밴드를 추가합니다. 잘못된 매개변수는 테이블과 항목 수를 보존하고 BAD_RANGE를 저장합니다. 구성이 성공해도 Raster_Commit을 호출해야 합니다.

사용 예

c
Raster_BuildHudBottom(96,8,8);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

96행부터 아래는 고정됩니다. 카메라 (8,8)은 위쪽 사각형들을 (24,8), (24,72)에 놓고, 아래쪽 사각형은 (32,112)에 남습니다. FIXED BOTTOM HUD는 아래쪽에 유지됩니다.

Raster_BuildHudBottom: DMG — 96행부터 아래는 고정됩니다. 카메라 (8,8)은 위쪽 사각형들을 (24,8), (24,72)에 놓고, 아래쪽 사각형은 (32,112)에 남습니다. FIXED BOTTOM HUD는 아래쪽에 유지됩니다.
DMG — 96행부터 아래는 고정됩니다. 카메라 (8,8)은 위쪽 사각형들을 (24,8), (24,72)에 놓고, 아래쪽 사각형은 (32,112)에 남습니다. FIXED BOTTOM HUD는 아래쪽에 유지됩니다.
Raster_BuildHudBottom: CGB — 96행부터 아래는 고정됩니다. 카메라 (8,8)은 위쪽 사각형들을 (24,8), (24,72)에 놓고, 아래쪽 사각형은 (32,112)에 남습니다. FIXED BOTTOM HUD는 아래쪽에 유지됩니다.
CGB — 96행부터 아래는 고정됩니다. 카메라 (8,8)은 위쪽 사각형들을 (24,8), (24,72)에 놓고, 아래쪽 사각형은 (32,112)에 남습니다. FIXED BOTTOM HUD는 아래쪽에 유지됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_hud_bottom.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:73

선언 주석 원문
Build a scrolling upper playfield and fixed bottom HUD after validating the split.

kitaqgb/lib/raster.c:183

c
u8 Raster_BuildHudBottom(u8 hud_y, u8 camera_x, u8 camera_y)
{
    u8 r;

    if (hud_y == 0) return Raster_SetError(KQ_RASTER_BAD_RANGE);
    if (hud_y >= 144) return Raster_SetError(KQ_RASTER_BAD_RANGE);

    Raster_Clear();
    r = Raster_Push(0, camera_x, camera_y);
    if (r != KQ_RASTER_OK) return r;
    return Raster_Push(hud_y, 0, 0);
}
Raster_BuildHudTop

위쪽 HUD를 고정하는 배경 밴드 두 개를 구성합니다. LY=0에서 (0,0), hud_height에서 카메라 좌표를 적용합니다. 배경 스크롤을 분할하는 방식이며 윈도우는 사용하지 않습니다.

사용 형식

c
u8 Raster_BuildHudTop(u8 hud_height, u8 camera_x, u8 camera_y);

매개변수

hud_height

분할 줄 1..143입니다. 0 또는 144 이상은 BAD_RANGE를 반환합니다.

camera_x

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

camera_y

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

매개변수가 유효하면 기존 화면 분할을 멈추고 테이블을 지운 뒤 새 밴드를 추가합니다. 잘못된 매개변수는 테이블과 항목 수를 보존하고 BAD_RANGE를 저장합니다. 구성이 성공해도 Raster_Commit을 호출해야 합니다.

사용 예

c
Raster_BuildHudTop(32,8,8);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

위쪽 32개 줄은 고정됩니다. 위쪽 사각형은 (32,16)에 남고, 카메라 (8,8)은 나머지 두 사각형을 (24,72), (24,104)로 옮깁니다. FIXED TOP HUD는 위쪽에 유지됩니다.

Raster_BuildHudTop: DMG — 위쪽 32개 줄은 고정됩니다. 위쪽 사각형은 (32,16)에 남고, 카메라 (8,8)은 나머지 두 사각형을 (24,72), (24,104)로 옮깁니다. FIXED TOP HUD는 위쪽에 유지됩니다.
DMG — 위쪽 32개 줄은 고정됩니다. 위쪽 사각형은 (32,16)에 남고, 카메라 (8,8)은 나머지 두 사각형을 (24,72), (24,104)로 옮깁니다. FIXED TOP HUD는 위쪽에 유지됩니다.
Raster_BuildHudTop: CGB — 위쪽 32개 줄은 고정됩니다. 위쪽 사각형은 (32,16)에 남고, 카메라 (8,8)은 나머지 두 사각형을 (24,72), (24,104)로 옮깁니다. FIXED TOP HUD는 위쪽에 유지됩니다.
CGB — 위쪽 32개 줄은 고정됩니다. 위쪽 사각형은 (32,16)에 남고, 카메라 (8,8)은 나머지 두 사각형을 (24,72), (24,104)로 옮깁니다. FIXED TOP HUD는 위쪽에 유지됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_hud_top.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:71

선언 주석 원문
Validate the HUD height, then replace pending splits with a fixed top band
and scrolling playfield. The new table still requires an explicit commit.

kitaqgb/lib/raster.c:169

c
u8 Raster_BuildHudTop(u8 hud_height, u8 camera_x, u8 camera_y)
{
    u8 r;

    if (hud_height == 0) return Raster_SetError(KQ_RASTER_BAD_RANGE);
    if (hud_height >= 144) return Raster_SetError(KQ_RASTER_BAD_RANGE);

    Raster_Clear();
    r = Raster_Push(0, 0, 0);
    if (r != KQ_RASTER_OK) return r;
    return Raster_Push(hud_height, camera_x, camera_y);
}
Raster_BuildParallax2

수평 오프셋이 서로 다른 배경 밴드 두 개를 구성합니다. LY=0에는 far_scx, split_y부터는 near_scx를 사용하며 Y 스크롤은 공유합니다.

사용 형식

c
u8 Raster_BuildParallax2(u8 split_y, u8 far_scx, u8 near_scx, u8 scy);

매개변수

split_y

분할 줄 1..143입니다. 0 또는 144 이상은 BAD_RANGE를 반환합니다.

far_scx

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

near_scx

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

scy

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

매개변수가 유효하면 기존 화면 분할을 멈추고 테이블을 지운 뒤 새 밴드를 추가합니다. 잘못된 매개변수는 테이블과 항목 수를 보존하고 BAD_RANGE를 저장합니다. 구성이 성공해도 Raster_Commit을 호출해야 합니다.

사용 예

c
Raster_BuildParallax2(64,0,16,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예약된 64행에서 X가 0에서 16으로 바뀝니다. 사각형은 (32,16), (16,80), (16,112)에 나타나며 아래쪽 영역만 왼쪽으로 16픽셀 이동합니다.

Raster_BuildParallax2: DMG — 예약된 64행에서 X가 0에서 16으로 바뀝니다. 사각형은 (32,16), (16,80), (16,112)에 나타나며 아래쪽 영역만 왼쪽으로 16픽셀 이동합니다.
DMG — 예약된 64행에서 X가 0에서 16으로 바뀝니다. 사각형은 (32,16), (16,80), (16,112)에 나타나며 아래쪽 영역만 왼쪽으로 16픽셀 이동합니다.
Raster_BuildParallax2: CGB — 예약된 64행에서 X가 0에서 16으로 바뀝니다. 사각형은 (32,16), (16,80), (16,112)에 나타나며 아래쪽 영역만 왼쪽으로 16픽셀 이동합니다.
CGB — 예약된 64행에서 X가 0에서 16으로 바뀝니다. 사각형은 (32,16), (16,80), (16,112)에 나타나며 아래쪽 영역만 왼쪽으로 16픽셀 이동합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_parallax2.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:76

선언 주석 원문
Build two horizontal-scroll bands sharing one vertical scroll value.

kitaqgb/lib/raster.c:197

c
u8 Raster_BuildParallax2(u8 split_y, u8 far_scx, u8 near_scx, u8 scy)
{
    u8 r;

    if (split_y == 0) return Raster_SetError(KQ_RASTER_BAD_RANGE);
    if (split_y >= 144) return Raster_SetError(KQ_RASTER_BAD_RANGE);

    Raster_Clear();
    r = Raster_Push(0, far_scx, scy);
    if (r != KQ_RASTER_OK) return r;
    return Raster_Push(split_y, near_scx, scy);
}
Raster_BuildParallax3

LY=0, y1, y2에서 시작하는 밴드에 scx0, scx1, scx2를 등록합니다. 먼·중간·가까운 레이어에 서로 다른 수평 오프셋을 주고 Y 스크롤은 공유합니다.

사용 형식

c
u8 Raster_BuildParallax3(u8 y1, u8 y2, u8 scx0, u8 scx1, u8 scx2, u8 scy);

매개변수

y1

분할 줄이며, 1 <= y1 < y2 <= 143을 만족해야 합니다.

y2

분할 줄이며, 1 <= y1 < y2 <= 143을 만족해야 합니다.

scx0

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

scx1

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

scx2

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

scy

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

매개변수가 유효하면 기존 화면 분할을 멈추고 테이블을 지운 뒤 새 밴드를 추가합니다. 잘못된 매개변수는 테이블과 항목 수를 보존하고 BAD_RANGE를 저장합니다. 구성이 성공해도 Raster_Commit을 호출해야 합니다.

사용 예

c
Raster_BuildParallax3(64,104,0,8,16,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예약된 64행과 104행을 경계로 X 오프셋 0, 8, 16을 선택합니다. (32,16), (24,80), (16,112)의 사각형이 세 밴드의 점점 커지는 이동량을 보여 줍니다.

Raster_BuildParallax3: DMG — 예약된 64행과 104행을 경계로 X 오프셋 0, 8, 16을 선택합니다. (32,16), (24,80), (16,112)의 사각형이 세 밴드의 점점 커지는 이동량을 보여 줍니다.
DMG — 예약된 64행과 104행을 경계로 X 오프셋 0, 8, 16을 선택합니다. (32,16), (24,80), (16,112)의 사각형이 세 밴드의 점점 커지는 이동량을 보여 줍니다.
Raster_BuildParallax3: CGB — 예약된 64행과 104행을 경계로 X 오프셋 0, 8, 16을 선택합니다. (32,16), (24,80), (16,112)의 사각형이 세 밴드의 점점 커지는 이동량을 보여 줍니다.
CGB — 예약된 64행과 104행을 경계로 X 오프셋 0, 8, 16을 선택합니다. (32,16), (24,80), (16,112)의 사각형이 세 밴드의 점점 커지는 이동량을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_parallax3.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:79

선언 주석 원문
Build three horizontal-scroll bands at ordered visible split lines. Invalid
parameters leave the previous pending table intact and set the error status.

kitaqgb/lib/raster.c:212

c
u8 Raster_BuildParallax3(u8 y1, u8 y2, u8 scx0, u8 scx1, u8 scx2, u8 scy)
{
    u8 r;

    if (y1 == 0) return Raster_SetError(KQ_RASTER_BAD_RANGE);
    if (y2 >= 144) return Raster_SetError(KQ_RASTER_BAD_RANGE);
    if (y2 <= y1) return Raster_SetError(KQ_RASTER_BAD_RANGE);

    Raster_Clear();
    r = Raster_Push(0, scx0, scy);
    if (r != KQ_RASTER_OK) return r;
    r = Raster_Push(y1, scx1, scy);
    if (r != KQ_RASTER_OK) return r;
    return Raster_Push(y2, scx2, scy);
}
Raster_Clear

같은 장면에서 테이블을 다시 구성하기 전에 화면 분할 예약을 즉시 멈추고 항목 수, 순서, 오류 상태를 초기화합니다. 테이블 저장 공간의 모든 바이트를 0으로 만들지는 않습니다.

사용 형식

c
void Raster_Clear();

반환값

반환값은 없습니다.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

화면 분할을 멈춰도 SCX, SCY, WX, WY는 0이 되지 않습니다. 원하는 기본 상태는 Scroll_SetBg 같은 일반 설정 함수로 지정하세요. 이 함수들은 이전의 VBlank/STAT IE 비트나 IME도 복원하지 않습니다.

사용 예

c
Raster_Clear();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

Raster_Clear: DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
Raster_Clear: CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:39

선언 주석 원문
Stop splits immediately and clear bookkeeping. Build and commit a new table to restart.

kitaqgb/lib/raster.c:65

c
void Raster_Clear()
{
    Scroll_SplitReset();
    Raster_CountValue = 0;
    Raster_LastLyValue = 0;
    Raster_HasLastLy = 0;
    Raster_LastErrorValue = KQ_RASTER_OK;
}
Raster_Commit

구성한 공유 테이블을 활성화합니다. 앞선 추가가 실패했더라도 그 전에 성공적으로 들어간 항목은 활성화되므로 호출자가 각 등록 결과를 검사해야 합니다.

사용 형식

c
u8 Raster_Commit();

반환값

마지막으로 저장된 오류를 반환합니다. 0이라고 해서 이전의 모든 등록이 성공했다는 뜻은 아닙니다.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

테이블이 비어 있지 않으면 VBlank/STAT IE 비트를 설정하고 EI를 실행해 인터럽트를 활성화합니다. 다른 IE 비트는 보존합니다. 빈 테이블은 화면 분할 예약을 비활성화하지만 전역 인터럽트 설정을 복원하지 않습니다.

사용 예

c
result[2]=Raster_Commit();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

Raster_Commit: DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
Raster_Commit: CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:67

선언 주석 원문
Publish pending splits and return the stored status. This commits even if an
earlier append failed; callers should inspect errors while building the table.

kitaqgb/lib/raster.c:161

c
u8 Raster_Commit()
{
    Scroll_SplitCommit();
    return Raster_LastErrorValue;
}
Raster_Disable

테이블을 지우고 빈 테이블을 커밋해 래스터 밴드를 비활성화합니다. 분할 스크롤을 사용하지 않는 장면으로 들어갈 때 명시적으로 멈추는 용도로 사용합니다.

사용 형식

c
void Raster_Disable();

반환값

반환값은 없습니다.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

화면 분할을 멈춰도 SCX, SCY, WX, WY는 0이 되지 않습니다. 원하는 기본 상태는 Scroll_SetBg 같은 일반 설정 함수로 지정하세요. 이 함수들은 이전의 VBlank/STAT IE 비트나 IME도 복원하지 않습니다.

사용 예

c
Raster_Disable();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

Raster_Disable: DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
Raster_Disable: CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:41

선언 주석 원문
Commit an empty split table so no raster bands remain active.

kitaqgb/lib/raster.c:75

c
void Raster_Disable()
{
    Raster_Clear();
    Scroll_SplitCommit();
}
Raster_GetCount

Raster 래퍼를 통해 등록한 밴드 수를 읽습니다. Clear/Disable은 0으로 초기화하며, 커밋만 하면 값은 유지됩니다.

사용 형식

c
u8 Raster_GetCount();

반환값

항목 수 0..8을 반환합니다. 남은 용량은 8에서 이 값을 뺀 값입니다. 읽어도 상태는 바뀌지 않습니다.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

사용 예

c
result[0]=Raster_GetCount();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

Raster_GetCount: DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
Raster_GetCount: CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:44

선언 주석 원문
Read the number of bands currently recorded by this wrapper.

kitaqgb/lib/raster.c:82

c
u8 Raster_GetCount()
{
    return Raster_CountValue;
}
Raster_GetLastError

마지막으로 저장된 Raster 상태를 지우지 않고 읽습니다. 이전의 모든 실패를 누적해서 기록하는 값은 아닙니다.

사용 형식

c
u8 Raster_GetLastError();

반환값

저장된 상태값 0..4를 반환합니다. 커밋은 이 값을 반환하지만 오류를 자동으로 되돌리거나 테이블을 폐기하지 않습니다.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

사용 예

c
result[1]=Raster_GetLastError();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

Raster_GetLastError: DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
Raster_GetLastError: CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:46

선언 주석 원문
Read the last stored status without clearing it.

kitaqgb/lib/raster.c:88

c
u8 Raster_GetLastError()
{
    return Raster_LastErrorValue;
}
Raster_Init

공유 밴드 테이블을 비우고 화면 분할을 멈춥니다. 항목 수, 마지막 LY의 유효 여부, 오류 상태를 초기화합니다. Scroll_Init과 달리 배경·윈도우 좌표는 초기화하지 않습니다.

사용 형식

c
void Raster_Init();

반환값

반환값은 없습니다.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

화면 분할을 멈춰도 SCX, SCY, WX, WY는 0이 되지 않습니다. 원하는 기본 상태는 Scroll_SetBg 같은 일반 설정 함수로 지정하세요. 이 함수들은 이전의 VBlank/STAT IE 비트나 IME도 복원하지 않습니다.

사용 예

c
Raster_Init();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

Raster_Init: DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
Raster_Init: CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:37

선언 주석 원문
Stop split scheduling, empty the shared table and clear error/count state.

kitaqgb/lib/raster.c:59

c
void Raster_Init()
{
    Raster_Clear();
}
Raster_LineXGetOffset

상태, 화면, 위상을 바꾸지 않고 요청한 줄의 SCX를 계산합니다.

사용 형식

c
u8 Raster_LineXGetOffset(const RasterLineX* effect, u8 ly);

매개변수

effect

초기화된 RasterLineX의 포인터이며, 호출이 끝날 때까지 유효해야 합니다.

ly

조회할 줄 좌표 0..255입니다. 가시 줄은 0..143입니다. 조회는 범위 오류를 반환하는 대신 파형 주기에 따라 순환합니다.

반환값

기준 X에 해당 줄의 변위를 더한 8비트 SCX입니다. 샘플에서 위상 8, 줄 0을 조회하면 17을 반환합니다.

사용 조건과 제한

SCX는 8비트 값이며 배경은 256픽셀에서 순환합니다. 음수 변위는 256을 법으로 하는 바이트 값으로 표현합니다. 화면에 보이는 영역 바깥까지 맵을 채워 두세요.

이 효과는 배경의 수평 스크롤을 바꿉니다. 스프라이트와 윈도우는 휘어지지 않습니다. RunFrame은 가시 영역 144줄 전체에서 CPU를 점유하고 인터럽트를 차단합니다. 호출 사이에 게임 로직과 오디오를 갱신하고, STAT 래스터 인터럽트 드라이버와 함께 사용하지 마세요.

이미지는 KOKURA의 DMG 및 CGB 실행에서 얻었습니다. 기둥과 글자를 포함한 160×144 장면의 모든 픽셀을 예상되는 줄별 좌표와 비교합니다. 실기 타이밍은 시험하지 않았습니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 폴더 아래에 놓고 그 상위 폴더에서 PowerShell을 여세요. ROM은 DMG와 CGB를 모두 지원합니다. KOKURA --hardware로 dmg 또는 cgb를 선택하세요.

사용 예

c
wave_lookup = Raster_LineXGetOffset(&wave, 0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

Raster_LineXGetOffset: DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
Raster_LineXGetOffset: CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png
구현과 소스

kitaqgb/lib/raster.h:91

선언 주석 원문
Look up the selected periodic profile at LY + phase and add base X modulo
256. An unknown profile returns the unmodified base X.

kitaqgb/lib/raster.c:264

c
u8 Raster_LineXGetOffset(const RasterLineX* effect, u8 ly)
{
    u8 index;

    if (effect->profile == KQ_RASTER_LINE_X_TITLE) {
        index = (u8)((ly + effect->phase) & 15);
        return (u8)(effect->base_x + Raster_LineXXTitle[(__safe_index u8)index]);
    }

    if (effect->profile == KQ_RASTER_LINE_TRAVEL_GATE) {
        index = (u8)((ly + effect->phase) & 63);
        return (u8)(effect->base_x + Raster_LineXTravelGate[(__safe_index u8)index]);
    }

    return effect->base_x;
}
Raster_LineXInit

프로파일과 기준 X를 초기화하고 위상을 0, 프레임당 위상 증가량을 1로 설정합니다. 그리기나 스크롤 레지스터 쓰기는 하지 않습니다.

사용 형식

c
void Raster_LineXInit(RasterLineX* effect, u8 profile, u8 base_x);

매개변수

effect

쓰기 가능한 RasterLineX 저장 공간의 포인터입니다. 미리 초기화할 필요는 없습니다.

profile

0(FLAT)은 변위를 적용하지 않습니다. 1(X_TITLE)은 −4..+3픽셀 오프셋을 16줄마다 반복하고, 2(TRAVEL_GATE)는 ±24픽셀 파형을 64줄마다 반복합니다. 그 외 값은 변위를 적용하지 않습니다.

base_x

파형 변위에 더할 배경 X이며, 픽셀 단위 0..255입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

SCX는 8비트 값이며 배경은 256픽셀에서 순환합니다. 음수 변위는 256을 법으로 하는 바이트 값으로 표현합니다. 화면에 보이는 영역 바깥까지 맵을 채워 두세요.

이 효과는 배경의 수평 스크롤을 바꿉니다. 스프라이트와 윈도우는 휘어지지 않습니다. RunFrame은 가시 영역 144줄 전체에서 CPU를 점유하고 인터럽트를 차단합니다. 호출 사이에 게임 로직과 오디오를 갱신하고, STAT 래스터 인터럽트 드라이버와 함께 사용하지 마세요.

이미지는 KOKURA의 DMG 및 CGB 실행에서 얻었습니다. 기둥과 글자를 포함한 160×144 장면의 모든 픽셀을 예상되는 줄별 좌표와 비교합니다. 실기 타이밍은 시험하지 않았습니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 폴더 아래에 놓고 그 상위 폴더에서 PowerShell을 여세요. ROM은 DMG와 CGB를 모두 지원합니다. KOKURA --hardware로 dmg 또는 cgb를 선택하세요.

사용 예

c
Raster_LineXInit(&wave, KQ_RASTER_LINE_TRAVEL_GATE, 0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

Raster_LineXInit: DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
Raster_LineXInit: CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png
구현과 소스

kitaqgb/lib/raster.h:82

선언 주석 원문
Initialize a scanline-wave state with phase zero and one phase step per frame.

kitaqgb/lib/raster.c:229

c
void Raster_LineXInit(RasterLineX* effect, u8 profile, u8 base_x)
{
    effect->profile = profile;
    effect->base_x = base_x;
    effect->phase = 0;
    effect->phase_step = 1;
    effect->frame_divider = 1;
    effect->frame_counter = 0;
}
Raster_LineXRunFrame

VBlank를 기다린 뒤 다음 144개 가시 줄을 줄별 배경 X로 렌더링합니다. 이후 분주 카운터를 진행시키고 선택한 간격에 따라 위상을 갱신합니다.

사용 형식

c
void Raster_LineXRunFrame(RasterLineX* effect);

매개변수

effect

초기화된 RasterLineX의 포인터이며, 호출이 끝날 때까지 유효해야 합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

LCD가 꺼져 있으면 효과를 변경하지 않고 즉시 반환합니다. 켜져 있으면 144줄 모두의 SCX 갱신이 끝날 때까지 대기하고 인터럽트 활성 상태를 복원한 뒤 Scroll 보조 기능을 최종 SCX와 동기화합니다. 반환 시점이 VBlank라는 보장은 없습니다. VRAM에 직접 쓰기 전에는 VBlank를 기다리거나 안전한 접근 시점을 관리하는 전송 함수를 사용하세요.

SCX는 8비트 값이며 배경은 256픽셀에서 순환합니다. 음수 변위는 256을 법으로 하는 바이트 값으로 표현합니다. 화면에 보이는 영역 바깥까지 맵을 채워 두세요.

이 효과는 배경의 수평 스크롤을 바꿉니다. 스프라이트와 윈도우는 휘어지지 않습니다. RunFrame은 가시 영역 144줄 전체에서 CPU를 점유하고 인터럽트를 차단합니다. 호출 사이에 게임 로직과 오디오를 갱신하고, STAT 래스터 인터럽트 드라이버와 함께 사용하지 마세요.

이미지는 KOKURA의 DMG 및 CGB 실행에서 얻었습니다. 기둥과 글자를 포함한 160×144 장면의 모든 픽셀을 예상되는 줄별 좌표와 비교합니다. 실기 타이밍은 시험하지 않았습니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 폴더 아래에 놓고 그 상위 폴더에서 PowerShell을 여세요. ROM은 DMG와 CGB를 모두 지원합니다. KOKURA --hardware로 dmg 또는 cgb를 선택하세요.

사용 예

c
Raster_LineXRunFrame(&wave);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

Raster_LineXRunFrame: DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
Raster_LineXRunFrame: CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png
구현과 소스

kitaqgb/lib/raster.h:96

선언 주석 원문
Render all 144 visible lines with one SCX write per line, then advance phase.
This foreground renderer masks interrupts during the visible frame. Do game
and audio work between calls; do not combine it with a STAT raster driver.
Returns without changing the effect when the LCD is off.

kitaqgb/lib/raster.c:298

c
void Raster_LineXRunFrame(RasterLineX* effect)
{
    u8 interrupt_state;
    if ((Raster_LineXLcdc & 0x80) == 0) return;
    Raster_LineXTable = Raster_LineXFlat;
    Raster_LineXMask = 15;
    if (effect->profile == KQ_RASTER_LINE_X_TITLE) {
        Raster_LineXTable = Raster_LineXXTitle;
    }
    if (effect->profile == KQ_RASTER_LINE_TRAVEL_GATE) {
        Raster_LineXTable = Raster_LineXTravelGate;
        Raster_LineXMask = 63;
    }
    Raster_LineXPhase = effect->phase;
    Raster_LineXBase = effect->base_x;
    interrupt_state = __critical_enter();
    __asm {
        PUSH_AF
        PUSH_BC
        PUSH_DE
        PUSH_HL
        // Use the current VBlank when the preceding frame ended there.
        // Waiting for another VBlank edge would leave every second frame flat.
raster_linex_vblank:
        LDH_A_MEM 0x44
        CP_IMM 144
        JR_C raster_linex_vblank
        LD_B_IMM 0
        LD_A_MEM Raster_LineXPhase
        LD_C_A
        LD_A_MEM Raster_LineXMask
        LD_D_A
        LD_A_MEM Raster_LineXBase
        LD_E_A
raster_linex_line:
        LD_A_B
        ADD_C
        AND_D
        LD_L_A
        LD_H_IMM 0
        PUSH_DE
        LD_A_MEM Raster_LineXTable
        LD_E_A
        LD_A_MEM Raster_LineXTable+1
        LD_D_A
        ADD_HL_DE
        POP_DE
        LD_A_HL
        ADD_E
        PUSH_AF
raster_linex_wait:
        LDH_A_MEM 0x44
        CP_B
        JR_NZ raster_linex_wait
        POP_AF
        LDH_MEM_A 0x43
        INC_B
        LD_A_B
        CP_IMM 144
        JR_NZ raster_linex_line
        POP_HL
        POP_DE
        POP_BC
        POP_AF
    }
    // Synchronize the scroll helper's tracked state with the last hardware write.
    __scroll_bg_x_set(Raster_LineXScx);
    __critical_leave(interrupt_state);
    effect->frame_counter++;
    if (effect->frame_counter >= effect->frame_divider) {
        effect->frame_counter = 0;
        effect->phase = (u8)(effect->phase + effect->phase_step);
    }
}
Raster_LineXSetPhase

파형 위치를 직접 설정합니다. 기준 X, 속도, 분주 카운터는 유지합니다.

사용 형식

c
void Raster_LineXSetPhase(RasterLineX* effect, u8 phase);

매개변수

effect

초기화된 RasterLineX의 포인터이며, 호출이 끝날 때까지 유효해야 합니다.

phase

8비트 위상값입니다. 선택한 파형은 16단계 또는 64단계마다 반복됩니다.

반환값

반환값은 없습니다.

사용 조건과 제한

SCX는 8비트 값이며 배경은 256픽셀에서 순환합니다. 음수 변위는 256을 법으로 하는 바이트 값으로 표현합니다. 화면에 보이는 영역 바깥까지 맵을 채워 두세요.

이 효과는 배경의 수평 스크롤을 바꿉니다. 스프라이트와 윈도우는 휘어지지 않습니다. RunFrame은 가시 영역 144줄 전체에서 CPU를 점유하고 인터럽트를 차단합니다. 호출 사이에 게임 로직과 오디오를 갱신하고, STAT 래스터 인터럽트 드라이버와 함께 사용하지 마세요.

이미지는 KOKURA의 DMG 및 CGB 실행에서 얻었습니다. 기둥과 글자를 포함한 160×144 장면의 모든 픽셀을 예상되는 줄별 좌표와 비교합니다. 실기 타이밍은 시험하지 않았습니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 폴더 아래에 놓고 그 상위 폴더에서 PowerShell을 여세요. ROM은 DMG와 CGB를 모두 지원합니다. KOKURA --hardware로 dmg 또는 cgb를 선택하세요.

사용 예

c
Raster_LineXSetPhase(&wave, 8);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

Raster_LineXSetPhase: DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
Raster_LineXSetPhase: CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png
구현과 소스

kitaqgb/lib/raster.h:88

선언 주석 원문
Set the byte phase directly without resetting the frame-divider counter.

kitaqgb/lib/raster.c:257

c
void Raster_LineXSetPhase(RasterLineX* effect, u8 phase)
{
    effect->phase = phase;
}
Raster_LineXSetProfile

프로파일을 선택하고 위상과 프레임 분주 카운터를 0으로 초기화합니다. 기준 X와 속도는 유지합니다.

사용 형식

c
void Raster_LineXSetProfile(RasterLineX* effect, u8 profile);

매개변수

effect

초기화된 RasterLineX의 포인터이며, 호출이 끝날 때까지 유효해야 합니다.

profile

0(FLAT)은 변위를 적용하지 않습니다. 1(X_TITLE)은 −4..+3픽셀 오프셋을 16줄마다 반복하고, 2(TRAVEL_GATE)는 ±24픽셀 파형을 64줄마다 반복합니다. 그 외 값은 변위를 적용하지 않습니다.

반환값

반환값은 없습니다.

사용 조건과 제한

SCX는 8비트 값이며 배경은 256픽셀에서 순환합니다. 음수 변위는 256을 법으로 하는 바이트 값으로 표현합니다. 화면에 보이는 영역 바깥까지 맵을 채워 두세요.

이 효과는 배경의 수평 스크롤을 바꿉니다. 스프라이트와 윈도우는 휘어지지 않습니다. RunFrame은 가시 영역 144줄 전체에서 CPU를 점유하고 인터럽트를 차단합니다. 호출 사이에 게임 로직과 오디오를 갱신하고, STAT 래스터 인터럽트 드라이버와 함께 사용하지 마세요.

이미지는 KOKURA의 DMG 및 CGB 실행에서 얻었습니다. 기둥과 글자를 포함한 160×144 장면의 모든 픽셀을 예상되는 줄별 좌표와 비교합니다. 실기 타이밍은 시험하지 않았습니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 폴더 아래에 놓고 그 상위 폴더에서 PowerShell을 여세요. ROM은 DMG와 CGB를 모두 지원합니다. KOKURA --hardware로 dmg 또는 cgb를 선택하세요.

사용 예

c
Raster_LineXSetProfile(&wave, KQ_RASTER_LINE_X_TITLE);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.

Raster_LineXSetProfile: DMG / 16프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
DMG / 16프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
Raster_LineXSetProfile: DMG / 60프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
DMG / 60프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
Raster_LineXSetProfile: DMG / 120프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
DMG / 120프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
Raster_LineXSetProfile: CGB / 16프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
CGB / 16프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
Raster_LineXSetProfile: CGB / 60프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
CGB / 60프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
Raster_LineXSetProfile: CGB / 120프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.
CGB / 120프레임 — 이 샘플의 독자적인 타이틀 ORBIT GUARD가 큰 파형과 함께 오른쪽에서 들어옵니다. 48프레임을 그린 뒤 작은 물결로 바뀌고, 96프레임부터 정지합니다. 등장 연출은 160프레임 후 반복됩니다. 이미지는 등장, 작은 물결, 정착한 타이틀 순서입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_title_entry.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_title_entry.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_title_entry.gb --hardware cgb --run-frames 120 --png .\out\raster_title_entry.png
구현과 소스

kitaqgb/lib/raster.h:84

선언 주석 원문
Change the wave profile and restart its phase/divider counter.

kitaqgb/lib/raster.c:240

c
void Raster_LineXSetProfile(RasterLineX* effect, u8 profile)
{
    effect->profile = profile;
    effect->phase = 0;
    effect->frame_counter = 0;
}
Raster_LineXSetSpeed

위상 증가량과 갱신 간격을 설정합니다. 현재 위상은 유지하고 분주 카운터는 초기화합니다.

사용 형식

c
void Raster_LineXSetSpeed(RasterLineX* effect, u8 phase_step, u8 frame_divider);

매개변수

effect

초기화된 RasterLineX의 포인터이며, 호출이 끝날 때까지 유효해야 합니다.

phase_step

갱신당 위상 증가량 0..255입니다. 0은 파형을 정지시킵니다. 255는 8비트 순환으로 한 단계씩 뒤로 진행합니다.

frame_divider

위상 갱신 한 번당 실제 렌더링하는 RunFrame 호출 수 1..255입니다. 0은 1로 취급합니다. LCD가 꺼져 있어 바로 반환한 호출은 세지 않습니다.

반환값

반환값은 없습니다.

사용 조건과 제한

SCX는 8비트 값이며 배경은 256픽셀에서 순환합니다. 음수 변위는 256을 법으로 하는 바이트 값으로 표현합니다. 화면에 보이는 영역 바깥까지 맵을 채워 두세요.

이 효과는 배경의 수평 스크롤을 바꿉니다. 스프라이트와 윈도우는 휘어지지 않습니다. RunFrame은 가시 영역 144줄 전체에서 CPU를 점유하고 인터럽트를 차단합니다. 호출 사이에 게임 로직과 오디오를 갱신하고, STAT 래스터 인터럽트 드라이버와 함께 사용하지 마세요.

이미지는 KOKURA의 DMG 및 CGB 실행에서 얻었습니다. 기둥과 글자를 포함한 160×144 장면의 모든 픽셀을 예상되는 줄별 좌표와 비교합니다. 실기 타이밍은 시험하지 않았습니다.

kitaqgb, kokura, kitaq-docs를 같은 상위 폴더 아래에 놓고 그 상위 폴더에서 PowerShell을 여세요. ROM은 DMG와 CGB를 모두 지원합니다. KOKURA --hardware로 dmg 또는 cgb를 선택하세요.

사용 예

c
Raster_LineXSetSpeed(&wave, 1, 1);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

Raster_LineXSetSpeed: DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
DMG / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
Raster_LineXSetSpeed: CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.
CGB / 60프레임 — 기둥과 글자가 수평으로 최대 24픽셀 휘어집니다. 파형 하나는 64개 주사선에 걸치며 위상은 프레임마다 한 줄씩 진행합니다. CGB에서는 기둥과 글자가 파란색입니다. 화면 전체가 똑같이 움직이는 것이 아니라 각 줄의 수평 오프셋이 달라지는지 확인하세요.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_wave.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_wave.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
.\kokura\kokura-cli.exe .\out\raster_wave.gb --hardware cgb --run-frames 120 --png .\out\raster_wave.png
구현과 소스

kitaqgb/lib/raster.h:86

선언 주석 원문
Configure the phase increment and frame interval; clamp a zero interval to one.

kitaqgb/lib/raster.c:248

c
void Raster_LineXSetSpeed(RasterLineX* effect, u8 phase_step, u8 frame_divider)
{
    effect->phase_step = phase_step;
    if (frame_divider == 0) frame_divider = 1;
    effect->frame_divider = frame_divider;
    effect->frame_counter = 0;
}
Raster_Push

예약된 LY에서 배경 SCX/SCY를 바꾸는 밴드 하나를 추가합니다. 배경 전용 연산이므로 윈도우나 색은 바꾸지 않습니다.

사용 형식

c
u8 Raster_Push(u8 ly, u8 scx, u8 scy);

매개변수

ly

예약할 가시 영역 줄 번호 0..143입니다. 테이블의 이전 항목보다 반드시 커야 합니다. 첫 항목이 LY=0이면 VBlank 처리에서 적용해 프레임 시작 상태를 설정합니다.

scx

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

scy

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

사용 예

c
Raster_Push(0,0,0);Raster_Push(64,8,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

Raster_Push: DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
Raster_Push: CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:50

선언 주석 원문
Append a validated background-scroll band and advance the monotonic-LY
bookkeeping. A successful append clears the previous error.

kitaqgb/lib/raster.c:95

c
u8 Raster_Push(u8 ly, u8 scx, u8 scy)
{
    u8 r;

    r = Raster_CheckPush(ly);
    if (r != KQ_RASTER_OK) return r;

    Scroll_SplitPush(ly, scx, scy);

    Raster_LastLyValue = ly;
    Raster_HasLastLy = 1;
    Raster_CountValue++;
    Raster_LastErrorValue = KQ_RASTER_OK;
    return KQ_RASTER_OK;
}
Raster_PushBgColor0

프레임 도중 CGB 배경 팔레트 0의 색 0을 바꾸는 밴드를 추가합니다. 다른 팔레트를 선택하거나 나머지 세 색을 바꾸지 않습니다. DMG에서 등록해도 색 효과는 나오지 않습니다.

사용 형식

c
u8 Raster_PushBgColor0(u8 ly, u16 rgb15);

매개변수

ly

예약할 가시 영역 줄 번호 0..143입니다. 테이블의 이전 항목보다 반드시 커야 합니다. 첫 항목이 LY=0이면 VBlank 처리에서 적용해 프레임 시작 상태를 설정합니다.

rgb15

RGB15 형식으로 빨강은 비트 0..4, 초록은 5..9, 파랑은 10..14입니다. 0x001F는 빨강, 0x03E0은 초록, 0x7C00은 파랑입니다. 입력 범위는 검사하지 않습니다.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

색 갱신은 BCPS/BCPD를 사용하며 이전 BCPS 인덱스를 보존하지 않습니다. 메인 코드에서도 팔레트를 쓰면 인덱스를 명시적으로 설정하세요. 핸들러는 접근 가능한 LCD 모드를 기다리므로 실제 색 경계가 예약된 LY보다 뒤에 나타날 수 있습니다.

사용 예

c
Raster_PushBgColor0(0,0x7C00);Raster_PushBgColor0(64,0x001F);Raster_PushBgColor0(112,0x03E0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

확인한 CGB 일반 속도 캡처에서는 0..65행이 파랑, 66..113행이 빨강, 114..143행이 초록입니다. 예약된 LY는 0, 64, 112이며, 인터럽트와 팔레트 접근 지연이 실제 경계 위치에 영향을 줍니다. DMG용 컬러 버전은 없습니다.

Raster_PushBgColor0: CGB — 확인한 CGB 일반 속도 캡처에서는 0..65행이 파랑, 66..113행이 빨강, 114..143행이 초록입니다. 예약된 LY는 0, 64, 112이며, 인터럽트와 팔레트 접근 지연이 실제 경계 위치에 영향을 줍니다. DMG용 컬러 버전은 없습니다.
CGB — 확인한 CGB 일반 속도 캡처에서는 0..65행이 파랑, 66..113행이 빨강, 114..143행이 초록입니다. 예약된 LY는 0, 64, 112이며, 인터럽트와 팔레트 접근 지연이 실제 경계 위치에 영향을 줍니다. DMG용 컬러 버전은 없습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_color.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:63

선언 주석 원문
Pack a 15-bit color into the extended band's two scroll-byte fields and select
the color-zero operation, which interprets those fields as color data.

kitaqgb/lib/raster.c:154

c
u8 Raster_PushBgColor0(u8 ly, u16 rgb15)
{
    return Raster_PushEx(ly, (u8)rgb15, (u8)(rgb15 >> 8), 0, 0, KQ_RASTER_BG_COLOR0);
}
Raster_PushBgWindowScreen

밴드 하나에서 배경 스크롤과 윈도우 좌표를 갱신합니다. 래퍼가 BG와 WIN을 추가하고 윈도우 화면 X를 WX로 변환합니다.

사용 형식

c
u8 Raster_PushBgWindowScreen(u8 ly, u8 scx, u8 scy, u8 screen_x, u8 screen_y, u8 flags);

매개변수

ly

예약할 가시 영역 줄 번호 0..143입니다. 테이블의 이전 항목보다 반드시 커야 합니다. 첫 항목이 LY=0이면 VBlank 처리에서 적용해 프레임 시작 상태를 설정합니다.

scx

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

scy

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

screen_x

윈도우 왼쪽 가장자리의 화면 X 좌표입니다. 래퍼가 7을 더해 WX를 만듭니다. 보통 0..159를 사용하세요. 249 이상은 바이트 덧셈에서 순환하므로 윈도우를 숨기는 용도로 사용하지 마세요.

screen_y

위쪽 가장자리에서 픽셀 단위로 잰 윈도우 WY입니다. X와 달리 Y에는 7을 더하지 않습니다. WY가 144 이상이면 가시 영역 안에 시작 줄이 없습니다.

flags

보통 WIN_SHOW 또는 WIN_HIDE를 전달합니다. 래퍼가 WIN을 추가하므로 0을 전달하면 표시 상태를 바꾸지 않고 좌표만 갱신할 수 있습니다. 지원되는 다른 비트도 그대로 전달되므로 의도하지 않은 BG 또는 색 연산을 넣지 않도록 하세요.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

사용 예

c
Raster_PushBgWindowScreen(0,8,0,24,48,KQ_RASTER_WIN_SHOW);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

배경 X=8은 빨간색 배경 사각형을 (24,16)으로 옮깁니다. 윈도우 원점은 (24,48)을 유지하므로 파란색 사각형은 (32,56)에 남습니다. 두 좌표계가 독립적임을 보여 줍니다.

Raster_PushBgWindowScreen: DMG — 배경 X=8은 빨간색 배경 사각형을 (24,16)으로 옮깁니다. 윈도우 원점은 (24,48)을 유지하므로 파란색 사각형은 (32,56)에 남습니다. 두 좌표계가 독립적임을 보여 줍니다.
DMG — 배경 X=8은 빨간색 배경 사각형을 (24,16)으로 옮깁니다. 윈도우 원점은 (24,48)을 유지하므로 파란색 사각형은 (32,56)에 남습니다. 두 좌표계가 독립적임을 보여 줍니다.
Raster_PushBgWindowScreen: CGB — 배경 X=8은 빨간색 배경 사각형을 (24,16)으로 옮깁니다. 윈도우 원점은 (24,48)을 유지하므로 파란색 사각형은 (32,56)에 남습니다. 두 좌표계가 독립적임을 보여 줍니다.
CGB — 배경 X=8은 빨간색 배경 사각형을 (24,16)으로 옮깁니다. 윈도우 원점은 (24,48)을 유지하므로 파란색 사각형은 (32,56)에 남습니다. 두 좌표계가 독립적임을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bg_window.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:60

선언 주석 원문
Queue both background and window updates, converting window screen X to WX.

kitaqgb/lib/raster.c:145

c
u8 Raster_PushBgWindowScreen(u8 ly, u8 scx, u8 scy, u8 screen_x, u8 screen_y, u8 flags)
{
    flags = (u8)(flags | KQ_RASTER_BG | KQ_RASTER_WIN);
    return Raster_PushEx(ly, scx, scy, (u8)(screen_x + 7), screen_y, flags);
}
Raster_PushEx

플래그로 선택한 배경, 윈도우, 표시 여부, 색 연산을 수행하는 확장 밴드를 추가합니다. 배경만 바꾸려면 인수가 더 적은 Raster_Push를 사용하세요.

사용 형식

c
u8 Raster_PushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);

매개변수

ly

예약할 가시 영역 줄 번호 0..143입니다. 테이블의 이전 항목보다 반드시 커야 합니다. 첫 항목이 LY=0이면 VBlank 처리에서 적용해 프레임 시작 상태를 설정합니다.

scx

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

scy

배경 스크롤 바이트이며 범위는 0..255입니다. SCX/SCY는 화면상의 위치가 아니라 배경 맵을 읽기 시작할 위치입니다. 좌표는 256픽셀 배경 안에서 순환합니다.

wx

하드웨어 WX 원시 값입니다. 일반 화면 X 좌표에 7을 더하세요. WX=7이면 윈도우가 왼쪽 가장자리에 놓입니다. 이 함수는 WX를 제한하거나 검사하지 않습니다.

wy

위쪽 가장자리에서 픽셀 단위로 잰 윈도우 WY입니다. X와 달리 Y에는 7을 더하지 않습니다. WY가 144 이상이면 가시 영역 안에 시작 줄이 없습니다.

flags

플래그: BG=1은 배경 스크롤, WIN=2는 WX/WY를 갱신합니다. WIN_SHOW=4는 윈도우 표시, WIN_HIDE=8은 숨김, BG_COLOR0=16은 CGB 배경색 0 갱신입니다. 알 수 없는 상위 비트는 버립니다. SHOW와 HIDE가 함께 있으면 SHOW가 마지막에 적용됩니다. 색 갱신은 SCX/SCY 데이터 필드를 재사용하므로 일반 배경 스크롤과 함께 지정하지 마세요.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

사용 예

c
Raster_PushEx(104,16,0,7,0,KQ_RASTER_BG|KQ_RASTER_WIN_HIDE);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

Raster_PushEx: DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
DMG — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
Raster_PushEx: CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.
CGB — 각각 24x16픽셀인 빨간색 사각형(DMG에서는 검은색)이 (32,16), (24,80), (16,112)에 나타납니다. 아래쪽 밴드일수록 왼쪽으로 더 많이 이동합니다. 내부 결과에는 항목 수 3, 오류 0, 커밋 결과 0이 기록됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_bands.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:52

선언 주석 원문
Append a validated extended band after masking flags to supported operations.

kitaqgb/lib/raster.c:112

c
u8 Raster_PushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags)
{
    u8 r;

    r = Raster_CheckPush(ly);
    if (r != KQ_RASTER_OK) return r;

    // Masking removes unknown bits but does not reject conflicting supported operations.
    flags = (u8)(flags & KQ_RASTER_FLAG_MASK);
    Scroll_SplitPushEx(ly, scx, scy, wx, wy, flags);

    Raster_LastLyValue = ly;
    Raster_HasLastLy = 1;
    Raster_CountValue++;
    Raster_LastErrorValue = KQ_RASTER_OK;
    return KQ_RASTER_OK;
}
Raster_PushWindowRaw

하드웨어 원시 WX/WY로 윈도우 밴드를 추가합니다. WIN을 자동으로 추가하고 두 배경 데이터 바이트에는 0을 전달합니다.

사용 형식

c
u8 Raster_PushWindowRaw(u8 ly, u8 wx, u8 wy, u8 flags);

매개변수

ly

예약할 가시 영역 줄 번호 0..143입니다. 테이블의 이전 항목보다 반드시 커야 합니다. 첫 항목이 LY=0이면 VBlank 처리에서 적용해 프레임 시작 상태를 설정합니다.

wx

하드웨어 WX 원시 값입니다. 일반 화면 X 좌표에 7을 더하세요. WX=7이면 윈도우가 왼쪽 가장자리에 놓입니다. 이 함수는 WX를 제한하거나 검사하지 않습니다.

wy

위쪽 가장자리에서 픽셀 단위로 잰 윈도우 WY입니다. X와 달리 Y에는 7을 더하지 않습니다. WY가 144 이상이면 가시 영역 안에 시작 줄이 없습니다.

flags

보통 WIN_SHOW 또는 WIN_HIDE를 전달합니다. 래퍼가 WIN을 추가하므로 0을 전달하면 표시 상태를 바꾸지 않고 좌표만 갱신할 수 있습니다. 지원되는 다른 비트도 그대로 전달되므로 의도하지 않은 BG 또는 색 연산을 넣지 않도록 하세요.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

사용 예

c
Raster_PushWindowRaw(0,31,48,KQ_RASTER_WIN_SHOW);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

WX=31, WY=48이면 윈도우 원점은 화면 (24,48)입니다. 윈도우 내부 (8,8)의 파란색 16x16 사각형은 화면 (32,56)에 나타납니다. 위쪽 빨간색 배경 사각형은 (32,16)에 남습니다. DMG에서는 둘 다 검은색입니다.

Raster_PushWindowRaw: DMG — WX=31, WY=48이면 윈도우 원점은 화면 (24,48)입니다. 윈도우 내부 (8,8)의 파란색 16x16 사각형은 화면 (32,56)에 나타납니다. 위쪽 빨간색 배경 사각형은 (32,16)에 남습니다. DMG에서는 둘 다 검은색입니다.
DMG — WX=31, WY=48이면 윈도우 원점은 화면 (24,48)입니다. 윈도우 내부 (8,8)의 파란색 16x16 사각형은 화면 (32,56)에 나타납니다. 위쪽 빨간색 배경 사각형은 (32,16)에 남습니다. DMG에서는 둘 다 검은색입니다.
Raster_PushWindowRaw: CGB — WX=31, WY=48이면 윈도우 원점은 화면 (24,48)입니다. 윈도우 내부 (8,8)의 파란색 16x16 사각형은 화면 (32,56)에 나타납니다. 위쪽 빨간색 배경 사각형은 (32,16)에 남습니다. DMG에서는 둘 다 검은색입니다.
CGB — WX=31, WY=48이면 윈도우 원점은 화면 (24,48)입니다. 윈도우 내부 (8,8)의 파란색 16x16 사각형은 화면 (32,56)에 나타납니다. 위쪽 빨간색 배경 사각형은 (32,16)에 남습니다. DMG에서는 둘 다 검은색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_window_raw.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:55

선언 주석 원문
Enable window updates and pass hardware WX/WY values without coordinate conversion.

kitaqgb/lib/raster.c:131

c
u8 Raster_PushWindowRaw(u8 ly, u8 wx, u8 wy, u8 flags)
{
    flags = (u8)(flags | KQ_RASTER_WIN);
    return Raster_PushEx(ly, 0, 0, wx, wy, flags);
}
Raster_PushWindowScreen

화면 좌표로 윈도우 밴드를 추가합니다. 원시 값 함수를 호출하기 전에 X에 7을 더하므로 화면 X와 WX를 혼동하지 않고 윈도우를 배치할 수 있습니다.

사용 형식

c
u8 Raster_PushWindowScreen(u8 ly, u8 screen_x, u8 screen_y, u8 flags);

매개변수

ly

예약할 가시 영역 줄 번호 0..143입니다. 테이블의 이전 항목보다 반드시 커야 합니다. 첫 항목이 LY=0이면 VBlank 처리에서 적용해 프레임 시작 상태를 설정합니다.

screen_x

윈도우 왼쪽 가장자리의 화면 X 좌표입니다. 래퍼가 7을 더해 WX를 만듭니다. 보통 0..159를 사용하세요. 249 이상은 바이트 덧셈에서 순환하므로 윈도우를 숨기는 용도로 사용하지 마세요.

screen_y

위쪽 가장자리에서 픽셀 단위로 잰 윈도우 WY입니다. X와 달리 Y에는 7을 더하지 않습니다. WY가 144 이상이면 가시 영역 안에 시작 줄이 없습니다.

flags

보통 WIN_SHOW 또는 WIN_HIDE를 전달합니다. 래퍼가 WIN을 추가하므로 0을 전달하면 표시 상태를 바꾸지 않고 좌표만 갱신할 수 있습니다. 지원되는 다른 비트도 그대로 전달되므로 의도하지 않은 BG 또는 색 연산을 넣지 않도록 하세요.

반환값

성공하면 KQ_RASTER_OK(0), 오류이면 상태값 1..4를 반환합니다. 해당 함수의 제약과 Raster_GetLastError를 참조하세요.

사용 조건과 제한

raster.h를 포함하고 raster.c와 scroll.c를 컴파일하세요. 공유 테이블에는 최대 8개 밴드를 저장할 수 있습니다. Raster_*로 테이블을 구성하는 도중 Scroll_Split* 또는 __scroll_split_*를 직접 호출하지 마세요. 이 호출들은 래퍼의 항목 수와 마지막 줄 기록을 갱신하지 않습니다.

VBlank 또는 화면에 미치는 영향을 제어할 수 있는 구간에서 지우기, 항목 추가, 커밋 순으로 재구성하세요. 지우기는 실행 중인 화면 분할도 멈추므로 독립된 백 버퍼를 편집하는 방식이 아닙니다. LY에서 인터럽트가 예약되며 레지스터 쓰기에는 추가 시간이 걸립니다. 매 주사선의 물결 효과에는 별도의 Raster_LineX* 계열을 사용하고 두 드라이버를 함께 실행하지 마세요.

상태 코드는 0 OK, 1 FULL, 2 BAD_LY, 3 UNSORTED, 4 BAD_RANGE입니다. 추가 연산은 LY 범위, 용량, 정렬 순서대로 검사합니다. 거부된 항목은 테이블 크기를 늘리지 않습니다. 이후 추가가 성공하거나 테이블을 지우면 오류가 0으로 초기화되므로 각 호출의 반환값을 즉시 확인하세요.

사용 예

c
Raster_PushWindowScreen(0,24,48,KQ_RASTER_WIN_SHOW);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

화면 좌표 (24,48)을 직접 전달하면 원시 값 예제와 동일하게 파란색 윈도우 사각형이 (32,56)에 나타납니다. 라이브러리가 X에 7을 더합니다. 위쪽 빨간색 배경 사각형은 (32,16)에 있습니다.

Raster_PushWindowScreen: DMG — 화면 좌표 (24,48)을 직접 전달하면 원시 값 예제와 동일하게 파란색 윈도우 사각형이 (32,56)에 나타납니다. 라이브러리가 X에 7을 더합니다. 위쪽 빨간색 배경 사각형은 (32,16)에 있습니다.
DMG — 화면 좌표 (24,48)을 직접 전달하면 원시 값 예제와 동일하게 파란색 윈도우 사각형이 (32,56)에 나타납니다. 라이브러리가 X에 7을 더합니다. 위쪽 빨간색 배경 사각형은 (32,16)에 있습니다.
Raster_PushWindowScreen: CGB — 화면 좌표 (24,48)을 직접 전달하면 원시 값 예제와 동일하게 파란색 윈도우 사각형이 (32,56)에 나타납니다. 라이브러리가 X에 7을 더합니다. 위쪽 빨간색 배경 사각형은 (32,16)에 있습니다.
CGB — 화면 좌표 (24,48)을 직접 전달하면 원시 값 예제와 동일하게 파란색 윈도우 사각형이 (32,56)에 나타납니다. 라이브러리가 X에 7을 더합니다. 위쪽 빨간색 배경 사각형은 (32,16)에 있습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\raster_bands_window_screen.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\raster_bands.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/raster.h:58

선언 주석 원문
Convert screen X to hardware WX by adding seven, then queue a window band.
The byte addition wraps if callers supply an excessive X coordinate.

kitaqgb/lib/raster.c:139

c
u8 Raster_PushWindowScreen(u8 ly, u8 screen_x, u8 screen_y, u8 flags)
{
    return Raster_PushWindowRaw(ly, (u8)(screen_x + 7), screen_y, flags);
}

rpg.h — 난수, 문자, 맵, 저장, RPG·ADV·SLG 기능

절대 위치 텍스트 도우미는 배경 맵에 직접 그립니다. text_window는 테두리가 있는 영역을 열고, text_clear_rect는 영역을 채우며, text_print_xy는 제어 코드를 해석하지 않고 타일 바이트를 씁니다. text_print_u8, text_print_u16, text_print_s16은 필요한 칸만 사용해 숫자를 십진수로 변환합니다. 길이가 다른 값으로 바꿀 때는 전체 필드를 확보하고 지우세요.

rpg.h에 선언된 RNG 함수는 lib/rng.c에 구현되어 있습니다. 컴파일러의 GB 생성기를 공유합니다. rng_seed는 초기화, rng8/rng_next8은 1바이트, rng16/rng_next16은 2바이트를 소비하고, rand_range/rng_range, rng_chance, weighted_choice는 게임 선택에 맞게 추출을 가공합니다. 이 라이브러리 함수를 호출하면 rng.c를 함께 컴파일하세요. 재현 가능한 테스트에는 시드와 호출 순서를 고정하세요. 나머지 연산 기반 선택은 정확한 확률을 보장하지 않습니다.

RLE는 count/value 바이트 쌍과 count=0 종료자를 사용합니다. rle_decode는 일반 포인터에서 RAM으로, rle_decode_far는 ROM 뱅크 지정 포인터에서 RAM으로 풉니다. __rle_decode_vram은 뱅크 입력을 LCD 접근 시점을 고려해 VRAM으로 직접 풉니다. RAM 함수는 lib/rle.c에 있고 직접 VRAM 연산은 컴파일러가 생성합니다. 세 가지 모두 출력 바이트 수를 반환하며, 유효한 스트림과 충분한 대상 공간이 필요합니다.

rpg.h에 선언된 게임 상태 저장 기능은 lib/flags.c가 구현합니다. 플래그 함수 3개는 서로 독립적인 불리언 비트 2048개를 다루며, quest_state와 quest_set_state는 게임이 정의한 단계용 바이트 64개를 다룹니다. 사용할 때 flags.c를 컴파일하고 ID 범위를 지키세요. 전원을 꺼도 진행 상황을 유지해야 한다면 별도의 세이브 시스템을 사용해야 합니다.

창 안 대화는 활성 사각형, 커서, 문자 속도 설정을 하나씩 공유합니다. text_open은 영역 초기화, text_close는 지우기, text_set_speed는 문자별 VBlank 대기를 설정합니다. text_print/text_print_far는 제어 스트림을 해석하고 text_choice는 블로킹 세로 선택기를 실행합니다. 타일을 로드하고 영역 크기를 맞춘 뒤 게임에서 이 블로킹 호출을 어떻게 처리할지 정하세요.

맵·메타타일 그리기, 스크립트, SRAM 저장, 경로 탐색을 제공합니다. 일반 셀은 8×8픽셀, 메타타일은 16×16입니다. 로드·그리기, 이동 마스크, 공격 마스크는 별도 작업이며, 그래픽 로드와 이벤트 실행 순서는 게임이 관리합니다.

탐색에는 약 4KiB의 공유 작업 공간을 사용하며 재진입할 수 없습니다. 맵은 1024셀, 탐색 거리는 254 이하로 제한하세요. 거리 0xFF는 미도달을 뜻하므로 255단계 경로는 표현할 수 없습니다. 비용·마스크 출력에는 width*height바이트의 쓰기 가능한 공간이 필요합니다.

기본 구성은 512바이트 슬롯 4개이며, 각 슬롯은 6바이트 헤더와 최대 506바이트 데이터를 담습니다. 샘플은 8KiB SRAM이 있는 MBC5를 사용합니다. 호출이 끝나면 RAM을 비활성화하며, 이전 뱅크나 활성 상태로 복원하지 않습니다.

메뉴는 선택이 끝날 때까지 기다리는 방식과 게임 루프에서 입력·그리기를 따로 호출하는 방식을 모두 지원합니다. 소지품 메뉴에는 항목 이름과 수량이 표시됩니다.

camera_center

일반 맵의 셀을 20×18타일 뷰포트의 중앙에 배치하되 맵 경계를 넘지 않도록 제한합니다.

사용 형식

c
void camera_center(u8 x, u8 y);

매개변수

x

셀의 X 좌표입니다.

y

셀의 Y 좌표입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

원점은 max(x−10,0), max(y−9,0)에서 시작하여 맵 경계 안으로 제한한 뒤, 원점*8의 하위 바이트를 SCX/SCY에 씁니다. 메타타일 모드에서는 적용하지 않습니다. 새 행이나 열을 VRAM으로 스트리밍하지 않습니다.

사용 예

c
camera_center(5,4);result[9]=*((u8*)0xFF43);result[10]=*((u8*)0xFF42);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

camera_center: DMG
DMG
camera_center: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:297

선언 주석 원문
Center an ordinary-map tile coordinate within a 20-by-18 viewport and clamp
the scroll origin to its edges. This adjusts scroll registers only; it does
not stream newly exposed map rows into VRAM.

kitaqgb/lib/map.c:105

c
void camera_center(u8 x, u8 y)
{
    u8 tile_x = 0;
    u8 tile_y = 0;
    u8 max_x = 0;
    u8 max_y = 0;

    map_camera_x = x;
    map_camera_y = y;

    if (map_loaded == 0) return;

    if (map_current.width > 20) max_x = (u8)(map_current.width - 20);
    if (map_current.height > 18) max_y = (u8)(map_current.height - 18);

    if (x > 10) tile_x = (u8)(x - 10);
    if (y > 9) tile_y = (u8)(y - 9);

    if (tile_x > max_x) tile_x = max_x;
    if (tile_y > max_y) tile_y = max_y;

    __scroll_bg_set((u8)(tile_x << 3), (u8)(tile_y << 3));
}
far_read16

뱅크 정보가 있는 포인터로 리틀 엔디언 워드를 읽습니다.

사용 형식

c
#define far_read16(p) __farpeek16((p).bank, (p).ptr)

매개변수

p

bank와 ptr을 포함하는 far_ptr_t입니다. ptr은 CPU에서 보이는 주소입니다.

반환값

u16 형식의 워드입니다.

사용 조건과 제한

매크로는 p.bank와 p.ptr을 따로 읽으므로 부작용이 있는 표현식을 전달하지 마세요. 내장 함수는 ROM 뱅크를 임시 선택한 뒤 복원합니다. 인터럽트에서 동시에 뱅크를 바꾸지 마세요.

사용 예

c
result[1]=far_read16(far);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

다른 ROM 뱅크에서 16진수 34 12 AB를 읽습니다. 첫 바이트는 52, 리틀 엔디언 워드는 4660, 복사된 마지막 바이트는 171입니다.

far_read16: DMG
DMG
far_read16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_far.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_far.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:172

far_read8

뱅크 정보가 있는 포인터로 1바이트를 읽습니다.

사용 형식

c
#define far_read8(p) __farpeek8((p).bank, (p).ptr)

매개변수

p

bank와 ptr을 포함하는 far_ptr_t입니다. ptr은 CPU에서 보이는 주소입니다.

반환값

u8 형식의 바이트입니다.

사용 조건과 제한

매크로는 p.bank와 p.ptr을 따로 읽으므로 부작용이 있는 표현식을 전달하지 마세요. 내장 함수는 ROM 뱅크를 임시 선택한 뒤 복원합니다. 인터럽트에서 동시에 뱅크를 바꾸지 마세요.

사용 예

c
far.bank=1;far.ptr=bank_bytes;result[0]=far_read8(far);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

다른 ROM 뱅크에서 16진수 34 12 AB를 읽습니다. 첫 바이트는 52, 리틀 엔디언 워드는 4660, 복사된 마지막 바이트는 171입니다.

far_read8: DMG
DMG
far_read8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_far.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_far.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:171

far_read_block

뱅크 정보가 있는 포인터에서 연속된 바이트를 RAM으로 복사합니다.

사용 형식

c
#define far_read_block(dst, p, len) __farmemcpy((dst), (p).bank, (p).ptr, (len))

매개변수

dst

쓰기 가능한 len바이트 RAM 영역의 시작입니다.

p

bank와 ptr을 포함하는 far_ptr_t입니다. ptr은 CPU에서 보이는 주소입니다.

len

바이트 수입니다. 원본 범위가 해당 뱅크를 벗어나지 않도록 하세요.

반환값

반환값은 없습니다.

사용 조건과 제한

__farmemcpy로 전달하는 매크로입니다. ROM 뱅크 경계를 자동으로 넘지 않으며, 겹치는 메모리 영역을 이동하는 기능은 아닙니다.

사용 예

c
far_read_block(copy,far,3);result[2]=copy[2];

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

다른 ROM 뱅크에서 16진수 34 12 AB를 읽습니다. 첫 바이트는 52, 리틀 엔디언 워드는 4660, 복사된 마지막 바이트는 171입니다.

far_read_block: DMG
DMG
far_read_block: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_far.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_far.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:173

flag_clear

이웃 플래그를 지우지 않고 게임 플래그 하나를 0으로 지웁니다. 이벤트 조건이 취소되었거나 플래그를 명시적으로 초기화할 때 사용하세요. 이미 0인 플래그는 0으로 유지됩니다.

사용 형식

c
void flag_clear(u16 id);

매개변수

id

플래그 번호 0~2047이며 u16으로 전달합니다. 바이트 오프셋은 id / 8, 해당 바이트의 비트는 최하위 비트부터 세는 id % 8입니다. 매개변수 자료형이 더 넓어도 고정된 2048개 플래그 저장 공간이 늘어나지는 않습니다.

반환값

없음(void).

사용 조건과 제한

함수는 ID를 검사하지 않습니다. 플래그 ID는 2048 미만, 퀘스트 ID는 64 미만으로 유지하세요. 범위를 벗어나면 관련 없는 RAM을 읽거나 덮어쓸 수 있습니다. 예제는 시작 시 메모리 내용에 의존하지 않고 명시적으로 초기화합니다.

flags.c는 RAM에 플래그용 256바이트와 별도의 퀘스트용 64바이트를 갖습니다. 이 함수들은 카트리지 세이브 RAM에 접근하지 않으며 전원이 꺼진 뒤에는 유지되지 않습니다. 진행 상황을 영구 저장하려면 게임이 플래그와 퀘스트 값을 세이브 시스템을 통해 직렬화하고 로드 시 복원해야 합니다.

rpg.h를 포함하고 lib/flags.c를 게임과 함께 컴파일하세요. 배열은 그 소스 파일 내부 전용이므로 플래그·퀘스트 API로 접근하세요. 모든 호출자가 저장 공간을 공유하므로 메인 루프와 인터럽트 핸들러의 쓰기 순서는 직접 조정해야 합니다.

사용 예

c
flag_clear(9);flag_clear(9); // Mark it closed; clearing twice still leaves 0.
cleared=flag_get(9);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 문 플래그 9를 설정한 뒤 지웁니다. 해제를 두 번 호출해도 DOOR CLOSED는 000입니다. 앞서 관측한 DOOR OPEN 값 001도 화면에 남아 두 시점의 관측값을 비교할 수 있습니다.

완전한 프로그램은 흰 배경에 10진수 결과를 표시합니다. DMG에서는 검은 글자, CGB에서는 파란 글자입니다. FAILED는 000이어야 합니다. 캡처 화면은 RAM 상태 동작만 보여 주며 게임 저장을 입증하지는 않습니다.

DMG 에뮬레이터 검증에서는 플래그 ID 0~2047 전체, 반복 설정·해제, 이웃 항목, 퀘스트 64개 각각의 모든 상태값 256개를 확인했습니다. 마지막의 256바이트 플래그 패턴과 퀘스트 64바이트를 예상 데이터와 비교했습니다. 두 학습 화면은 240프레임 후 확인했습니다. 실기와 저장 데이터의 영속성은 검증하지 않았습니다.

flag_clear: DMG
DMG
flag_clear: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:372

선언 주석 원문
Clear a flag bit; id must be below 2048.

kitaqgb/lib/flags.c:21

c
void flag_clear(u16 id)
{
    __bit_clear(flags_bits, id);
}
flag_get

라이브러리의 RAM 비트 배열에서 켜짐·꺼짐 게임 플래그 하나를 읽습니다. 문이 열려 있는지, 아이템을 획득했는지, 게임에서 정한 이벤트가 발생했는지 확인할 때 사용하세요. 읽기는 플래그를 바꾸지 않습니다.

사용 형식

c
u8 flag_get(u16 id);

매개변수

id

플래그 번호 0~2047이며 u16으로 전달합니다. 바이트 오프셋은 id / 8, 해당 바이트의 비트는 최하위 비트부터 세는 id % 8입니다. 매개변수 자료형이 더 넓어도 고정된 2048개 플래그 저장 공간이 늘어나지는 않습니다.

반환값

정규화된 u8 불리언으로, 플래그가 꺼져 있으면 0, 켜져 있으면 1입니다. 이 GB 라이브러리는 결과를 정규화하는 GB 내장 함수 __bit_test를 호출합니다.

사용 조건과 제한

함수는 ID를 검사하지 않습니다. 플래그 ID는 2048 미만, 퀘스트 ID는 64 미만으로 유지하세요. 범위를 벗어나면 관련 없는 RAM을 읽거나 덮어쓸 수 있습니다. 예제는 시작 시 메모리 내용에 의존하지 않고 명시적으로 초기화합니다.

flags.c는 RAM에 플래그용 256바이트와 별도의 퀘스트용 64바이트를 갖습니다. 이 함수들은 카트리지 세이브 RAM에 접근하지 않으며 전원이 꺼진 뒤에는 유지되지 않습니다. 진행 상황을 영구 저장하려면 게임이 플래그와 퀘스트 값을 세이브 시스템을 통해 직렬화하고 로드 시 복원해야 합니다.

rpg.h를 포함하고 lib/flags.c를 게임과 함께 컴파일하세요. 배열은 그 소스 파일 내부 전용이므로 플래그·퀘스트 API로 접근하세요. 모든 호출자가 저장 공간을 공유하므로 메인 루프와 인터럽트 핸들러의 쓰기 순서는 직접 조정해야 합니다.

사용 예

c
before=flag_get(9); // Door-open flag: 0 after explicit initialization.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 플래그 9를 문에 할당합니다. 명시적으로 지운 뒤 BEFORE는 000입니다. 이후 설정과 해제 시 DOOR OPEN 001과 DOOR CLOSED 000이 표시되어 저장된 조건을 읽는다는 것을 보여 줍니다.

완전한 프로그램은 흰 배경에 10진수 결과를 표시합니다. DMG에서는 검은 글자, CGB에서는 파란 글자입니다. FAILED는 000이어야 합니다. 캡처 화면은 RAM 상태 동작만 보여 주며 게임 저장을 입증하지는 않습니다.

DMG 에뮬레이터 검증에서는 플래그 ID 0~2047 전체, 반복 설정·해제, 이웃 항목, 퀘스트 64개 각각의 모든 상태값 256개를 확인했습니다. 마지막의 256바이트 플래그 패턴과 퀘스트 64바이트를 예상 데이터와 비교했습니다. 두 학습 화면은 240프레임 후 확인했습니다. 실기와 저장 데이터의 영속성은 검증하지 않았습니다.

flag_get: DMG
DMG
flag_get: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:368

선언 주석 원문
Read a bit from the flag array. Callers must keep id below 2048.

kitaqgb/lib/flags.c:9

c
u8 flag_get(u16 id)
{
    return __bit_test(flags_bits, id);
}
flag_set

같은 바이트의 다른 7개 플래그를 유지하면서 게임 플래그 하나를 1로 설정합니다. 이미 설정된 플래그는 계속 1로 남습니다. 문 열기 같은 일회성 이벤트를 기록할 때 사용하세요.

사용 형식

c
void flag_set(u16 id);

매개변수

id

플래그 번호 0~2047이며 u16으로 전달합니다. 바이트 오프셋은 id / 8, 해당 바이트의 비트는 최하위 비트부터 세는 id % 8입니다. 매개변수 자료형이 더 넓어도 고정된 2048개 플래그 저장 공간이 늘어나지는 않습니다.

반환값

없음(void).

사용 조건과 제한

함수는 ID를 검사하지 않습니다. 플래그 ID는 2048 미만, 퀘스트 ID는 64 미만으로 유지하세요. 범위를 벗어나면 관련 없는 RAM을 읽거나 덮어쓸 수 있습니다. 예제는 시작 시 메모리 내용에 의존하지 않고 명시적으로 초기화합니다.

flags.c는 RAM에 플래그용 256바이트와 별도의 퀘스트용 64바이트를 갖습니다. 이 함수들은 카트리지 세이브 RAM에 접근하지 않으며 전원이 꺼진 뒤에는 유지되지 않습니다. 진행 상황을 영구 저장하려면 게임이 플래그와 퀘스트 값을 세이브 시스템을 통해 직렬화하고 로드 시 복원해야 합니다.

rpg.h를 포함하고 lib/flags.c를 게임과 함께 컴파일하세요. 배열은 그 소스 파일 내부 전용이므로 플래그·퀘스트 API로 접근하세요. 모든 호출자가 저장 공간을 공유하므로 메인 루프와 인터럽트 핸들러의 쓰기 순서는 직접 조정해야 합니다.

사용 예

c
flag_set(9); // Mark the door as open; setting an already set flag is harmless.
flag_set(9);
opened=flag_get(9);neighbor=flag_get(8); // 1 and 0: adjacent flag is unchanged.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 문 플래그 9를 두 번 설정합니다. DOOR OPEN은 001이고 이웃 플래그 8은 NEIGHBOR 000으로 유지됩니다. 두 플래그는 같은 바이트에 있으므로 이웃 값이 유지되는 것을 통해 한 플래그의 설정이 다른 플래그를 보존함을 확인할 수 있습니다.

완전한 프로그램은 흰 배경에 10진수 결과를 표시합니다. DMG에서는 검은 글자, CGB에서는 파란 글자입니다. FAILED는 000이어야 합니다. 캡처 화면은 RAM 상태 동작만 보여 주며 게임 저장을 입증하지는 않습니다.

DMG 에뮬레이터 검증에서는 플래그 ID 0~2047 전체, 반복 설정·해제, 이웃 항목, 퀘스트 64개 각각의 모든 상태값 256개를 확인했습니다. 마지막의 256바이트 플래그 패턴과 퀘스트 64바이트를 예상 데이터와 비교했습니다. 두 학습 화면은 240프레임 후 확인했습니다. 실기와 저장 데이터의 영속성은 검증하지 않았습니다.

flag_set: DMG
DMG
flag_set: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:370

선언 주석 원문
Set a flag bit without disturbing adjacent flags; id must be below 2048.

kitaqgb/lib/flags.c:15

c
void flag_set(u16 id)
{
    __bit_set(flags_bits, id);
}
map_current_height

활성 맵의 높이를 읽습니다.

사용 형식

c
u8 map_current_height();

반환값

셀 단위의 높이를 반환합니다. 로드된 맵이 없으면 0입니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

사용 예

c
result[1]=map_current_height();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

map_current_height: DMG
DMG
map_current_height: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:391

선언 주석 원문
Return the active map height in its own cell units, or zero when no map is loaded.

kitaqgb/lib/map.c:25

c
u8 map_current_height()
{
    if (map_meta_loaded != 0) return map_meta_current.height;
    if (map_loaded == 0) return 0;
    return map_current.height;
}
map_current_width

활성 맵의 너비를 읽습니다.

사용 형식

c
u8 map_current_width();

반환값

셀 단위의 너비를 반환합니다. 로드된 맵이 없으면 0입니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

사용 예

c
result[0]=map_current_width();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

map_current_width: DMG
DMG
map_current_width: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:389

선언 주석 원문
Return the active map width in its own cell units, or zero when no map is loaded.

kitaqgb/lib/map.c:17

c
u8 map_current_width()
{
    if (map_meta_loaded != 0) return map_meta_current.width;
    if (map_loaded == 0) return 0;
    return map_current.width;
}
map_draw_visible

지정한 원점에서 10×9메타타일을 그리고, 변경 후 다시 그릴 때 사용할 카메라 위치를 저장합니다.

사용 형식

c
void map_draw_visible(u8 camera_tx, u8 camera_ty);

매개변수

camera_tx

가장 왼쪽 셀의 X입니다. 순회 중 바이트 래핑을 피하려면 246 이하로 유지하세요.

camera_ty

맨 위 셀의 Y입니다. 247 이하로 유지하세요.

반환값

반환값은 없습니다.

사용 조건과 제한

맵 밖의 셀은 메타타일 ID 0으로 그리므로 항상 정의 0을 제공하세요. 이 호출은 20×18타일 뷰포트 밖의 셀과 CGB 속성을 변경하지 않습니다.

사용 예

c
map_draw_visible(1,0);result[9]=*((u8*)0x9800);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM의 메타타일 ID를 바꾸고 변경 표시 후 반영합니다. 카메라 (1,0)에서 왼쪽 위에 초록 16×16 정사각형이 보입니다. 샘플은 팔레트 메타데이터를 CGB 속성에 명시적으로 적용합니다. DMG에서는 검은 정사각형입니다.

map_draw_visible: DMG
DMG
map_draw_visible: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:304

선언 주석 원문
Draw a 10-by-9 metatile viewport as 20-by-18 individual background tiles.
Out-of-range cells use definition zero; palette attributes are not written.
Remember the camera and clear the dirty flag after the full redraw.

kitaqgb/lib/map.c:212

c
void map_draw_visible(u8 camera_tx, u8 camera_ty)
{
    u8 my;

    if (map_meta_loaded == 0) return;

    map_camera_x = camera_tx;
    map_camera_y = camera_ty;

    my = 0;
    while (my < 9) {
        u8 mx = 0;
        while (mx < 10) {
            u8 tx = (u8)(camera_tx + mx);
            u8 ty = (u8)(camera_ty + my);
            u8 sx = (u8)(mx << 1);
            u8 sy = (u8)(my << 1);
            metatile_t meta;
            u8 id = map_get_metatile(tx, ty);
            map_read_metatile(id, &meta);
            __settile_xy(sx, sy, meta.tile_tl);
            __settile_xy((u8)(sx + 1), sy, meta.tile_tr);
            __settile_xy(sx, (u8)(sy + 1), meta.tile_bl);
            __settile_xy((u8)(sx + 1), (u8)(sy + 1), meta.tile_br);
            mx++;
        }
        my++;
    }
    map_dirty = 0;
}
map_flush_dirty

변경 표시가 있으면 저장된 카메라 원점에서 뷰포트를 다시 그리고 변경 플래그를 지웁니다.

사용 형식

c
void map_flush_dirty();

반환값

반환값은 없습니다.

사용 조건과 제한

변경 표시가 없으면 아무 동작도 하지 않습니다. 다시 그릴 때는 변경된 셀만이 아니라 10×9메타타일 전체를 그립니다.

사용 예

c
map_flush_dirty();result[11]=*((u8*)0x9800);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM의 메타타일 ID를 바꾸고 변경 표시 후 반영합니다. 카메라 (1,0)에서 왼쪽 위에 초록 16×16 정사각형이 보입니다. 샘플은 팔레트 메타데이터를 CGB 속성에 명시적으로 적용합니다. DMG에서는 검은 정사각형입니다.

map_flush_dirty: DMG
DMG
map_flush_dirty: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:321

선언 주석 원문
Redraw the remembered metatile viewport only when the shared dirty flag is set.

kitaqgb/lib/map.c:254

c
void map_flush_dirty()
{
    if (map_dirty == 0) return;
    map_draw_visible(map_camera_x, map_camera_y);
}
map_get_attr

셀의 메타타일 정의에서 팔레트 메타데이터를 읽습니다.

사용 형식

c
u8 map_get_attr(u8 tx, u8 ty);

매개변수

tx

메타타일 X 좌표입니다.

ty

메타타일 Y 좌표입니다.

반환값

팔레트 바이트를 반환합니다. 맵 밖의 셀은 정의 0을 사용하며, 메타타일 모드가 아니면 0을 반환합니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

사용 예

c
result[3]=map_get_attr(0,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM의 메타타일 ID를 바꾸고 변경 표시 후 반영합니다. 카메라 (1,0)에서 왼쪽 위에 초록 16×16 정사각형이 보입니다. 샘플은 팔레트 메타데이터를 CGB 속성에 명시적으로 적용합니다. DMG에서는 검은 정사각형입니다.

map_get_attr: DMG
DMG
map_get_attr: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:310

선언 주석 원문
Return the selected definition's palette byte. An out-of-range coordinate
uses the metatile-zero fallback; this function does not write CGB attributes.

kitaqgb/lib/map.c:172

c
u8 map_get_attr(u8 tx, u8 ty)
{
    metatile_t meta;
    u8 id;
    if (map_meta_loaded == 0) return 0;
    id = map_get_metatile(tx, ty);
    map_read_metatile(id, &meta);
    return meta.palette;
}
map_get_event

메타타일 이벤트 ID를 읽습니다. 일반 맵에서는 이벤트 존재 여부를 반환합니다.

사용 형식

c
u8 map_get_event(u8 tx, u8 ty);

매개변수

tx

메타타일 X 좌표입니다.

ty

메타타일 Y 좌표입니다.

반환값

메타타일의 이벤트 바이트 또는 일반 맵의 불리언 값을 반환합니다. 맵이 없거나 밖의 셀이면 0입니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

사용 예

c
result[7]=map_get_event(0,0);result[8]=map_get_event(3,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM의 메타타일 ID를 바꾸고 변경 표시 후 반영합니다. 카메라 (1,0)에서 왼쪽 위에 초록 16×16 정사각형이 보입니다. 샘플은 팔레트 메타데이터를 CGB 속성에 명시적으로 적용합니다. DMG에서는 검은 정사각형입니다.

map_get_event: DMG
DMG
map_get_event: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:316

선언 주석 원문
Return a metatile event ID, or the ordinary-map Boolean trigger result.
Missing/out-of-range metatile cells have no event.

kitaqgb/lib/map.c:197

c
u8 map_get_event(u8 tx, u8 ty)
{
    metatile_t meta;
    u8 id;
    if (map_meta_loaded == 0) return map_trigger_at(tx, ty);
    if (tx >= map_meta_current.width || ty >= map_meta_current.height) return 0;
    id = map_get_metatile(tx, ty);
    map_read_metatile(id, &meta);
    return meta.event;
}
map_get_metatile

셀의 메타타일 ID를 읽습니다.

사용 형식

c
u8 map_get_metatile(u8 tx, u8 ty);

매개변수

tx

메타타일 X 좌표입니다.

ty

메타타일 Y 좌표입니다.

반환값

ID를 반환합니다. 맵 밖이거나 메타타일 모드가 아니면 0입니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

사용 예

c
result[1]=map_get_metatile(0,0);result[2]=map_get_metatile(3,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM의 메타타일 ID를 바꾸고 변경 표시 후 반영합니다. 카메라 (1,0)에서 왼쪽 위에 초록 16×16 정사각형이 보입니다. 샘플은 팔레트 메타데이터를 CGB 속성에 명시적으로 적용합니다. DMG에서는 검은 정사각형입니다.

map_get_metatile: DMG
DMG
map_get_metatile: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:307

선언 주석 원문
Read a row-major metatile ID, returning ID zero for inactive or out-of-range
lookups. Callers must provide a usable definition for metatile zero.

kitaqgb/lib/map.c:159

c
u8 map_get_metatile(u8 tx, u8 ty)
{
    u16 index;

    if (map_meta_loaded == 0) return 0;
    if (tx >= map_meta_current.width || ty >= map_meta_current.height) return 0;

    index = __map_index(tx, ty, map_meta_current.width);
    return __farpeek8(map_meta_data_bank(), map_meta_current.metatile_ids + index);
}
map_is_blocked

이동할 셀이 통과를 막는지 검사합니다. 메타타일 모드에서는 정의의 collision 필드를 사용합니다.

사용 형식

c
u8 map_is_blocked(u8 x, u8 y);

매개변수

x

셀의 X 좌표입니다.

y

셀의 Y 좌표입니다.

반환값

벽, 맵 밖 좌표, 맵 없음이면 1, 통과 가능한 셀이면 0을 반환합니다. 일반 맵의 충돌 배열이 NULL이면 맵 안의 모든 셀을 통과할 수 있습니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

사용 예

c
result[4]=map_is_blocked(2,2);result[5]=map_is_blocked(6,2);result[6]=map_is_blocked(1,2);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

map_is_blocked: DMG
DMG
map_is_blocked: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:290

선언 주석 원문
Use metatile collision when that mode is active; otherwise read one packed
collision bit. Missing maps/out-of-range cells block movement, but a valid
ordinary map without a collision array is entirely passable.

kitaqgb/lib/map.c:68

c
u8 map_is_blocked(u8 x, u8 y)
{
    u16 index;
    u8 value;

    if (map_meta_loaded != 0) return map_is_solid(x, y);
    if (map_loaded == 0) return 1;
    if (x >= map_current.width || y >= map_current.height) return 1;
    if (map_current.collision_bits == 0) return 0;

    index = __map_index(x, y, map_current.width);
    // Collision uses least-significant bit first within each row-major group of eight cells.
    value = __farpeek8(map_bank, map_current.collision_bits + (index >> 3));
    if ((value & (u8)(1 << (index & 7))) != 0) return 1;
    return 0;
}
map_is_solid

고체 여부를 검사합니다. 일반 맵 모드에서는 충돌 비트에 위임합니다.

사용 형식

c
u8 map_is_solid(u8 tx, u8 ty);

매개변수

tx

메타타일 X 좌표입니다.

ty

메타타일 Y 좌표입니다.

반환값

collision이 0이 아니거나 맵 밖의 셀이면 1, 아니면 0을 반환합니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

사용 예

c
result[4]=map_is_solid(0,0);result[5]=map_is_solid(1,0);result[6]=map_is_solid(3,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM의 메타타일 ID를 바꾸고 변경 표시 후 반영합니다. 카메라 (1,0)에서 왼쪽 위에 초록 16×16 정사각형이 보입니다. 샘플은 팔레트 메타데이터를 CGB 속성에 명시적으로 적용합니다. DMG에서는 검은 정사각형입니다.

map_is_solid: DMG
DMG
map_is_solid: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:313

선언 주석 원문
Treat out-of-range metatile cells as solid; otherwise inspect the definition
collision flag. In ordinary-map mode, delegate to its packed collision bits.

kitaqgb/lib/map.c:184

c
u8 map_is_solid(u8 tx, u8 ty)
{
    metatile_t meta;
    u8 id;
    if (map_meta_loaded == 0) return map_is_blocked(tx, ty);
    if (tx >= map_meta_current.width || ty >= map_meta_current.height) return 1;
    id = map_get_metatile(tx, ty);
    map_read_metatile(id, &meta);
    return (u8)(meta.collision != 0);
}
map_load

일반 맵 설명자를 로드하고 왼쪽 위에서 최대 20×18타일을 선택한 배경 맵에 그립니다.

사용 형식

c
void map_load(u8 bank, const map_t* map);

매개변수

bank

설명자, 충돌 비트, 이벤트가 있는 ROM 뱅크입니다.

map

패딩 없이 9바이트로 배치된 map_t입니다. tiles에는 width*height개의 타일 ID가 있고, collision_bits는 셀을 최하위 비트부터 채우며, events는 셀마다 1바이트를 저장합니다. 타일 읽기에는 bank_tiles를 사용합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

활성 맵 하나를 공유합니다. 설명자 자체는 복사하지만, 그 배열들은 필요한 동안 계속 읽을 수 있어야 합니다. 타일 그래픽은 VRAM에 별도로 로드하세요.

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

작은 맵의 바깥쪽 셀은 지우지 않습니다. 일반 맵에서 bank_tiles=0은 뱅크 0을 뜻하며, 설명자의 뱅크를 상속하지 않습니다.

사용 예

c
map_load(0,maps);result[2]=map_current_width();result[3]=map_current_height();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

map_load: DMG
DMG
map_load: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:286

선언 주석 원문
Load the nine-byte ordinary-map descriptor and draw up to 20 by 18 tiles
from its top-left corner. Drawing does not upload tile graphics or clear
background cells beyond smaller map dimensions.

kitaqgb/lib/map.c:35

c
void map_load(u8 bank, const map_t* map)
{
    u8 row;
    u8 h;
    u8 w;

    // The literal copy size depends on the packed map_t layout; changing that layout requires updating this copy.
    __farmemcpy(&map_current, bank, map, 9);
    map_bank = bank;
    map_loaded = 1;
    map_meta_loaded = 0;

    w = map_current.width;
    h = map_current.height;
    if (w > 20) w = 20;
    if (h > 18) h = 18;

    row = 0;
    while (row < h) {
        u8 x = 0;
        u16 base_index = __map_index(0, row, map_current.width);
        while (x < w) {
            map_row[x] = __farpeek8(map_current.bank_tiles, map_current.tiles + base_index + x);
            x++;
        }
        __settile_row(0, row, map_row, w);
        row++;
    }
}
map_load_metatile

메타타일 맵을 선택하고 카메라 (0,0)의 10×9셀 뷰포트를 20×18타일로 펼칩니다.

사용 형식

c
void map_load_metatile(u8 bank, const metatile_map_t* map);

매개변수

bank

설명자가 들어 있는 ROM 뱅크입니다.

map

metatile_map_t 포인터입니다. 크기는 16×16셀 단위이며, ID 배열과 7바이트 metatile_t 정의 테이블을 참조합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

활성 맵 하나를 공유합니다. 설명자 자체는 복사하지만, 그 배열들은 필요한 동안 계속 읽을 수 있어야 합니다. 타일 그래픽은 VRAM에 별도로 로드하세요.

bank_tiles=0이면 설명자의 뱅크를 상속합니다. 0이 아니면 ID와 정의 모두에 그 뱅크를 사용합니다. 정의에는 왼쪽 위·오른쪽 위·왼쪽 아래·오른쪽 아래 타일, 충돌, 팔레트, 이벤트가 저장됩니다. 그릴 때 팔레트 메타데이터가 자동 적용되지는 않습니다.

사용 예

c
map_load_metatile(0,&level);result[0]=*((u8*)0x9800);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM의 메타타일 ID를 바꾸고 변경 표시 후 반영합니다. 카메라 (1,0)에서 왼쪽 위에 초록 16×16 정사각형이 보입니다. 샘플은 팔레트 메타데이터를 CGB 속성에 명시적으로 적용합니다. DMG에서는 검은 정사각형입니다.

map_load_metatile: DMG
DMG
map_load_metatile: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:300

선언 주석 원문
Select metatile mode, copy its descriptor and draw the initial viewport
with the camera at cell (0,0).

kitaqgb/lib/map.c:145

c
void map_load_metatile(u8 bank, const metatile_map_t* map)
{
    map_meta_bank = bank;
    __farmemcpy(&map_meta_current, bank, map, sizeof(metatile_map_t));
    map_meta_loaded = 1;
    map_loaded = 0;
    map_dirty = 0;
    map_camera_x = 0;
    map_camera_y = 0;
    map_draw_visible(0, 0);
}
map_mark_dirty

유효한 메타타일 좌표를 받으면 뷰포트에 다시 그리기 표시를 합니다.

사용 형식

c
void map_mark_dirty(u8 tx, u8 ty);

매개변수

tx

메타타일 X 좌표입니다.

ty

메타타일 Y 좌표입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

셀별 갱신을 큐에 넣는 대신 공유 변경 플래그 하나를 설정합니다. 맵 밖의 좌표는 무시합니다. 호출자가 ID나 정의를 별도로 바꾼 뒤 변경 표시를 해야 합니다.

사용 예

c
ids[1]=1;map_mark_dirty(1,0);result[10]=*((u8*)0x9800);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

RAM의 메타타일 ID를 바꾸고 변경 표시 후 반영합니다. 카메라 (1,0)에서 왼쪽 위에 초록 16×16 정사각형이 보입니다. 샘플은 팔레트 메타데이터를 CGB 속성에 명시적으로 적용합니다. DMG에서는 검은 정사각형입니다.

map_mark_dirty: DMG
DMG
map_mark_dirty: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_metatile.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_metatile.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:319

선언 주석 원문
Mark the viewport for a full redraw when a valid metatile cell changes.
The coordinate is validated but no per-cell dirty list is retained.

kitaqgb/lib/map.c:246

c
void map_mark_dirty(u8 tx, u8 ty)
{
    if (map_meta_loaded == 0) return;
    if (tx >= map_meta_current.width || ty >= map_meta_current.height) return;
    map_dirty = 1;
}
map_trigger_at

셀에 이벤트가 있는지 검사하되 실행하지는 않습니다.

사용 형식

c
u8 map_trigger_at(u8 x, u8 y);

매개변수

x

셀의 X 좌표입니다.

y

셀의 Y 좌표입니다.

반환값

이벤트가 있으면 1, 아니면 0을 반환합니다. 저장된 이벤트 바이트나 메타타일 이벤트 ID를 반환하지는 않습니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

사용 예

c
result[7]=map_trigger_at(5,4);result[8]=map_trigger_at(6,4);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

map_trigger_at: DMG
DMG
map_trigger_at: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:293

선언 주석 원문
Report whether an event exists at the cell. Ordinary maps expose a Boolean
byte-presence test; metatile maps reduce their event ID to a Boolean here.

kitaqgb/lib/map.c:87

c
u8 map_trigger_at(u8 x, u8 y)
{
    u16 index;
    u8 value;

    if (map_meta_loaded != 0) return (u8)(map_get_event(x, y) != 0);
    if (map_loaded == 0) return 0;
    if (x >= map_current.width || y >= map_current.height) return 0;
    if (map_current.events == 0) return 0;

    index = __map_index(x, y, map_current.width);
    value = __farpeek8(map_bank, ((const u8*)map_current.events) + index);
    return (u8)((value != 0) ? 1 : 0);
}
menu_draw

메뉴 상태를 바탕으로 테두리, 항목 이름, 현재 커서를 그립니다.

사용 형식

c
void menu_draw(menu_state_t* state);

매개변수

state

초기화된 메뉴 상태를 가리키는 포인터입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

null이면 아무 동작도 하지 않습니다. 호출할 때마다 text_open()으로 창을 다시 열며, 공유 텍스트 창 상태도 갱신합니다. 입력은 읽지 않습니다. 테두리, 커서, 글자 타일을 미리 로드하세요. 항목 배열과 문자열은 호출자가 유지해야 합니다. 텍스트를 자동으로 줄바꿈하거나 창에 맞춰 잘라내지 않으므로 위치, 항목 수, 이름 길이가 창에 맞도록 정하세요.

사용 예

c
menu_draw(&menu_state);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

처음에 메뉴를 그리고, 입력 후 다시 그리는 예제입니다. DOWN을 누르면 커서가 SHIELD 옆으로 이동합니다.

menu_draw: DMG
DMG
menu_draw: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_menu_state.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_menu_state.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/rpg.h:273

선언 주석 원문
Draw the current menu and cursor without waiting or sampling input. The
caller schedules suitable display timing and keeps item text within bounds.

kitaqgb/lib/menu.c:94

c
void menu_draw(menu_state_t* state)
{
    u8 i;
    if (state == 0) return;

    text_open(state->x, state->y, state->w, state->h);
    i = 0;
    while (i < state->count) {
        u8 py = (u8)(state->y + 1 + i);
        const u8* s = state->items[i];
        u8 px = (u8)(state->x + 2);
        __settile_xy((u8)(state->x + 1), py, (i == state->cursor) ? TEXT_TILE_CURSOR : TEXT_TILE_FILL);
        while (*s != 0) {
            __settile_xy(px, py, *s);
            px++;
            s++;
        }
        i++;
    }
}
menu_get_selected

단계적으로 처리하는 메뉴에 저장된 선택값을 읽습니다.

사용 형식

c
u8 menu_get_selected(menu_state_t* state);

매개변수

state

초기화된 메뉴 상태를 가리키는 포인터입니다.

반환값

0부터 시작하는 선택 인덱스를 반환합니다. 입력 대기 중이거나 취소했거나 null을 전달하면 255를 반환합니다.

사용 조건과 제한

읽어도 결과는 지워지지 않습니다. 처리가 끝나면 갱신을 멈추고, 새로운 입력 처리를 시작하기 전에 menu_init_state()를 호출하세요.

사용 예

c
result[0]=menu_get_selected(&menu_state);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

SHIELD의 선택값 1을 읽고, null을 전달하면 255가 반환되는지 확인하는 예제입니다.

menu_get_selected: DMG
DMG
menu_get_selected: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_menu_state.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_menu_state.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/rpg.h:279

선언 주석 원문
Read the latched selection without clearing it; null state returns 0xFF.

kitaqgb/lib/menu.c:148

c
u8 menu_get_selected(menu_state_t* state)
{
    if (state == 0) return 0xFF;
    return state->selected;
}
menu_init_state

게임 루프에서 단계적으로 처리할 메뉴를 초기화합니다.

사용 형식

c
void menu_init_state(menu_state_t* state, u8 x, u8 y, u8 w, u8 h, const u8* const* items, u8 count);

매개변수

state

초기화할 쓰기 가능한 menu_state_t입니다. null이면 안 됩니다.

x

창의 가장 왼쪽 타일 열입니다.

y

창의 맨 위 타일 행입니다.

w

테두리를 포함한 너비이며, 단위는 타일입니다.

h

테두리를 포함한 높이이며, 단위는 타일입니다.

items

0으로 끝나는 항목 이름 문자열을 가리키는 포인터 배열입니다.

count

항목 수이며, 창 내부의 사용 가능한 행 수를 넘으면 안 됩니다.

반환값

반환값은 없습니다.

사용 조건과 제한

커서와 이전 키 상태를 0, 선택값을 255, 취소 상태를 0으로 설정합니다. 화면을 그리거나 입력을 기다리지 않습니다. 테두리, 커서, 글자 타일을 미리 로드하세요. 항목 배열과 문자열은 호출자가 유지해야 합니다. 텍스트를 자동으로 줄바꿈하거나 창에 맞춰 잘라내지 않으므로 위치, 항목 수, 이름 길이가 창에 맞도록 정하세요.

사용 예

c
menu_init_state(&menu_state,1,2,18,5,choices,3);result[2]=menu_state.selected;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

(1,2)에 크기 18×5타일인 세 항목 메뉴를 준비합니다. 초기 선택값은 255입니다.

menu_init_state: DMG
DMG
menu_init_state: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_menu_state.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_menu_state.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/rpg.h:270

선언 주석 원문
Initialize a nonblocking menu state that borrows the item pointer table.
Selection starts unset (0xFF), and the cancellation flag starts clear.

kitaqgb/lib/menu.c:78

c
void menu_init_state(menu_state_t* state, u8 x, u8 y, u8 w, u8 h, const u8* const* items, u8 count)
{
    state->x = x;
    state->y = y;
    state->w = w;
    state->h = h;
    state->items = items;
    state->count = count;
    state->cursor = 0;
    state->prev_keys = 0;
    state->selected = 0xFF;
    state->cancelled = 0;
}
menu_inventory

소지품의 이름과 두 자리 수량을 표시하고 플레이어가 항목을 선택하게 합니다.

사용 형식

c
u8 menu_inventory(const item_t* items, u8 count);

매개변수

items

ID, 수량, 이름이 들어 있는 읽기 가능한 item_t 배열입니다.

count

항목 수입니다. 표시할 목록은 1~15개, 빈 목록은 0으로 지정합니다.

반환값

선택한 항목의 ID가 아닌 배열 인덱스를 반환합니다. 취소하거나 입력 목록이 비어 있으면 255를 반환합니다.

사용 조건과 제한

항목과 수량은 변경하지 않습니다. 수량은 0~99, 화면에 표시할 항목은 최대 15개로 제한하세요. 창의 위치는 (1,1), 너비는 18, 높이는 항목 수+2입니다. 이름은 3열에서 시작하고 수량은 15~16열에 표시하므로 긴 이름은 수량을 덮어쓸 수 있습니다. UP/DOWN은 목록의 끝에서 순환하며, A와 B를 동시에 누르면 A가 우선합니다. 테두리, 커서, 글자 타일을 미리 로드하세요. 항목 배열과 문자열은 호출자가 유지해야 합니다. 텍스트를 자동으로 줄바꿈하거나 창에 맞춰 잘라내지 않으므로 위치, 항목 수, 이름 길이가 창에 맞도록 정하세요.

사용 예

c
result[0]=menu_inventory(items,3);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

창에는 SWORD 07, SHIELD 42, POTION 99가 표시됩니다. SHIELD를 선택하면 인덱스 1을 반환하고 수량은 42로 유지됩니다.

menu_inventory: DMG
DMG
menu_inventory: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_menu_inventory.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_menu_inventory.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/rpg.h:267

선언 주석 원문
Run a blocking item menu, drawing names and two-digit quantities. Return
the selected index or 0xFF on empty input/B; this does not consume an item.

kitaqgb/lib/menu.c:176

c
u8 menu_inventory(const item_t* items, u8 count)
{
    u8 cursor;
    u8 prev;
    u8 i;

    if (count == 0) return 0xFF;

    text_open(1, 1, 18, (u8)(count + 2));
    cursor = 0;
    prev = 0;

    while (1) {
        for (i = 0; i < count; i++) {
            u8 py = (u8)(2 + i);
            const u8* s = items[i].name;
            u8 px = 3;
            __settile_xy(2, py, (i == cursor) ? TEXT_TILE_CURSOR : TEXT_TILE_FILL);
            while (*s != 0) {
                __settile_xy(px, py, *s);
                px++;
                s++;
            }
            menu_draw_ascii_qty(15, py, items[i].qty);
        }

        __wait_vblank();
        {
            u16 kt = __readpadex(prev);
            u8 trigger;
            prev = (u8)kt;
            trigger = (u8)(kt >> 8);

            if ((trigger & PAD_KEY_UP) != 0) {
                if (cursor == 0) cursor = (u8)(count - 1);
                else cursor--;
            }
            if ((trigger & PAD_KEY_DOWN) != 0) {
                cursor++;
                if (cursor >= count) cursor = 0;
            }
            if ((trigger & PAD_KEY_A) != 0) return cursor;
            if ((trigger & PAD_KEY_B) != 0) return 0xFF;
        }
    }
}
menu_run

항목을 표시하고 확정 또는 취소 입력을 기다리는 선택 메뉴를 실행합니다.

사용 형식

c
u8 menu_run(const menu_t* menu);

매개변수

menu

위치, 크기, 항목, 항목 수, 시작 커서를 지정하는 null이 아닌 menu_t입니다. 시작 커서가 범위를 벗어나면 0을 사용합니다.

반환값

0부터 시작하는 선택 인덱스를 반환합니다. B로 취소하거나 목록이 비어 있으면 255를 반환합니다.

사용 조건과 제한

UP/DOWN을 새로 누를 때마다 이동하며, 목록의 끝에서는 반대쪽으로 순환합니다. 누르고 있어도 반복 입력하지 않습니다. A와 B를 동시에 누르면 A가 우선합니다. 메뉴에 진입할 때 이미 누르고 있던 버튼도 새 입력으로 처리합니다. menu->cursor는 시작 위치를 지정하며, 선택 결과로 갱신되지 않습니다. 반환 후에도 창은 남아 있습니다. 테두리, 커서, 글자 타일을 미리 로드하세요. 항목 배열과 문자열은 호출자가 유지해야 합니다. 텍스트를 자동으로 줄바꿈하거나 창에 맞춰 잘라내지 않으므로 위치, 항목 수, 이름 길이가 창에 맞도록 정하세요.

사용 예

c
result[0]=menu_run(&menu);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

SWORD/SHIELD/POTION 중에서 DOWN 다음 A를 누르면 인덱스 1인 SHIELD가 선택됩니다. 저장된 시작 커서는 0으로 유지됩니다.

menu_run: DMG
DMG
menu_run: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_menu_run.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_menu_run.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/rpg.h:262

선언 주석 원문
Run a blocking menu loop with wraparound up/down selection, A to accept
and B to cancel. Return 0xFF for an empty menu or cancellation. Item strings
and menu dimensions must fit the visible tile area.

kitaqgb/lib/menu.c:25

c
u8 menu_run(const menu_t* menu)
{
    u8 cursor;
    u8 prev;

    if (menu->count == 0) return 0xFF;

    text_open(menu->x, menu->y, menu->w, menu->h);
    cursor = menu->cursor;
    if (cursor >= menu->count) cursor = 0;
    prev = 0;

    while (1) {
        u8 i;
        for (i = 0; i < menu->count; i++) {
            u8 py = (u8)(menu->y + 1 + i);
            __settile_xy((u8)(menu->x + 1), py, (i == cursor) ? TEXT_TILE_CURSOR : TEXT_TILE_FILL);
            {
                const u8* s = menu->items[i];
                u8 px = (u8)(menu->x + 2);
                while (*s != 0) {
                    __settile_xy(px, py, *s);
                    px++;
                    s++;
                }
            }
        }

        __wait_vblank();
        {
            u16 kt = __readpadex(prev);
            u8 trigger;
            prev = (u8)kt;
            trigger = (u8)(kt >> 8);

            if ((trigger & PAD_KEY_UP) != 0) {
                if (cursor == 0) cursor = (u8)(menu->count - 1);
                else cursor--;
            }
            if ((trigger & PAD_KEY_DOWN) != 0) {
                cursor++;
                if (cursor >= menu->count) cursor = 0;
            }
            if ((trigger & PAD_KEY_A) != 0) return cursor;
            if ((trigger & PAD_KEY_B) != 0) return 0xFF;
        }
    }
}
menu_update

컨트롤러 입력 변화를 한 번 읽고 커서, 선택값, 취소 상태를 갱신합니다.

사용 형식

c
void menu_update(menu_state_t* state);

매개변수

state

입력 이력과 결과를 갱신할 초기화된 메뉴 상태입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

null이거나 목록이 비어 있으면 아무 동작도 하지 않습니다. 프레임을 기다리거나 그리지 않으므로 게임 루프의 프레임마다 한 번 정도 호출하세요. UP/DOWN은 목록의 끝에서 반대쪽으로 순환하며, 누르고 있어도 반복 입력하지 않습니다. A 다음에 B를 처리하므로 동시에 누르면 취소됩니다.

사용 예

c
menu_update(&menu_state);menu_draw(&menu_state);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

루프는 VBlank를 기다리고, 상태를 갱신한 뒤 그리는 순서를 선택 또는 취소될 때까지 반복합니다. DOWN 다음 A를 누르면 선택값은 1, 취소 플래그는 0이 됩니다.

menu_update: DMG
DMG
menu_update: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_menu_state.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_menu_state.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/rpg.h:277

선언 주석 원문
Sample new button presses and update cursor/selection state without drawing.
Selected and cancelled results remain latched; a B press in the same update
as A clears selection and leaves cancellation set.

kitaqgb/lib/menu.c:118

c
void menu_update(menu_state_t* state)
{
    u16 kt;
    u8 trigger;

    if (state == 0) return;
    if (state->count == 0) return;

    kt = __readpadex(state->prev_keys);
    state->prev_keys = (u8)kt;
    trigger = (u8)(kt >> 8);

    if ((trigger & PAD_KEY_UP) != 0) {
        if (state->cursor == 0) state->cursor = (u8)(state->count - 1);
        else state->cursor--;
    }
    if ((trigger & PAD_KEY_DOWN) != 0) {
        state->cursor++;
        if (state->cursor >= state->count) state->cursor = 0;
    }
    if ((trigger & PAD_KEY_A) != 0) {
        state->selected = state->cursor;
    }
    if ((trigger & PAD_KEY_B) != 0) {
        state->cancelled = 1;
        state->selected = 0xFF;
    }
}
menu_was_cancelled

단계적으로 처리하는 메뉴가 B 버튼으로 취소되었는지 확인합니다.

사용 형식

c
u8 menu_was_cancelled(menu_state_t* state);

매개변수

state

초기화된 메뉴 상태를 가리키는 포인터입니다.

반환값

취소했으면 1, 아니면 0을 반환합니다. null을 전달해도 0입니다.

사용 조건과 제한

읽어도 플래그는 지워지지 않습니다. 다시 사용하기 전에 초기화하세요. 선택값 255만으로는 입력 대기와 취소를 구별할 수 없으므로 선택값과 함께 이 플래그를 사용하세요.

사용 예

c
result[1]=menu_was_cancelled(&menu_state);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

A로 확정하면 플래그는 0으로 유지됩니다. 별도의 입력 검사에서는 B로 취소하고 플래그가 1인지 확인합니다.

menu_was_cancelled: DMG
DMG
menu_was_cancelled: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_menu_state.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_menu_state.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/rpg.h:281

선언 주석 원문
Read the latched cancellation flag; null state returns false.

kitaqgb/lib/menu.c:155

c
u8 menu_was_cancelled(menu_state_t* state)
{
    if (state == 0) return 0;
    return state->cancelled;
}
menu_yesno

고정 위치에 YES/NO 메뉴를 표시하고 입력을 기다립니다.

사용 형식

c
u8 menu_yesno();

반환값

YES는 0, NO는 1, B로 취소하면 255를 반환합니다.

사용 조건과 제한

창은 타일 좌표 (6,10)에서 시작하며 크기는 8×4타일입니다. 선택에는 text_choice()를 사용합니다. 선택한 게임 동작은 함수가 반환한 뒤 호출자가 실행합니다. 테두리, 커서, 글자 타일을 미리 로드하세요. 항목 배열과 문자열은 호출자가 유지해야 합니다. 텍스트를 자동으로 줄바꿈하거나 창에 맞춰 잘라내지 않으므로 위치, 항목 수, 이름 길이가 창에 맞도록 정하세요.

사용 예

c
result[0]=menu_yesno();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

DOWN 다음 A를 누르면 NO가 선택됩니다. 커서는 NO 왼쪽에 나타나고 SELECTED에는 00001이 표시됩니다.

menu_yesno: DMG
DMG
menu_yesno: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_menu_yesno.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_menu_yesno.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/rpg.h:264

선언 주석 원문
Open a two-choice dialog and return the text-choice result (YES first, NO second).

kitaqgb/lib/menu.c:162

c
u8 menu_yesno()
{
    const u8* items[2];

    items[0] = menu_yes;
    items[1] = menu_no;
    text_open(6, 10, 8, 4);
    return text_choice(items, 2);
}
path_find_bfs

상하좌우 이동의 최단 경로를 찾아 시작점에서 목표까지의 순서로 방향을 기록합니다.

사용 형식

c
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len);

매개변수

sx

맵 안의 시작 셀 X 좌표입니다.

sy

시작 셀의 Y 좌표입니다.

gx

목표 셀의 X입니다. 출발점과 다른 막힌 목표는 거부합니다.

gy

목표 셀의 Y입니다.

out_path

최소 max_len바이트의 쓰기 가능한 배열입니다. 0=위, 1=오른쪽, 2=아래, 3=왼쪽입니다.

max_len

출력 용량입니다. 경로가 너무 길면 잘라내지 않고 실패합니다.

반환값

경로 길이를 반환합니다. 0은 도달 불가, 유효하지 않은 좌표, 부족한 max_len 또는 이미 목표에 도달한 상태를 뜻합니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

탐색에는 약 4KiB의 공유 작업 공간을 사용하며 재진입할 수 없습니다. 맵은 1024셀, 탐색 거리는 254 이하로 제한하세요. 거리 0xFF는 미도달을 뜻하므로 255단계 경로는 표현할 수 없습니다. 비용·마스크 출력에는 width*height바이트의 쓰기 가능한 공간이 필요합니다.

max_len은 탐색 반경이 아니라 출력 길이를 제한합니다. 실패한 뒤에는 출력을 새 경로로 사용하지 마세요.

사용 예

c
result[49]=path_find_bfs(0,2,5,2,route,30);x=0;y=2;for(i=0;i<result[49];i++){if(route[i]==0)y--;if(route[i]==1)x++;if(route[i]==2)y++;if(route[i]==3)x--;}result[50]=x;result[51]=y;result[52]=path_find_bfs(0,2,5,2,route,2);result[53]=path_find_bfs(0,2,2,2,route,30);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

path_find_bfs: DMG
DMG
path_find_bfs: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:361

선언 주석 원문
Find a shortest cardinal path with BFS and write direction codes 0=up,
1=right, 2=down, 3=left. Return its byte length, or zero for failure or an
already-reached goal. The caller supplies max_len output bytes and respects
the shared workspace/distance limits; excessive paths are not truncated.

kitaqgb/lib/slg_path.c:78

c
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len)
{
    u8 w = map_current_width();
    u8 h = map_current_height();
    u16 total;
    u16 head = 0;
    u16 tail = 0;
    u16 start;
    u16 goal;
    u8 found = 0;

    if (w == 0 || h == 0) return 0;
    if (sx >= w || sy >= h || gx >= w || gy >= h) return 0;
    if ((sx != gx || sy != gy) && map_is_blocked(gx, gy) != 0) return 0;

    total = (u16)((u16)w * (u16)h);
    __memset(path_dist, 0xFF, total);

    start = __map_index(sx, sy, w);
    goal = __map_index(gx, gy, w);

    path_dist[start] = 0;
    path_queue[tail++] = start;

    while (head < tail) {
        u16 cur = path_queue[head++];
        u8 cost = path_dist[cur];
        u8 y = (u8)(cur / w);
        u8 x = (u8)(cur - ((u16)y * (u16)w));

        if (cur == goal) {
            found = 1;
            break;
        }

        if (y > 0) {
            u16 next = (u16)(cur - w);
            if (path_dist[next] == 0xFF && map_is_blocked(x, (u8)(y - 1)) == 0) {
                path_dist[next] = (u8)(cost + 1);
                path_queue[tail++] = next;
            }
        }
        if ((u8)(x + 1) < w) {
            u16 next = (u16)(cur + 1);
            if (path_dist[next] == 0xFF && map_is_blocked((u8)(x + 1), y) == 0) {
                path_dist[next] = (u8)(cost + 1);
                path_queue[tail++] = next;
            }
        }
        if ((u8)(y + 1) < h) {
            u16 next = (u16)(cur + w);
            if (path_dist[next] == 0xFF && map_is_blocked(x, (u8)(y + 1)) == 0) {
                path_dist[next] = (u8)(cost + 1);
                path_queue[tail++] = next;
            }
        }
        if (x > 0) {
            u16 next = (u16)(cur - 1);
            if (path_dist[next] == 0xFF && map_is_blocked((u8)(x - 1), y) == 0) {
                path_dist[next] = (u8)(cost + 1);
                path_queue[tail++] = next;
            }
        }
    }

    // Reject unreachable or oversized paths before reconstructing output.
    if (found == 0) return 0;
    if (path_dist[goal] > max_len) return 0;

    {
        // Walk backward through decreasing costs, recording forward directions in
        // reverse order. The fixed neighbor order makes tied routes deterministic.
        u8 len = 0;
        u16 cur = goal;

        while (cur != start) {
            u8 cur_cost = path_dist[cur];
            u8 y = (u8)(cur / w);
            u8 x = (u8)(cur - ((u16)y * (u16)w));

            if (y > 0 && path_dist[(u16)(cur - w)] == (u8)(cur_cost - 1)) {
                path_rev[len++] = 2;
                cur = (u16)(cur - w);
                continue;
            }
            if ((u8)(x + 1) < w && path_dist[(u16)(cur + 1)] == (u8)(cur_cost - 1)) {
                path_rev[len++] = 3;
                cur = (u16)(cur + 1);
                continue;
            }
            if ((u8)(y + 1) < h && path_dist[(u16)(cur + w)] == (u8)(cur_cost - 1)) {
                path_rev[len++] = 0;
                cur = (u16)(cur + w);
                continue;
            }
            if (x > 0 && path_dist[(u16)(cur - 1)] == (u8)(cur_cost - 1)) {
                path_rev[len++] = 1;
                cur = (u16)(cur - 1);
                continue;
            }
            return 0;
        }

        // Reverse the recovered directions so the first output step starts at the origin.
        while (len != 0) {
            len--;
            out_path[path_dist[goal] - 1 - len] = path_rev[len];
        }

        return path_dist[goal];
    }
}
quest_set_state

퀘스트 하나의 상태 바이트 전체를 교체합니다. 값의 의미는 게임이 정합니다. 예를 들어 1을 수락, 3을 완료로 쓸 수 있습니다. 함수는 해당 상태 전이가 허용되는지 검사하지 않으며 보상이나 콜백도 실행하지 않습니다.

사용 형식

c
void quest_set_state(u8 quest_id, u8 state);

매개변수

quest_id

퀘스트 번호 0~63이며 u8로 전달합니다. 64개 상태 바이트 중 하나를 직접 인덱싱합니다. 게임이 정한 ID이지 포인터나 완료한 퀘스트 수가 아닙니다.

state

새 u8 상태값 0~255입니다. 8비트 전체가 이전 값을 덮어씁니다. 라이브러리는 값에 기본 의미를 부여하지 않으며 0이나 255를 예약하지도 않습니다.

반환값

없음(void).

사용 조건과 제한

함수는 ID를 검사하지 않습니다. 플래그 ID는 2048 미만, 퀘스트 ID는 64 미만으로 유지하세요. 범위를 벗어나면 관련 없는 RAM을 읽거나 덮어쓸 수 있습니다. 예제는 시작 시 메모리 내용에 의존하지 않고 명시적으로 초기화합니다.

flags.c는 RAM에 플래그용 256바이트와 별도의 퀘스트용 64바이트를 갖습니다. 이 함수들은 카트리지 세이브 RAM에 접근하지 않으며 전원이 꺼진 뒤에는 유지되지 않습니다. 진행 상황을 영구 저장하려면 게임이 플래그와 퀘스트 값을 세이브 시스템을 통해 직렬화하고 로드 시 복원해야 합니다.

rpg.h를 포함하고 lib/flags.c를 게임과 함께 컴파일하세요. 배열은 그 소스 파일 내부 전용이므로 플래그·퀘스트 API로 접근하세요. 모든 호출자가 저장 공간을 공유하므로 메인 루프와 인터럽트 핸들러의 쓰기 순서는 직접 조정해야 합니다.

사용 예

c
quest_set_state(2,1); // In this game, 1 means accepted.
started=quest_state(2);
quest_set_state(2,3); // In this game, 3 means completed; replace the whole byte.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 퀘스트 2에 1을 저장한 뒤 3으로 덮어씁니다. ACCEPTED에는 처음 관측값 001, COMPLETED에는 교체된 값 003이 표시됩니다. 마지막 유효 항목인 퀘스트 ID 63에 255를 저장하면 LAST QUEST는 255입니다.

완전한 프로그램은 흰 배경에 10진수 결과를 표시합니다. DMG에서는 검은 글자, CGB에서는 파란 글자입니다. FAILED는 000이어야 합니다. 캡처 화면은 RAM 상태 동작만 보여 주며 게임 저장을 입증하지는 않습니다.

DMG 에뮬레이터 검증에서는 플래그 ID 0~2047 전체, 반복 설정·해제, 이웃 항목, 퀘스트 64개 각각의 모든 상태값 256개를 확인했습니다. 마지막의 256바이트 플래그 패턴과 퀘스트 64바이트를 예상 데이터와 비교했습니다. 두 학습 화면은 240프레임 후 확인했습니다. 실기와 저장 데이터의 영속성은 검증하지 않았습니다.

quest_set_state: DMG
DMG
quest_set_state: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:377

선언 주석 원문
Replace a quest-state byte without validating its game-specific meaning.
The caller must keep quest_id below 64.

kitaqgb/lib/flags.c:34

c
void quest_set_state(u8 quest_id, u8 state)
{
    quest_states[quest_id] = state;
}
quest_state

퀘스트 하나의 저장된 바이트를 읽습니다. 1비트 플래그와 달리 퀘스트 바이트는 미시작, 수락, 완료 같은 여러 단계를 구분할 수 있습니다. 함수는 저장값만 읽으며 퀘스트 로직을 실행하거나 단계를 진행시키지 않습니다.

사용 형식

c
u8 quest_state(u8 quest_id);

매개변수

quest_id

퀘스트 번호 0~63이며 u8로 전달합니다. 64개 상태 바이트 중 하나를 직접 인덱싱합니다. 게임이 정한 ID이지 포인터나 완료한 퀘스트 수가 아닙니다.

반환값

저장된 u8 값 0~255입니다. 정규화된 불리언이 아니라 전체 상태 바이트이므로 게임에서 정의한 단계 값과 비교하세요.

사용 조건과 제한

함수는 ID를 검사하지 않습니다. 플래그 ID는 2048 미만, 퀘스트 ID는 64 미만으로 유지하세요. 범위를 벗어나면 관련 없는 RAM을 읽거나 덮어쓸 수 있습니다. 예제는 시작 시 메모리 내용에 의존하지 않고 명시적으로 초기화합니다.

flags.c는 RAM에 플래그용 256바이트와 별도의 퀘스트용 64바이트를 갖습니다. 이 함수들은 카트리지 세이브 RAM에 접근하지 않으며 전원이 꺼진 뒤에는 유지되지 않습니다. 진행 상황을 영구 저장하려면 게임이 플래그와 퀘스트 값을 세이브 시스템을 통해 직렬화하고 로드 시 복원해야 합니다.

rpg.h를 포함하고 lib/flags.c를 게임과 함께 컴파일하세요. 배열은 그 소스 파일 내부 전용이므로 플래그·퀘스트 API로 접근하세요. 모든 호출자가 저장 공간을 공유하므로 메인 루프와 인터럽트 핸들러의 쓰기 순서는 직접 조정해야 합니다.

사용 예

c
finished=quest_state(2); // Read back 3 without advancing any quest logic.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 게임이 퀘스트 2의 상태를 명시적으로 1에서 3으로 바꾼 뒤 읽습니다. ACCEPTED는 001, COMPLETED는 003입니다. 이름과 단계 의미는 라이브러리가 강제하는 것이 아니라 예제에서 정한 것입니다.

완전한 프로그램은 흰 배경에 10진수 결과를 표시합니다. DMG에서는 검은 글자, CGB에서는 파란 글자입니다. FAILED는 000이어야 합니다. 캡처 화면은 RAM 상태 동작만 보여 주며 게임 저장을 입증하지는 않습니다.

DMG 에뮬레이터 검증에서는 플래그 ID 0~2047 전체, 반복 설정·해제, 이웃 항목, 퀘스트 64개 각각의 모든 상태값 256개를 확인했습니다. 마지막의 256바이트 플래그 패턴과 퀘스트 64바이트를 예상 데이터와 비교했습니다. 두 학습 화면은 240프레임 후 확인했습니다. 실기와 저장 데이터의 영속성은 검증하지 않았습니다.

quest_state: DMG
DMG
quest_state: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\flags_quests.c .\kitaqgb\lib\flags.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\flags_quests.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:374

선언 주석 원문
Read a quest-state byte; quest_id must be below 64.

kitaqgb/lib/flags.c:27

c
u8 quest_state(u8 quest_id)
{
    return quest_states[quest_id];
}
rand_range

rng8() % max로 0 이상 max 미만의 값을 고릅니다. 예를 들어 상한 10은 0부터 9까지의 인덱스를 만듭니다. 상한이 0이면 추출 없이 즉시 0을 반환합니다.

사용 형식

c
u8 rand_range(u8 max);

매개변수

max

배타적 상한 u8(0–255)입니다. max > 0이면 결과는 max보다 작습니다. 이 인수로 256은 표현할 수 없습니다. 나머지 연산 없이 전체 바이트 범위가 필요하면 rng8을 사용하세요.

반환값

max > 0이면 한 번 추출해 0부터 max−1까지의 u8을 반환합니다. max == 0이면 추출 없이 0입니다. max == 1도 결과는 항상 0이지만 한 번 추출합니다.

사용 조건과 제한

입력 범위가 상한으로 나누어떨어지지 않으면 나머지 연산이 일부 결과에 더 높은 확률을 줄 수 있습니다. 원래 생성기도 균등 분포일 필요는 없습니다. 범위 선택과 확률 임계값은 정확한 확률이 아니라 게임용 근사로 다루세요.

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
rng_seed(0x1234);
bounded=rand_range(10); // An index from 0 through 9; this seed yields 2.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

10 미만의 인덱스를 고르는 샘플입니다. 시드 0x1234의 첫 바이트가 2이므로 RANGE 10은 00002입니다. ZERO BOUND는 00000이고 다음 NEXT BYTE는 여전히 00002여서, 상한 0 호출이 추출하지 않았음을 확인합니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

rand_range: DMG
DMG
rand_range: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_choices.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_choices.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:199

선언 주석 원문
Reduce a random byte modulo max; zero returns zero without consuming randomness.
Modulo reduction is biased unless max divides the generator range.

kitaqgb/lib/rng.c:37

c
u8 rand_range(u8 max)
{
    if (max == 0) return 0;
    return (u8)(rng8() % max);
}
range_fill_move

상하좌우 이웃을 비용 1로 너비 우선 탐색하여 이동 비용을 만듭니다.

사용 형식

c
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap);

매개변수

sx

맵 안의 시작 셀 X 좌표입니다.

sy

시작 셀의 Y 좌표입니다.

move

이동 한도는 0~254입니다. 0이면 출발점에만 도달합니다.

out_costmap

쓰기 가능한 width*height 크기의 비용 배열입니다. 255는 미도달, 출발점은 0입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

탐색에는 약 4KiB의 공유 작업 공간을 사용하며 재진입할 수 없습니다. 맵은 1024셀, 탐색 거리는 254 이하로 제한하세요. 거리 0xFF는 미도달을 뜻하므로 255단계 경로는 표현할 수 없습니다. 비용·마스크 출력에는 width*height바이트의 쓰기 가능한 공간이 필요합니다.

맵이 없거나 출발점이 유효하지 않으면 출력을 바꾸지 않습니다. 막힌 목적지 셀로는 진입하지 않습니다.

사용 예

c
range_fill_move(0,2,3,costs);for(i=0;i<30;i++)result[13+i]=costs[i];

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

range_fill_move: DMG
DMG
range_fill_move: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:365

선언 주석 원문
Flood cardinal neighbors at unit cost, stopping expansion at the movement
limit and rejecting blocked destinations. Initialize output to 0xFF only
after validating the map and origin; invalid input leaves output unchanged.

kitaqgb/lib/slg_path.c:14

c
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap)
{
    u8 w = map_current_width();
    u8 h = map_current_height();
    u16 total;
    u16 head = 0;
    u16 tail = 0;
    u16 start;

    if (w == 0 || h == 0) return;
    if (sx >= w || sy >= h) return;

    total = (u16)((u16)w * (u16)h);
    __memset(out_costmap, 0xFF, total);

    start = __map_index(sx, sy, w);
    out_costmap[start] = 0;
    path_queue[tail++] = start;

    while (head < tail) {
        u16 cur = path_queue[head++];
        u8 cost = out_costmap[cur];
        u8 y = (u8)(cur / w);
        u8 x = (u8)(cur - ((u16)y * (u16)w));

        if (cost >= move) continue;

        if (y > 0) {
            u16 next = (u16)(cur - w);
            if (out_costmap[next] == 0xFF && map_is_blocked(x, (u8)(y - 1)) == 0) {
                out_costmap[next] = (u8)(cost + 1);
                path_queue[tail++] = next;
            }
        }
        if ((u8)(x + 1) < w) {
            u16 next = (u16)(cur + 1);
            if (out_costmap[next] == 0xFF && map_is_blocked((u8)(x + 1), y) == 0) {
                out_costmap[next] = (u8)(cost + 1);
                path_queue[tail++] = next;
            }
        }
        if ((u8)(y + 1) < h) {
            u16 next = (u16)(cur + w);
            if (out_costmap[next] == 0xFF && map_is_blocked(x, (u8)(y + 1)) == 0) {
                out_costmap[next] = (u8)(cost + 1);
                path_queue[tail++] = next;
            }
        }
        if (x > 0) {
            u16 next = (u16)(cur - 1);
            if (out_costmap[next] == 0xFF && map_is_blocked((u8)(x - 1), y) == 0) {
                out_costmap[next] = (u8)(cost + 1);
                path_queue[tail++] = next;
            }
        }
    }
}
rle_decode

런 길이로 압축된 바이트 스트림을 일반 쓰기 가능 RAM에 풉니다. 각 count/value 쌍은 한 바이트를 count번 반복하며, count가 0이면 스트림이 끝납니다. 압축 데이터를 일반 포인터로 읽을 수 있고 업로드 전에 풀린 바이트를 검사하거나 수정하려는 경우 사용합니다.

사용 형식

c
u16 rle_decode(void* dst, const void* src);

매개변수

dst

전체 해제 결과를 담을 만큼 충분한 쓰기 가능 RAM의 포인터입니다. 함수에 용량을 전달하지 않습니다. 아직 읽지 않은 쌍을 출력이 덮어쓰지 않도록 압축 소스와 출력 영역을 분리하세요.

src

count가 0인 종료자로 끝나는 count/value 바이트 쌍의 읽기 가능한 포인터입니다. 일반 반복의 count는 1–255이며 value는 0을 포함한 어떤 바이트도 가능합니다. 종료용 0 뒤에는 value 바이트가 없습니다. 호출 내내 현재 매핑에서 포인터를 읽을 수 있어야 합니다.

반환값

쓴 바이트 수를 u16으로 반환합니다. 처음부터 count가 0이면 아무것도 쓰지 않고 0을 반환합니다. 종료자는 복사하지 않습니다. 해제 후 길이가 u16 범위에 들어가야 합니다. 별도 오류 코드는 없으며 반환값은 타일 수가 아닙니다.

사용 조건과 제한

이 인코딩은 텍스트가 아니라 바이트 단위입니다. 예를 들어 {3, 0x12, 2, 0xA5, 0}은 12 12 12 A5 A5의 5바이트로 풀립니다. 이 출력 표기의 값은 16진수입니다. count가 0이 아닌 쌍의 value=0은 종료 표식이 아니라 일반 데이터입니다.

압축 크기, 출력 용량, 잘못된 데이터 처리를 위한 인수는 없습니다. 에셋을 만들거나 로드할 때 검증하고, 종료용 0을 넣고, 디코딩 전에 해제 후 크기를 계산하세요. 잘못되거나 끝나지 않는 스트림은 소스 밖을 읽고 대상 밖에 쓸 수 있습니다.

RAM 디코더는 일반 쓰기 명령을 사용하며 LCD 접근 구간과 동기화하지 않습니다. 대상은 RAM으로 지정하세요. 결과를 표시하려면 샘플처럼 LCD를 멈춘 상태에서 적절한 VRAM 복사 API로 별도 업로드하세요.

뱅크 지정 읽기가 진행되는 동안 인터럽트 루틴이 ROM 매핑을 바꾸거나 far-copy 보조 함수를 재사용하지 않게 하세요. 보조 함수들은 뱅크 관리 상태를 공유합니다. 일반 포인터 디코더와 소스는 서로 호환되는 매핑에 배치하세요. 함수의 뱅크로 전환했을 때 일반 소스 포인터가 가려져서는 안 됩니다.

rle_decode와 rle_decode_far는 rpg.h에 선언되어 있고 lib/rle.c에 구현되어 있습니다. 게임과 함께 이 구현을 한 번만 컴파일하세요. 전체 예제는 호출자와 디코더를 공통 뱅크에 두기 위해 #pragma bank 0 뒤에 rle.c를 포함합니다. 이 예제에서는 rle.c를 별도 입력으로도 전달하지 마세요. __rle_decode_vram 내장 함수 자체에는 라이브러리 구현 파일이 필요 없습니다.

사용 예

c
near_count=rle_decode(near_buffer+1,local_rle); // 48 bytes in writable RAM.
__vram_copy(0x8800,near_buffer+1,near_count); // Upload those bytes while the LCD is off.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 예제는 압축된 9바이트를 보호 영역이 있는 RAM 버퍼에 풀고, 48바이트 결과를 타일 데이터 주소 0x8800에 복사합니다. RLE TO RAM은 048로 표시됩니다. 위쪽 줄은 CGB에서 빨간색이며 일반 포인터 경로로 푼 타일 세 개를 보여 줍니다.

각 줄은 왼쪽부터 채워진 8×8 정사각형, 테두리 두께 1픽셀인 8×8 사각형, 8×8 타일의 왼쪽 절반을 채운 4×8 직사각형입니다. 타일 열은 2, 5, 8(픽셀 x = 16, 40, 64)이고 세 줄의 시작 픽셀 y는 32, 72, 112입니다. DMG는 검은색, CGB는 줄별 빨강·초록·파랑입니다. FAILED는 000이어야 합니다. 숫자는 바이트 수로, 16바이트 GB 타일 세 개에 해제된 48바이트가 필요합니다.

검증은 빈 스트림, 1바이트 반복, 값 0인 데이터, 255바이트 반복, 대상 페이지를 넘는 510바이트 출력, 소스 페이지를 넘는 압축 데이터 등 42가지 경우를 포함합니다. 관찰한 대상·보호 영역 528바이트 전체, 출력 길이, 복원된 ROM 매핑을 비교합니다. 직접 VRAM 경로는 DMG·CGB의 LCD 켜짐/꺼짐과 CGB VBK 1도 포함합니다. 학습용 화면 두 개는 에뮬레이터 240프레임 후 검사합니다. 잘못된 에셋, 인터럽트의 동시 사용, 실기는 검증 범위에 포함하지 않습니다.

rle_decode: DMG
DMG
rle_decode: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rle_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rle_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:382

선언 주석 원문
Expand count/value byte pairs until a zero count terminates the stream.
The caller must provide a valid terminator and sufficient destination storage;
there are no source or destination bounds parameters. Return the 16-bit byte count.

kitaqgb/lib/rle.c:8

c
u16 rle_decode(void* dst, const void* src)
{
    const u8* in = (const u8*)src;
    u8* out = (u8*)dst;
    u16 total = 0;

    while (1) {
        u8 count = *in++;
        u8 value;
        if (count == 0) break;
        value = *in++;
        while (count != 0) {
            *out++ = value;
            total++;
            count--;
        }
    }

    return total;
}
rle_decode_far

같은 count/value 형식을 RAM에 풀되, 지정한 ROM 뱅크에서 __farpeek8로 각 압축 바이트를 읽습니다. 전환 가능한 ROM 뱅크에 저장한 압축 에셋에 사용합니다. 대상은 일반 RAM 포인터이며 bank 인수는 소스를 지정합니다.

사용 형식

c
u16 rle_decode_far(void* dst, u8 bank, const void* src);

매개변수

dst

전체 해제 결과를 담을 만큼 충분한 쓰기 가능 RAM의 포인터입니다. 함수에 용량을 전달하지 않습니다. 아직 읽지 않은 쌍을 출력이 덮어쓰지 않도록 압축 소스와 출력 영역을 분리하세요.

bank

소스 ROM 뱅크 번호이며 u8입니다. 뱅크와 CPU 주소는 카트리지 매퍼와 에셋 배치에 맞아야 합니다. 압축 바이트를 읽을 때마다 뱅크 선택을 복원합니다. 대상 VRAM 뱅크를 선택하는 인수가 아니며 9비트 MBC5 뱅크 번호는 표현할 수 없습니다.

src

지정한 뱅크 안의 압축 스트림을 가리키는 CPU 포인터입니다. 주소는 증가하지만 뱅크 번호는 고정됩니다. 종료용 0까지 전체 스트림을 읽기 가능한 매핑 안에 두세요. 0x7FFF를 넘는다고 다음 ROM 뱅크로 자동 이어지지 않습니다.

반환값

쓴 바이트 수를 u16으로 반환합니다. 처음부터 count가 0이면 아무것도 쓰지 않고 0을 반환합니다. 종료자는 복사하지 않습니다. 해제 후 길이가 u16 범위에 들어가야 합니다. 별도 오류 코드는 없으며 반환값은 타일 수가 아닙니다.

사용 조건과 제한

이 인코딩은 텍스트가 아니라 바이트 단위입니다. 예를 들어 {3, 0x12, 2, 0xA5, 0}은 12 12 12 A5 A5의 5바이트로 풀립니다. 이 출력 표기의 값은 16진수입니다. count가 0이 아닌 쌍의 value=0은 종료 표식이 아니라 일반 데이터입니다.

압축 크기, 출력 용량, 잘못된 데이터 처리를 위한 인수는 없습니다. 에셋을 만들거나 로드할 때 검증하고, 종료용 0을 넣고, 디코딩 전에 해제 후 크기를 계산하세요. 잘못되거나 끝나지 않는 스트림은 소스 밖을 읽고 대상 밖에 쓸 수 있습니다.

RAM 디코더는 일반 쓰기 명령을 사용하며 LCD 접근 구간과 동기화하지 않습니다. 대상은 RAM으로 지정하세요. 결과를 표시하려면 샘플처럼 LCD를 멈춘 상태에서 적절한 VRAM 복사 API로 별도 업로드하세요.

뱅크 지정 읽기가 진행되는 동안 인터럽트 루틴이 ROM 매핑을 바꾸거나 far-copy 보조 함수를 재사용하지 않게 하세요. 보조 함수들은 뱅크 관리 상태를 공유합니다. 일반 포인터 디코더와 소스는 서로 호환되는 매핑에 배치하세요. 함수의 뱅크로 전환했을 때 일반 소스 포인터가 가려져서는 안 됩니다.

rle_decode와 rle_decode_far는 rpg.h에 선언되어 있고 lib/rle.c에 구현되어 있습니다. 게임과 함께 이 구현을 한 번만 컴파일하세요. 전체 예제는 호출자와 디코더를 공통 뱅크에 두기 위해 #pragma bank 0 뒤에 rle.c를 포함합니다. 이 예제에서는 rle.c를 별도 입력으로도 전달하지 마세요. __rle_decode_vram 내장 함수 자체에는 라이브러리 구현 파일이 필요 없습니다.

사용 예

c
far_count=rle_decode_far(far_buffer+1,2,banked_rle); // Read encoded pairs from ROM bank 2.
if(*rle_bank_marker!=0xA1)failures++; // ROM bank 1 must be visible again.
__vram_copy(0x8830,far_buffer+1,far_count);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이 예제는 ROM 뱅크 2의 압축 스트림을 읽어 RAM에 48바이트로 풀고 0x8830에 업로드합니다. BANKED RAM은 048로 표시됩니다. 가운데 줄은 CGB에서 초록색입니다. ROM 뱅크 1의 표식도 검사해 호출자의 매핑이 복원되었는지 확인합니다.

각 줄은 왼쪽부터 채워진 8×8 정사각형, 테두리 두께 1픽셀인 8×8 사각형, 8×8 타일의 왼쪽 절반을 채운 4×8 직사각형입니다. 타일 열은 2, 5, 8(픽셀 x = 16, 40, 64)이고 세 줄의 시작 픽셀 y는 32, 72, 112입니다. DMG는 검은색, CGB는 줄별 빨강·초록·파랑입니다. FAILED는 000이어야 합니다. 숫자는 바이트 수로, 16바이트 GB 타일 세 개에 해제된 48바이트가 필요합니다.

검증은 빈 스트림, 1바이트 반복, 값 0인 데이터, 255바이트 반복, 대상 페이지를 넘는 510바이트 출력, 소스 페이지를 넘는 압축 데이터 등 42가지 경우를 포함합니다. 관찰한 대상·보호 영역 528바이트 전체, 출력 길이, 복원된 ROM 매핑을 비교합니다. 직접 VRAM 경로는 DMG·CGB의 LCD 켜짐/꺼짐과 CGB VBK 1도 포함합니다. 학습용 화면 두 개는 에뮬레이터 240프레임 후 검사합니다. 잘못된 에셋, 인터럽트의 동시 사용, 실기는 검증 범위에 포함하지 않습니다.

rle_decode_far: DMG
DMG
rle_decode_far: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rle_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rle_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:386

선언 주석 원문
Decode the same count/value format using bank-qualified reads for every source
byte. Keep the encoded stream within the supplied bank/address mapping and
provide enough destination space; a zero count ends the stream.

kitaqgb/lib/rle.c:34

c
u16 rle_decode_far(void* dst, u8 bank, const void* src)
{
    const u8* p = (const u8*)src;
    u8* out = (u8*)dst;
    u16 total = 0;

    while (1) {
        u8 count = __farpeek8(bank, p);
        u8 value;
        p++;
        if (count == 0) break;
        value = __farpeek8(bank, p);
        p++;
        while (count != 0) {
            *out++ = value;
            total++;
            count--;
        }
    }

    return total;
}
rng16

연속된 rng8 추출 두 개로 부호 없는 16비트 값을 만듭니다. 첫 바이트는 비트 15–8, 두 번째는 7–0이 됩니다. 필요한 값 범위를 한 바이트로 표현할 수 없을 때 사용합니다.

사용 형식

c
u16 rng16();

반환값

(first_byte << 8) | second_byte로 만든 u16 결과(0–65535)입니다. 정확히 두 번의 바이트 추출을 소비합니다. 65536개 모든 값의 균등 분포를 뜻하지는 않습니다.

사용 조건과 제한

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
rng_seed(0x1234);
word=rng16(); // First draw 2 is high, second draw 34 is low: 0x0222 = 546.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

워드 조합을 보여 주는 샘플입니다. 0x1234로 다시 시드를 설정하면 바이트 2와 34가 0x0222를 만들므로 RNG16은 00546입니다. FIRST와 SECOND는 해당 바이트값을 따로 표시합니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

rng16: DMG
DMG
rng16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:196

선언 주석 원문
Consume two generator bytes in high-byte/low-byte order to form a 16-bit value.

kitaqgb/lib/rng.c:22

c
u16 rng16()
{
    u16 hi = (u16)rng8();
    u16 lo = (u16)rng8();
    return (u16)((hi << 8) | lo);
}
rng8

GB 라이브러리로 의사 난수 바이트 하나를 얻습니다. rng8은 __rng8을 정확히 한 번 호출하며, rng.c의 다른 보조 함수들이 사용하는 기본 추출 연산입니다.

사용 형식

c
u8 rng8();

반환값

공유 생성기를 한 번 진행시킨 뒤 얻는 u8 결과(0–255)입니다. 값의 자료형과 범위를 설명하는 것이며 모든 바이트의 확률이 같다는 뜻은 아닙니다.

사용 조건과 제한

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
rng_seed(0x1234); // Reset the same generator used by the intrinsics.
wrapped=rng8(); // One byte draw: 2 after the preceding seed.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

라이브러리 바이트 추출과 내장 함수를 비교하는 샘플입니다. rng_seed(0x1234) 이후 RNG8은 FIRST와 같은 00002입니다. 시드 설정은 첫 추출을 소비하지 않습니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

rng8: DMG
DMG
rng8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:194

선언 주석 원문
Advance the compiler-provided pseudorandom generator and return one byte.

kitaqgb/lib/rng.c:4

c
u8 rng8()
{
    return __rng8();
}
rng_chance

rng_range(100) < percent로 예/아니요를 고릅니다. 적이 아이템을 떨어뜨릴지 결정하는 등의 대략적인 게임 확률에 유용합니다. 0은 항상 거짓, 100 이상은 항상 참이며 두 끝 구간 모두 추출하지 않습니다.

사용 형식

c
u8 rng_chance(u8 percent);

매개변수

percent

요청 확률을 나타내는 u8입니다. 1–99는 바이트를 한 번 추출해 나머지 연산을 적용합니다. 0은 거짓, 100–255는 참을 반환합니다. 중간값은 근사 임계값이며 정확한 백분율을 보장하지 않습니다.

반환값

정규화된 불리언으로 거짓은 0, 참은 1입니다. 임계값 1–99로 호출하면 바이트를 한 번 추출합니다.

사용 조건과 제한

입력 범위가 상한으로 나누어떨어지지 않으면 나머지 연산이 일부 결과에 더 높은 확률을 줄 수 있습니다. 원래 생성기도 균등 분포일 필요는 없습니다. 범위 선택과 확률 임계값은 정확한 확률이 아니라 게임용 근사로 다루세요.

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
rng_seed(0x1234);
chance=rng_chance(50); // Here 2 % 100 < 50, so the result is 1 (true).

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

근사 50% 판정을 한 번 수행하는 샘플입니다. 시드로 얻는 바이트가 2이고 2 % 100 < 50이 참이므로 CHANCE 50은 00001입니다. 한 번 성공했다고 장기 성공률이 50%임을 입증하는 것은 아닙니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

rng_chance: DMG
DMG
rng_chance: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_choices.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_choices.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:214

선언 주석 원문
Return false for zero and true for values at least 100. Intermediate values
use the modulo-based range generator, so percentages are approximate.

kitaqgb/lib/rng.c:51

c
u8 rng_chance(u8 percent)
{
    if (percent == 0) return 0;
    if (percent >= 100) return 1;
    return (u8)(rng_range(100) < percent);
}
rng_next16

rng16과 같은 두 번 추출한 워드를 반환합니다. 라이브러리 별칭이며 첫 추출은 상위 바이트, 두 번째는 하위 바이트입니다. 추출 전에 추가 값을 건너뛰지 않습니다.

사용 형식

c
u16 rng_next16();

반환값

(first_byte << 8) | second_byte로 만든 u16 결과(0–65535)입니다. 정확히 두 번의 바이트 추출을 소비합니다. 65536개 모든 값의 균등 분포를 뜻하지는 않습니다.

사용 조건과 제한

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
rng_seed(0x1234);
nextword=rng_next16(); // The same two-draw word: 546.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

동일한 시드에서 워드 별칭과 rng16을 비교하는 샘플입니다. NEXT16과 RNG16은 모두 00546이며, 상위/하위 순서의 두 바이트 추출을 나타냅니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

rng_next16: DMG
DMG
rng_next16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:209

선언 주석 원문
Alias the two-step 16-bit generator.

kitaqgb/lib/rng.c:30

c
u16 rng_next16()
{
    return rng16();
}
rng_next8

rng8과 같은 연산으로 다음 바이트를 뽑습니다. 이름은 수열을 진행한다는 점을 강조합니다. 두 이름을 차례로 호출하면 같은 공유 생성기에서 연속 두 값을 소비합니다.

사용 형식

c
u8 rng_next8();

반환값

공유 생성기를 한 번 진행시킨 뒤 얻는 u8 결과(0–255)입니다. 값의 자료형과 범위를 설명하는 것이며 모든 바이트의 확률이 같다는 뜻은 아닙니다.

사용 조건과 제한

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
rng_seed(0x1234);
nextbyte=rng_next8(); // One draw, just like rng8(): 2.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

같은 시드에서 바이트 별칭을 확인하는 샘플입니다. 비교 전에 각각 다시 시드를 설정하므로 NEXT8과 RNG8은 모두 00002입니다. 초기화하지 않았다면 연속된 서로 다른 순서의 값을 소비합니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

rng_next8: DMG
DMG
rng_next8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:207

선언 주석 원문
Alias the byte generator; this consumes one generator step.

kitaqgb/lib/rng.c:16

c
u8 rng_next8()
{
    return rng8();
}
rng_range

같은 배타적 상한으로 rand_range를 호출합니다. 이 이름은 범위 선택을 다른 rng_ 함수들과 묶어 줍니다. 동일한 바이트 추출과 나머지 연산을 사용하며 상한 0에서는 추출하지 않습니다.

사용 형식

c
u8 rng_range(u8 max);

매개변수

max

배타적 상한 u8(0–255)입니다. max > 0이면 결과는 max보다 작습니다. 이 인수로 256은 표현할 수 없습니다. 나머지 연산 없이 전체 바이트 범위가 필요하면 rng8을 사용하세요.

반환값

max > 0이면 한 번 추출해 0부터 max−1까지의 u8을 반환합니다. max == 0이면 추출 없이 0입니다. max == 1도 결과는 항상 0이지만 한 번 추출합니다.

사용 조건과 제한

입력 범위가 상한으로 나누어떨어지지 않으면 나머지 연산이 일부 결과에 더 높은 확률을 줄 수 있습니다. 원래 생성기도 균등 분포일 필요는 없습니다. 범위 선택과 확률 임계값은 정확한 확률이 아니라 게임용 근사로 다루세요.

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
rng_seed(0x1234);
alias=rng_range(10); // The same exclusive upper bound and result, 2.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

범위 선택의 두 이름을 비교하는 샘플입니다. 호출마다 시드를 다시 설정하므로 ALIAS 10과 RANGE 10은 모두 00002입니다. 상한 10 자체는 결과에서 제외됩니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

rng_range: DMG
DMG
rng_range: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_choices.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_choices.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:211

선언 주석 원문
Alias rand_range and return a value in [0,max), or zero when max is zero.

kitaqgb/lib/rng.c:44

c
u8 rng_range(u8 max)
{
    return rand_range(max);
}
rng_seed

GB 라이브러리 인터페이스로 시드를 설정합니다. __rng_seed의 래퍼이므로 rng8, rng16, 선택 보조 함수들이 사용하는 같은 공유 상태를 초기화합니다. 별도 생성기를 만들지는 않습니다.

사용 형식

c
void rng_seed(u16 seed);

매개변수

seed

부호 없는 16비트 시드 0–65535입니다. 두 바이트를 전달된 그대로 저장합니다. 재현할 게임 추출 순서가 시작되기 전에 시드를 정하고 기록하세요.

반환값

없음(void).

사용 조건과 제한

상태 0도 허용됩니다. 다음 바이트 추출에서 GB 생성기는 진행 전에 0x5AA5로 대체합니다. 따라서 __rng_seed(0) 다음 __rng8()은 122를 반환합니다. 시드를 반복 설정하면 무작위성이 더해지는 것이 아니라 수열이 처음부터 다시 시작됩니다.

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
rng_seed(0x1234); // Reset the same generator used by the intrinsics.
wrapped=rng8(); // One byte draw: 2 after the preceding seed.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

라이브러리 바이트 추출과 내장 함수를 비교하는 샘플입니다. rng_seed(0x1234) 이후 RNG8은 FIRST와 같은 00002입니다. 시드 설정은 첫 추출을 소비하지 않습니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

rng_seed: DMG
DMG
rng_seed: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_values.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_values.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:205

선언 주석 원문
Replace the generator seed so subsequent calls can reproduce a sequence.

kitaqgb/lib/rng.c:10

c
void rng_seed(u16 seed)
{
    __rng_seed(seed);
}
save_check

데이터를 추출하지 않고 save_exists와 같은 무결성 검사를 수행합니다.

사용 형식

c
u8 save_check(u8 slot);

매개변수

slot

슬롯 번호 0~3입니다.

반환값

유효하면 1, 아니면 0을 반환합니다. 길이가 0인 저장 데이터도 유효할 수 있습니다.

사용 조건과 제한

기본 구성은 512바이트 슬롯 4개이며, 각 슬롯은 6바이트 헤더와 최대 506바이트 데이터를 담습니다. 샘플은 8KiB SRAM이 있는 MBC5를 사용합니다. 호출이 끝나면 RAM을 비활성화하며, 이전 뱅크나 활성 상태로 복원하지 않습니다.

사용 예

c
result[4]=save_check(0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

7/42/255의 세 바이트를 저장한 뒤 길이 불일치, 잘못된 슬롯, 손상된 체크섬을 검사합니다. 불러오기에 성공하면 가운데 바이트는 42입니다. 읽기에 실패하면 대상의 77을 유지하며, 지운 뒤 검증하면 0을 반환합니다.

save_check: DMG
DMG
save_check: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k
구현과 소스

kitaqgb/lib/rpg.h:341

선언 주석 원문
Alias save_exists, including its header and checksum validation.

kitaqgb/lib/save.c:175

c
u8 save_check(u8 slot)
{
    return save_exists(slot);
}
save_clear

슬롯의 512바이트를 모두 0으로 채워 저장 데이터를 무효화합니다.

사용 형식

c
void save_clear(u8 slot);

매개변수

slot

슬롯 번호 0~3입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

기본 구성은 512바이트 슬롯 4개이며, 각 슬롯은 6바이트 헤더와 최대 506바이트 데이터를 담습니다. 샘플은 8KiB SRAM이 있는 MBC5를 사용합니다. 호출이 끝나면 RAM을 비활성화하며, 이전 뱅크나 활성 상태로 복원하지 않습니다.

0~3 범위 밖의 슬롯은 무시하며, 다른 슬롯은 변경하지 않습니다.

사용 예

c
save_clear(0);result[16]=save_check(0);result[17]=save_write(3,payload,0);result[18]=save_exists(3);save_clear(3);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

7/42/255의 세 바이트를 저장한 뒤 길이 불일치, 잘못된 슬롯, 손상된 체크섬을 검사합니다. 불러오기에 성공하면 가운데 바이트는 42입니다. 읽기에 실패하면 대상의 77을 유지하며, 지운 뒤 검증하면 0을 반환합니다.

save_clear: DMG
DMG
save_clear: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k
구현과 소스

kitaqgb/lib/rpg.h:344

선언 주석 원문
Zero the complete selected slot, including header and payload; invalid slot
IDs are ignored. Cartridge RAM is disabled when clearing finishes.

kitaqgb/lib/save.c:225

c
void save_clear(u8 slot)
{
    u16 base;
    u16 i;

    if (slot >= SAVE_SLOT_COUNT) return;

    base = save_slot_base(slot);
    save_enable();

    i = 0;
    while (i < SAVE_SLOT_SIZE) {
        save_write_abs((u16)(base + i), 0);
        i++;
    }

    save_disable();
}
save_exists

슬롯의 헤더, 길이, 체크섬을 검사하여 사용할 수 있는 저장 데이터가 있는지 확인합니다.

사용 형식

c
u8 save_exists(u8 slot);

매개변수

slot

슬롯 번호 0~3입니다.

반환값

유효하면 1, 아니면 0을 반환합니다. 길이가 0인 저장 데이터도 유효할 수 있습니다.

사용 조건과 제한

기본 구성은 512바이트 슬롯 4개이며, 각 슬롯은 6바이트 헤더와 최대 506바이트 데이터를 담습니다. 샘플은 8KiB SRAM이 있는 MBC5를 사용합니다. 호출이 끝나면 RAM을 비활성화하며, 이전 뱅크나 활성 상태로 복원하지 않습니다.

사용 예

c
result[0]=save_exists(0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

7/42/255의 세 바이트를 저장한 뒤 길이 불일치, 잘못된 슬롯, 손상된 체크섬을 검사합니다. 불러오기에 성공하면 가운데 바이트는 42입니다. 읽기에 실패하면 대상의 77을 유지하며, 지운 뒤 검증하면 0을 반환합니다.

save_exists: DMG
DMG
save_exists: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k
구현과 소스

kitaqgb/lib/rpg.h:334

선언 주석 원문
Validate a slot's header, payload bounds and checksum without copying the
payload out. A nonzero result means the stored record passes these checks.

kitaqgb/lib/save.c:182

c
u8 save_exists(u8 slot)
{
    u16 base;
    u16 stored_len;
    u8 stored_sum;

    if (slot >= SAVE_SLOT_COUNT) return 0;

    base = save_slot_base(slot);
    save_enable();

    if (save_read_abs(base + 0) != SAVE_MAGIC0) {
        save_disable();
        return 0;
    }
    if (save_read_abs(base + 1) != SAVE_MAGIC1) {
        save_disable();
        return 0;
    }
    if (save_read_abs(base + 2) != SAVE_VERSION) {
        save_disable();
        return 0;
    }

    stored_len = (u16)save_read_abs(base + 3);
    stored_len |= (u16)((u16)save_read_abs(base + 4) << 8);
    stored_sum = save_read_abs(base + 5);

    if (stored_len > (u16)(SAVE_SLOT_SIZE - SAVE_HEADER_SIZE)) {
        save_disable();
        return 0;
    }
    if (save_checksum_ram((u16)(base + SAVE_HEADER_SIZE), stored_len) != stored_sum) {
        save_disable();
        return 0;
    }

    save_disable();
    return 1;
}
save_init

RAM 뱅크 0을 선택하고 잠시 활성화한 뒤 비활성화합니다.

사용 형식

c
void save_init();

반환값

반환값은 없습니다.

사용 조건과 제한

기본 구성은 512바이트 슬롯 4개이며, 각 슬롯은 6바이트 헤더와 최대 506바이트 데이터를 담습니다. 샘플은 8KiB SRAM이 있는 MBC5를 사용합니다. 호출이 끝나면 RAM을 비활성화하며, 이전 뱅크나 활성 상태로 복원하지 않습니다.

저장 데이터 삭제, 카트리지 하드웨어 감지, 슬롯 포맷은 수행하지 않습니다.

사용 예

c
save_init();save_clear(0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

7/42/255의 세 바이트를 저장한 뒤 길이 불일치, 잘못된 슬롯, 손상된 체크섬을 검사합니다. 불러오기에 성공하면 가운데 바이트는 42입니다. 읽기에 실패하면 대상의 77을 유지하며, 지운 뒤 검증하면 0을 반환합니다.

save_init: DMG
DMG
save_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k
구현과 소스

kitaqgb/lib/rpg.h:337

선언 주석 원문
Initialize the expected RAM access state and leave cartridge RAM disabled.
Existing slot contents are preserved.

kitaqgb/lib/save.c:70

c
void save_init()
{
    save_enable();
    save_disable();
}
save_load

save_read와 같은 검증을 거쳐 저장 데이터를 불러옵니다.

사용 형식

c
u8 save_load(u8 slot, void* data, u16 len);

매개변수

slot

슬롯 번호 0~3입니다.

data

len바이트의 쓰기 가능한 대상입니다.

len

데이터 길이는 0~506바이트입니다. 읽을 때는 저장된 길이와 정확히 일치해야 합니다.

반환값

불러오기에 성공하면 1, 아니면 0을 반환합니다. 요청한 길이는 저장된 길이와 일치해야 합니다.

사용 조건과 제한

기본 구성은 512바이트 슬롯 4개이며, 각 슬롯은 6바이트 헤더와 최대 506바이트 데이터를 담습니다. 샘플은 8KiB SRAM이 있는 MBC5를 사용합니다. 호출이 끝나면 RAM을 비활성화하며, 이전 뱅크나 활성 상태로 복원하지 않습니다.

8비트 가산 체크섬으로 모든 손상을 탐지할 수는 없습니다. 전원 차단에 대해 쓰기의 원자성이 보장되지 않으므로, 성공 반환만으로 실제 영구 저장을 보장하지는 않습니다.

사용 예

c
readback[1]=0;result[10]=save_load(0,readback,3);result[11]=readback[1];

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

7/42/255의 세 바이트를 저장한 뒤 길이 불일치, 잘못된 슬롯, 손상된 체크섬을 검사합니다. 불러오기에 성공하면 가운데 바이트는 42입니다. 읽기에 실패하면 대상의 77을 유지하며, 지운 뒤 검증하면 0을 반환합니다.

save_load: DMG
DMG
save_load: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k
구현과 소스

kitaqgb/lib/rpg.h:339

선언 주석 원문
Alias the checked save_read operation.

kitaqgb/lib/save.c:114

c
u8 save_load(u8 slot, void* data, u16 len)
{
    return save_read(slot, data, len);
}
save_read

헤더, 정확한 길이, 체크섬을 검사하고 모두 통과한 경우에만 데이터를 복사합니다.

사용 형식

c
u8 save_read(u8 slot, void* data, u16 len);

매개변수

slot

슬롯 번호 0~3입니다.

data

len바이트의 쓰기 가능한 대상입니다.

len

데이터 길이는 0~506바이트입니다. 읽을 때는 저장된 길이와 정확히 일치해야 합니다.

반환값

성공하면 1, 검증에 실패하면 0을 반환합니다. 실패해도 대상은 변경하지 않습니다.

사용 조건과 제한

기본 구성은 512바이트 슬롯 4개이며, 각 슬롯은 6바이트 헤더와 최대 506바이트 데이터를 담습니다. 샘플은 8KiB SRAM이 있는 MBC5를 사용합니다. 호출이 끝나면 RAM을 비활성화하며, 이전 뱅크나 활성 상태로 복원하지 않습니다.

8비트 가산 체크섬으로 모든 손상을 탐지할 수는 없습니다. 전원 차단에 대해 쓰기의 원자성이 보장되지 않으므로, 성공 반환만으로 실제 영구 저장을 보장하지는 않습니다.

사용 예

c
readback[0]=99;result[5]=save_read(0,readback,2);result[6]=readback[0];result[7]=save_read(0,readback,3);result[8]=readback[0];result[9]=readback[2];

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

7/42/255의 세 바이트를 저장한 뒤 길이 불일치, 잘못된 슬롯, 손상된 체크섬을 검사합니다. 불러오기에 성공하면 가운데 바이트는 42입니다. 읽기에 실패하면 대상의 77을 유지하며, 지운 뒤 검증하면 0을 반환합니다.

save_read: DMG
DMG
save_read: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k
구현과 소스

kitaqgb/lib/rpg.h:331

선언 주석 원문
Require matching magic/version, exact requested length and a valid checksum
before copying data into the destination. Validation failure leaves the
destination unchanged. An invalid slot returns before touching RAM control;
validation failures after enabling RAM disable it before returning zero.

kitaqgb/lib/save.c:125

c
u8 save_read(u8 slot, void* data, u16 len)
{
    u8* dst = (u8*)data;
    u16 base;
    u16 stored_len;
    u8 stored_sum;
    u16 i;

    if (slot >= SAVE_SLOT_COUNT) return 0;

    base = save_slot_base(slot);
    save_enable();

    if (save_read_abs(base + 0) != SAVE_MAGIC0) {
        save_disable();
        return 0;
    }
    if (save_read_abs(base + 1) != SAVE_MAGIC1) {
        save_disable();
        return 0;
    }
    if (save_read_abs(base + 2) != SAVE_VERSION) {
        save_disable();
        return 0;
    }

    stored_len = (u16)save_read_abs(base + 3);
    stored_len |= (u16)((u16)save_read_abs(base + 4) << 8);
    stored_sum = save_read_abs(base + 5);

    if (stored_len != len || stored_len > (u16)(SAVE_SLOT_SIZE - SAVE_HEADER_SIZE)) {
        save_disable();
        return 0;
    }
    if (save_checksum_ram((u16)(base + SAVE_HEADER_SIZE), stored_len) != stored_sum) {
        save_disable();
        return 0;
    }

    i = 0;
    while (i < stored_len) {
        dst[i] = save_read_abs((u16)(base + SAVE_HEADER_SIZE + i));
        i++;
    }

    save_disable();
    return 1;
}
save_write

슬롯에 데이터, 길이, 체크섬을 씁니다.

사용 형식

c
u8 save_write(u8 slot, const void* data, u16 len);

매개변수

slot

슬롯 번호 0~3입니다.

data

len바이트의 읽기 가능한 원본입니다.

len

데이터 길이는 0~506바이트입니다. 읽을 때는 저장된 길이와 정확히 일치해야 합니다.

반환값

인수가 유효하면 1, 슬롯이나 길이가 유효하지 않으면 0을 반환합니다. 다시 읽어 검증하지는 않습니다.

사용 조건과 제한

기본 구성은 512바이트 슬롯 4개이며, 각 슬롯은 6바이트 헤더와 최대 506바이트 데이터를 담습니다. 샘플은 8KiB SRAM이 있는 MBC5를 사용합니다. 호출이 끝나면 RAM을 비활성화하며, 이전 뱅크나 활성 상태로 복원하지 않습니다.

8비트 가산 체크섬으로 모든 손상을 탐지할 수는 없습니다. 전원 차단에 대해 쓰기의 원자성이 보장되지 않으므로, 성공 반환만으로 실제 영구 저장을 보장하지는 않습니다.

사용 예

c
payload[0]=7;payload[1]=42;payload[2]=255;result[1]=save_write(0,payload,3);result[2]=save_write(4,payload,3);result[3]=save_write(0,payload,507);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

7/42/255의 세 바이트를 저장한 뒤 길이 불일치, 잘못된 슬롯, 손상된 체크섬을 검사합니다. 불러오기에 성공하면 가운데 바이트는 42입니다. 읽기에 실패하면 대상의 77을 유지하며, 지운 뒤 검증하면 0을 반환합니다.

save_write: DMG
DMG
save_write: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_save.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_save.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=8k
구현과 소스

kitaqgb/lib/rpg.h:326

선언 주석 원문
Validate slot and payload length, write payload bytes, then write the header
and checksum. Return one after completing the writes; interruption can leave
a partially replaced slot, so this is not transactional save storage.

kitaqgb/lib/save.c:81

c
u8 save_write(u8 slot, const void* data, u16 len)
{
    const u8* src = (const u8*)data;
    u16 base;
    u16 i;
    u8 sum = 0;

    if (slot >= SAVE_SLOT_COUNT) return 0;
    if (len > (u16)(SAVE_SLOT_SIZE - SAVE_HEADER_SIZE)) return 0;

    base = save_slot_base(slot);
    save_enable();

    i = 0;
    while (i < len) {
        u8 v = src[i];
        save_write_abs((u16)(base + SAVE_HEADER_SIZE + i), v);
        sum = (u8)(sum + v);
        i++;
    }

    save_write_abs(base + 0, SAVE_MAGIC0);
    save_write_abs(base + 1, SAVE_MAGIC1);
    save_write_abs(base + 2, SAVE_VERSION);
    save_write_abs(base + 3, (u8)(len & 0xFF));
    save_write_abs(base + 4, (u8)(len >> 8));
    save_write_abs(base + 5, sum);

    save_disable();
    return 1;
}
script_run

스크립트를 선택하고 대기 횟수, 선택 결과, 저장된 복귀 위치를 초기화합니다.

사용 형식

c
void script_run(u8 bank, const u8* script);

매개변수

bank

명령 스트림의 ROM 뱅크입니다.

script

종료 명령이 있는 유효한 스트림의 시작 위치입니다. 이 호출은 명령을 실행하지 않고 실행 준비만 합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

연산 코드는 00 END, 01 TEXT(bank,ptr16), 02 SET_FLAG(id16), 03 CLEAR_FLAG(id16), 04 JUMP(bank,ptr16), 05 IF_FLAG(id16,bank,ptr16), 06 CHOICE(count,table16), 07 WAIT(n), 08 CALL_EVENT(bank,ptr16)입니다. 워드는 리틀 엔디언입니다. 문자열, 포인터 테이블, 명령을 매핑된 뱅크 안에서 읽을 수 있도록 유지하세요.

사용 예

c
flag_clear(19);script_run(1,(const u8*)&entry);result[0]=flag_get(19);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

뱅크 1에서 2로 점프하여 플래그 19를 설정하고 대기합니다. 처음 두 대기 호출은 1을 반환하고 대상 플래그는 1이 되며, WAIT 이후 완료는 2를 반환합니다. 이 플래그로 다른 뱅크에 제어가 도달했음을 확인합니다.

script_run: DMG
DMG
script_run: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_script.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_script.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:250

선언 주석 원문
Replace the active script and clear wait, choice and saved-return state.

kitaqgb/lib/script.c:105

c
void script_run(u8 bank, const u8* script)
{
    script_active = 1;
    script_bank = bank;
    script_pc = script;
    script_wait = 0;
    script_last_choice = 0xFF;
    script_return_active = 0;
}
script_step

출력, 선택, 대기, 완료 중 하나가 제어를 돌려줄 때까지 명령을 진행합니다.

사용 형식

c
u8 script_step();

반환값

0=TEXT/CHOICE의 제어 반환, 1=대기 중, 2=완료 또는 비활성입니다. 알 수 없는 연산 코드도 2로 종료합니다.

사용 조건과 제한

연산 코드는 00 END, 01 TEXT(bank,ptr16), 02 SET_FLAG(id16), 03 CLEAR_FLAG(id16), 04 JUMP(bank,ptr16), 05 IF_FLAG(id16,bank,ptr16), 06 CHOICE(count,table16), 07 WAIT(n), 08 CALL_EVENT(bank,ptr16)입니다. 워드는 리틀 엔디언입니다. 문자열, 포인터 테이블, 명령을 매핑된 뱅크 안에서 읽을 수 있도록 유지하세요.

WAIT n은 해독할 때 1을 반환한 뒤 n번 더 호출되는 동안 기다립니다. CALL_EVENT에는 저장된 복귀 위치가 한 칸뿐입니다. CHOICE는 0이 아닌 개수가 필요하며 선택할 때까지 내부에서 대기합니다. 제어를 돌려주지 않는 점프 루프는 게임 루프를 막으므로 종료 또는 제어 반환 명령에 반드시 도달하게 하세요.

사용 예

c
result[3]=script_step();result[4]=flag_get(19);result[5]=script_step();result[6]=script_step();result[7]=script_step();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

뱅크 1에서 2로 점프하여 플래그 19를 설정하고 대기합니다. 처음 두 대기 호출은 1을 반환하고 대상 플래그는 1이 되며, WAIT 이후 완료는 2를 반환합니다. 이 플래그로 다른 뱅크에 제어가 도달했음을 확인합니다.

script_step: DMG
DMG
script_step: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_script.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_script.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:254

선언 주석 원문
Execute commands until an output/choice yields (0), a wait yields (1), or
execution ends (2). Control/flag commands continue within the same call, so
a script loop without a yielding command can block the game loop indefinitely.

kitaqgb/lib/script.c:125

c
u8 script_step()
{
    if (script_active == 0) return 2;
    if (script_wait != 0) {
        script_wait--;
        return 1;
    }

    while (script_active != 0) {
        u8 op = script_read8();

        // An END returns to the one saved caller when present; otherwise it ends the script.
        if (op == SCRIPT_OP_END) {
            if (script_return_active != 0) {
                script_bank = script_return_bank;
                script_pc = script_return_pc;
                script_return_active = 0;
                continue;
            }
            script_active = 0;
            return 2;
        }

        if (op == SCRIPT_OP_TEXT) {
            u8 bank = script_read8();
            u16 ptr = script_read16();
            text_print_far(bank, (const u8*)ptr);
            return 0;
        }

        if (op == SCRIPT_OP_SET_FLAG) {
            u16 id = script_read16();
            flag_set(id);
            continue;
        }

        if (op == SCRIPT_OP_CLEAR_FLAG) {
            u16 id = script_read16();
            flag_clear(id);
            continue;
        }

        if (op == SCRIPT_OP_JUMP) {
            // Read all operands in the source bank before installing the destination.
            u8 bank = script_read8();
            u16 ptr = script_read16();
            script_bank = bank;
            script_pc = (const u8*)ptr;
            continue;
        }

        // Read all branch operands before switching bank/address so an untaken branch
        // still consumes the full instruction.
        if (op == SCRIPT_OP_IF_FLAG) {
            u16 id = script_read16();
            u8 bank = script_read8();
            u16 ptr = script_read16();
            if (flag_get(id) != 0) {
                script_bank = bank;
                script_pc = (const u8*)ptr;
            }
            continue;
        }

        if (op == SCRIPT_OP_CHOICE) {
            u8 count = script_read8();
            u16 table = script_read16();
            script_last_choice = script_choice(script_bank, (const u8*)table, count);
            return 0;
        }

        if (op == SCRIPT_OP_WAIT) {
            script_wait = script_read8();
            return 1;
        }

        // Save the continuation only when the single return slot is empty. Nested
        // calls replace the current script but do not push another return address.
        if (op == SCRIPT_OP_CALL_EVENT) {
            u8 bank = script_read8();
            u16 ptr = script_read16();
            if (script_return_active == 0) {
                script_return_active = 1;
                script_return_bank = script_bank;
                script_return_pc = script_pc;
            }
            script_bank = bank;
            script_pc = (const u8*)ptr;
            continue;
        }

        // Unknown opcodes terminate with the same return code as END; there is no distinct malformed-stream error.
        script_active = 0;
        return 2;
    }

    return 2;
}
script_wait_frames

다음 script_step 호출들이 지정한 횟수만큼 대기하게 합니다.

사용 형식

c
void script_wait_frames(u8 n);

매개변수

n

대기할 호출 횟수 0~255입니다. 0은 대기를 해제합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

script_step을 프레임마다 한 번 호출할 때만 프레임 수를 뜻합니다. 함수 자체는 VBlank를 기다리지 않습니다.

사용 예

c
script_wait_frames(2);result[1]=script_step();result[2]=script_step();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

뱅크 1에서 2로 점프하여 플래그 19를 설정하고 대기합니다. 처음 두 대기 호출은 1을 반환하고 대상 플래그는 1이 되며, WAIT 이후 완료는 2를 반환합니다. 이 플래그로 다른 뱅크에 제어가 도달했음을 확인합니다.

script_wait_frames: DMG
DMG
script_wait_frames: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_script.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_script.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:257

선언 주석 원문
Set the number of subsequent script_step calls to spend waiting. Frame-based
timing requires the application to call script_step once per frame.

kitaqgb/lib/script.c:117

c
void script_wait_frames(u8 n)
{
    script_wait = n;
}
text_choice

활성 텍스트 영역에 세로 목록을 그리고 선택을 기다립니다. UP/DOWN은 끝에서 순환하며 커서를 움직이고, A는 확정, B는 취소합니다. 루프는 선택지를 다시 그리고 VBlank 대기 후 한 번 입력을 읽습니다. 0부터 시작하는 인덱스를 반환하며, 취소 또는 빈 목록은 255입니다.

사용 형식

c
u8 text_choice(const u8* const* choices, u8 count);

매개변수

choices

count개의 읽기 가능한 문자열 포인터 배열을 가리킵니다. 각 문자열은 0으로 끝나며 원시 타일 ID를 담습니다. 선택지 이름은 대화 제어 코드를 해석하지 않습니다. 선택이 끝날 때까지 포인터 테이블과 문자열을 매핑 상태로 유지하세요.

count

선택지 수입니다. 0이면 포인터 테이블을 읽지 않고 즉시 255를 반환합니다. 비어 있지 않다면 내부에 최소 count행과 커서 한 칸 및 가장 긴 이름이 들어갈 너비가 필요합니다. 클리핑이나 스크롤은 하지 않습니다.

반환값

A로 확정하면 0~count−1 인덱스입니다. 255는 B 취소 또는 count=0을 뜻하므로 필요하면 호출 코드에서 구분하세요. 텍스트 영역을 닫거나 목록을 지우지는 않습니다.

사용 조건과 제한

유효한 BG 맵 사각형을 사용하고 글꼴·테두리 타일을 먼저 로드하세요. 소프트웨어 텍스트 영역은 LCDC 비트 3이 선택한 BG 맵을 사용하며 하드웨어 Window 레이어를 켜지 않습니다. CGB에서는 타일 번호에 VBK 0을 사용하고 색상 속성을 따로 설정하세요. 예제는 ASCII에 맞춘 글꼴, 테두리, 커서, 페이지 표시 타일을 제공합니다. 대화와 선택지 이름은 UTF-8을 해독하지 않고 바이트 크기의 타일 ID를 사용합니다. 제공 글꼴 밖의 문자를 표시하려면 글리프 타일을 제공하고 해당 ID로 텍스트를 인코딩하되, 대화 제어 바이트 값은 비워 두세요.

호출 전에 영역을 열고 크기를 설정하세요. 선택 함수는 열린 상태를 확인하지 않고 저장된 위치를 사용합니다. 이름은 왼쪽 가장자리에서 두 열, 위쪽에서 한 행 안쪽부터 시작하고 커서는 바로 왼쪽 셀을 사용합니다. 선택지 출력에는 대화 문자 속도 설정을 쓰지 않습니다.

입력 루프는 새로 누른 버튼에 반응하며 UP 다음 DOWN, A 다음 B 순서로 처리합니다. 방향을 계속 눌러도 반복 이동하지 않으므로 놓았다 다시 누르세요. 이전 버튼 마스크는 0에서 시작하므로 진입할 때 누르고 있던 버튼이 즉시 동작할 수 있습니다. 방향과 A를 동시에 누르면 이동한 인덱스를 반환하지만 마지막에 그린 커서는 이전 위치를 가리킬 수 있습니다.

이 도우미들은 블로킹 방식이므로 기다리는 동안 게임 갱신, 음악 서비스, 렌더링 루프를 호출하지 않습니다. LCD가 꺼져 있으면 __wait_vblank가 즉시 반환하므로 문자 속도와 WAIT는 프레임 지연을 만들지 않습니다. 시간 제어 대화와 프레임 간격 입력 검사에는 LCD를 켜 두세요. 대화 중 다른 작업도 진행해야 한다면 게임 측 상태 머신을 사용하세요.

하위의 안전한 타일 쓰기는 LCD가 켜져 있으면 쓰기 가능한 모드를 기다리고, 쓰기 전후에 DI/EI를 사용합니다. 처음에 인터럽트가 꺼져 있었어도 그 상태를 보존하지 않고 켤 수 있습니다. 이 블로킹 도우미를 인터럽트 처리기에서 호출하거나, 비활성 상태 보존을 기대하지 마세요.

각 전체 예제는 text.c를 한 번 포함합니다. 라이브러리와 매뉴얼 샘플의 include 디렉터리로 빌드하고, lib/text.c를 별도의 원본 입력으로 또 추가하지 마세요. 원거리 스트림 예제는 뱅크 2 데이터가 들어가도록 MBC5와 64KiB ROM을 사용합니다.

사용 예

c
selected=text_choice(dialogue_choices,3);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

DOWN을 한 번 누른 다음 A를 누르세요. 캡처한 실행에서는 오른쪽 화살표 커서가 타일 (2,4)의 SHIELD 옆에 있고 SELECTED는 1입니다. 세 이름은 (3,3), (3,4), (3,5)에서 시작합니다. 테두리·커서·이름은 CGB에서 초록색, DMG에서 검은색이며 결과와 안내는 검은색입니다.

에뮬레이터 검사는 BG 맵 전체 내용과 샘플 이미지 4개를 비교합니다. 추가 실행은 열기·닫기 상태, 일반·뱅크 제어 스트림, 시간 대기, 명시적·자동 페이지 대기, A/B/START 진행, 버튼 유지, 순환 선택, 빈 목록, 동시 입력 우선순위를 다룹니다. 스크립트 입력 전후의 체크포인트로 페이지 대기가 실제로 막는지 확인합니다. 실기와 인터럽트 동시성은 검증하지 않았습니다.

text_choice: DMG
DMG
text_choice: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_choice.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_choice.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:231

선언 주석 원문
Redraw choices and block for edge-triggered navigation: UP/DOWN wrap, A
accepts, and B returns 0xFF. Zero choices also returns 0xFF. Choice strings
use raw tile bytes, and the caller must fit them inside the available rows.

kitaqgb/lib/text.c:316

c
u8 text_choice(const u8* const* choices, u8 count)
{
    u8 cursor;
    u8 prev;

    if (count == 0) return 0xFF;

    cursor = 0;
    prev = 0;
    while (1) {
        u8 i;
        for (i = 0; i < count; i++) {
            u8 py = (u8)(text_y + 1 + i);
            __settile_xy((u8)(text_x + 1), py, (i == cursor) ? TEXT_TILE_CURSOR : TEXT_TILE_FILL);
            text_draw_string_at((u8)(text_x + 2), py, choices[i]);
        }

        __wait_vblank();
        {
            u16 kt = __readpadex(prev);
            u8 trigger;
            prev = (u8)kt;
            trigger = (u8)(kt >> 8);

            if ((trigger & PAD_KEY_UP) != 0) {
                if (cursor == 0) cursor = (u8)(count - 1);
                else cursor--;
            }
            if ((trigger & PAD_KEY_DOWN) != 0) {
                cursor++;
                if (cursor >= count) cursor = 0;
            }
            if ((trigger & PAD_KEY_A) != 0) return cursor;
            if ((trigger & PAD_KEY_B) != 0) return 0xFF;
        }
    }
}
text_clear_rect

배경 타일 맵의 직사각형 영역을 TEXT_TILE_FILL로 채웁니다. 레이블이나 숫자 필드를 지우거나 패널 일부를 비울 때 사용합니다. 활성 텍스트 커서를 이동하거나 텍스트 영역을 닫거나 크기를 바꾸지는 않습니다.

사용 형식

c
void text_clear_rect(u8 x, u8 y, u8 w, u8 h);

매개변수

x

8×8 배경 맵 칸 단위의 시작 열입니다. 출력 전체가 0~31열 안에 들어가야 합니다. 배경을 스크롤하지 않으면 0~19열이 보입니다.

y

8×8 배경 맵 칸 단위의 시작 행으로, 범위는 0~31입니다. 배경을 스크롤하지 않으면 0~17행이 보입니다. 직사각형은 세로 방향으로도 맵 안에 들어가야 합니다.

w

타일 칸 단위 너비입니다. text_window에서는 양쪽 테두리 열을 포함하므로 내부는 max(w−2, 0)열입니다. text_clear_rect에서는 각 행에서 채울 칸 수입니다.

h

타일 칸 단위 높이입니다. text_window에서는 위아래 테두리를 포함하므로 내부는 max(h−2, 0)행입니다. text_clear_rect에서는 채울 행 수입니다.

반환값

반환값은 없습니다. 반환 전에 타일 맵 칸에 기록하며, 문자 수나 상태 코드는 반환하지 않습니다.

사용 조건과 제한

LCDC 비트 3으로 선택한 BG 맵에 그립니다. 텍스트 창은 이 맵 위의 소프트웨어 텍스트 영역이며, 하드웨어 Window 레이어가 아닙니다. 타일 번호를 기록할 때 CGB VBK를 0으로 유지하세요. 이 호출들은 색상 속성, 팔레트, 스크롤을 설정하지 않습니다.

그리기 전에 글꼴과 테두리 그래픽을 불러오세요. 기본 테두리 ID는 1~6, 채우기 타일은 0이며, 십진 숫자는 ASCII 0(타일 48)부터 시작합니다. 빼기 기호는 ASCII -(타일 45)입니다. 샘플은 테두리 타일 여섯 개와 글리프 ID가 ASCII에 대응하는 매뉴얼용 글꼴을 제공합니다.

직사각형과 텍스트가 32×32 맵 안에 들어가도록 하세요. 직사각형 채우기는 너비나 높이를 맵 경계에 맞춰 자르지 않습니다. 너비나 높이가 0이면 아무것도 채우지 않지만, text_window는 사용할 수 있는 내부가 없는 열린 영역으로 기록합니다.

공개 숫자 출력 함수는 새 값에 꼭 필요한 너비만 사용합니다. 오른쪽에 남은 칸은 지우지 않습니다. 같은 위치의 12345 위에 7을 쓰면 72345가 표시됩니다. 7만 표시하려면 출력 전에 text_clear_rect로 예약한 다섯 칸 필드를 지우세요. 부호 있는 16비트 필드는 여섯 칸을 확보하세요.

타일 쓰기 내장 함수는 LCD 상태를 확인합니다. LCD가 꺼져 있으면 즉시 쓰고, 켜져 있으면 쓰기 가능한 LCD 모드를 기다린 뒤 쓰기 전후에 DI/EI를 사용합니다. 이 경로는 반환 시 인터럽트를 활성화할 수 있으므로 비활성 상태가 유지된다고 가정하지 마세요. 여기의 샘플과 바이트 단위 테스트는 LCD를 끈 상태에서 기록합니다.

완전한 샘플은 text.c를 한 번 포함하여 라이브러리 구현을 프로그램과 함께 컴파일합니다. 이 샘플에서 lib/text.c를 별도의 입력 파일로도 넘기지 마세요. TEXT_* 타일 상수를 바꾸려면 rpg.h와 구현 파일을 포함하기 전에 정의하고, 라이브러리를 컴파일하는 모든 곳에 같은 정의를 적용하세요.

사용 예

c
text_clear_rect(7,5,5,1);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

처음에는 테두리 안의 5행에 KEEP ERASE KEEP가 표시됩니다. (7,5)부터 다섯 칸을 지우면 ERASE만 없어지고 두 KEEP 레이블과 테두리는 남습니다. CLEAN 행도 다섯 칸 숫자 필드를 지운 뒤 7을 씁니다.

검증은 두 샘플 화면의 모든 가시 픽셀과 BG 맵 1024바이트 전체를 비교합니다. 별도의 DMG/CGB ROM으로 부호 없는 바이트 값 256개 전부, 십진 자릿수가 바뀌는 경계, 부호 있는 값의 양 끝을 확인하며, 각 숫자 옆의 점을 경계 감시용으로 유지합니다. 배치 검사는 빈 직사각형과 좁은 직사각형, 맵 가장자리 배치, 제어 코드 값의 타일 바이트를 그대로 쓰는 동작, 절대 위치 쓰기 후 창 커서를 포함합니다. 에뮬레이터 테스트이며 실기 테스트는 아닙니다.

text_clear_rect: DMG
DMG
text_clear_rect: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:237

선언 주석 원문
Fill the supplied tile rectangle without changing the active text window or cursor.

kitaqgb/lib/text.c:220

c
void text_clear_rect(u8 x, u8 y, u8 w, u8 h)
{
    __settile_rect(x, y, w, h, TEXT_TILE_FILL);
}
text_close

활성 텍스트 영역과 테두리를 TEXT_TILE_FILL로 지우고 닫힌 상태로 표시합니다. 닫힌 상태에서 다시 호출하면 아무 동작도 하지 않습니다. 영역을 열기 전에 있던 배경 타일을 복원하지는 않습니다.

사용 형식

c
void text_close();

반환값

반환값은 없습니다. 그리기나 블로킹 대기는 반환 전에 수행됩니다.

사용 조건과 제한

유효한 BG 맵 사각형을 사용하고 글꼴·테두리 타일을 먼저 로드하세요. 소프트웨어 텍스트 영역은 LCDC 비트 3이 선택한 BG 맵을 사용하며 하드웨어 Window 레이어를 켜지 않습니다. CGB에서는 타일 번호에 VBK 0을 사용하고 색상 속성을 따로 설정하세요. 예제는 ASCII에 맞춘 글꼴, 테두리, 커서, 페이지 표시 타일을 제공합니다. 대화와 선택지 이름은 UTF-8을 해독하지 않고 바이트 크기의 타일 ID를 사용합니다. 제공 글꼴 밖의 문자를 표시하려면 글리프 타일을 제공하고 해당 ID로 텍스트를 인코딩하되, 대화 제어 바이트 값은 비워 두세요.

영역이 닫혀 있거나 사용 가능한 내부 공간이 없으면 일반 문자는 무시합니다. 제어 바이트는 여전히 해석하므로 WAIT는 대기할 수 있고 페이지 제어는 대기하거나 저장된 영역을 지울 수 있습니다. 따라서 닫힌 영역에 대한 text_print가 항상 아무 동작도 하지 않는 것은 아닙니다.

이 도우미들은 블로킹 방식이므로 기다리는 동안 게임 갱신, 음악 서비스, 렌더링 루프를 호출하지 않습니다. LCD가 꺼져 있으면 __wait_vblank가 즉시 반환하므로 문자 속도와 WAIT는 프레임 지연을 만들지 않습니다. 시간 제어 대화와 프레임 간격 입력 검사에는 LCD를 켜 두세요. 대화 중 다른 작업도 진행해야 한다면 게임 측 상태 머신을 사용하세요.

하위의 안전한 타일 쓰기는 LCD가 켜져 있으면 쓰기 가능한 모드를 기다리고, 쓰기 전후에 DI/EI를 사용합니다. 처음에 인터럽트가 꺼져 있었어도 그 상태를 보존하지 않고 켤 수 있습니다. 이 블로킹 도우미를 인터럽트 처리기에서 호출하거나, 비활성 상태 보존을 기대하지 마세요.

각 전체 예제는 text.c를 한 번 포함합니다. 라이브러리와 매뉴얼 샘플의 include 디렉터리로 빌드하고, lib/text.c를 별도의 원본 입력으로 또 추가하지 마세요. 원거리 스트림 예제는 뱅크 2 데이터가 들어가도록 MBC5와 64KiB ROM을 사용합니다.

사용 예

c
text_close();
text_print("HIDDEN"); // With the area closed, ordinary characters are not drawn.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 (1,9)에 18×3셀 영역을 열어 ERASE ME를 쓴 뒤 닫고 HIDDEN 출력을 시도합니다. CLOSED AREA 아래 x=1~18, y=9~11 셀은 비어 있어야 하며 글자와 테두리 모두 남아 있으면 안 됩니다. 위의 파란 대화는 그대로 보입니다.

에뮬레이터 검사는 BG 맵 전체 내용과 샘플 이미지 4개를 비교합니다. 추가 실행은 열기·닫기 상태, 일반·뱅크 제어 스트림, 시간 대기, 명시적·자동 페이지 대기, A/B/START 진행, 버튼 유지, 순환 선택, 빈 목록, 동시 입력 우선순위를 다룹니다. 스크립트 입력 전후의 체크포인트로 페이지 대기가 실제로 막는지 확인합니다. 실기와 인터럽트 동시성은 검증하지 않았습니다.

text_close: DMG
DMG
text_close: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:220

선언 주석 원문
Erase the open window with the fill tile and disable windowed character output.

kitaqgb/lib/text.c:200

c
void text_close()
{
    if (text_opened == 0) return;
    __settile_rect(text_x, text_y, text_w, text_h, TEXT_TILE_FILL);
    text_opened = 0;
}
text_open

배경 맵에 소프트웨어 텍스트 영역을 엽니다. 위치와 크기를 저장하고 문자 커서를 첫 내부 셀로 옮긴 뒤 테두리를 그리고 내부를 지웁니다. 다른 영역을 열면 활성 영역과 커서가 바뀌지만, 맵의 다른 위치에 그려 둔 영역은 지워지지 않습니다.

사용 형식

c
void text_open(u8 x, u8 y, u8 w, u8 h);

매개변수

x

8×8 BG 맵 셀 단위의 가장 왼쪽 열입니다. 전체 너비가 0~31열 안에 들어가야 합니다.

y

8×8 BG 맵 셀 단위의 맨 위 행입니다. 전체 높이가 0~31행 안에 들어가야 합니다.

w

좌우 테두리를 포함한 전체 너비이며 셀 단위입니다. 내부 문자 한 열에는 최소 3셀이 필요합니다.

h

위아래 테두리를 포함한 전체 높이이며 셀 단위입니다. 내부 문자 한 행에는 최소 3셀이 필요합니다.

반환값

반환값은 없습니다. 그리기나 블로킹 대기는 반환 전에 수행됩니다.

사용 조건과 제한

유효한 BG 맵 사각형을 사용하고 글꼴·테두리 타일을 먼저 로드하세요. 소프트웨어 텍스트 영역은 LCDC 비트 3이 선택한 BG 맵을 사용하며 하드웨어 Window 레이어를 켜지 않습니다. CGB에서는 타일 번호에 VBK 0을 사용하고 색상 속성을 따로 설정하세요. 예제는 ASCII에 맞춘 글꼴, 테두리, 커서, 페이지 표시 타일을 제공합니다. 대화와 선택지 이름은 UTF-8을 해독하지 않고 바이트 크기의 타일 ID를 사용합니다. 제공 글꼴 밖의 문자를 표시하려면 글리프 타일을 제공하고 해당 ID로 텍스트를 인코딩하되, 대화 제어 바이트 값은 비워 두세요.

이 도우미들은 블로킹 방식이므로 기다리는 동안 게임 갱신, 음악 서비스, 렌더링 루프를 호출하지 않습니다. LCD가 꺼져 있으면 __wait_vblank가 즉시 반환하므로 문자 속도와 WAIT는 프레임 지연을 만들지 않습니다. 시간 제어 대화와 프레임 간격 입력 검사에는 LCD를 켜 두세요. 대화 중 다른 작업도 진행해야 한다면 게임 측 상태 머신을 사용하세요.

하위의 안전한 타일 쓰기는 LCD가 켜져 있으면 쓰기 가능한 모드를 기다리고, 쓰기 전후에 DI/EI를 사용합니다. 처음에 인터럽트가 꺼져 있었어도 그 상태를 보존하지 않고 켤 수 있습니다. 이 블로킹 도우미를 인터럽트 처리기에서 호출하거나, 비활성 상태 보존을 기대하지 마세요.

각 전체 예제는 text.c를 한 번 포함합니다. 라이브러리와 매뉴얼 샘플의 include 디렉터리로 빌드하고, lib/text.c를 별도의 원본 입력으로 또 추가하지 마세요. 원거리 스트림 예제는 뱅크 2 데이터가 들어가도록 MBC5와 64KiB ROM을 사용합니다.

사용 예

c
text_open(1,2,18,5);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

DIALOGUE FLOW는 (1,2)에 18×5셀 테두리를 열며 내부는 16×3셀입니다. 세 행에 NEAR, READY, BANK 2가 표시됩니다. 보이는 테두리 선은 픽셀 x=11~147, y=19~51에 걸칩니다. CGB에서는 테두리와 글자가 파란색, DMG에서는 검은색입니다. 뒤의 지우기 시험 영역을 열어도 이 테두리는 남습니다.

에뮬레이터 검사는 BG 맵 전체 내용과 샘플 이미지 4개를 비교합니다. 추가 실행은 열기·닫기 상태, 일반·뱅크 제어 스트림, 시간 대기, 명시적·자동 페이지 대기, A/B/START 진행, 버튼 유지, 순환 선택, 빈 목록, 동시 입력 우선순위를 다룹니다. 스크립트 입력 전후의 체크포인트로 페이지 대기가 실제로 막는지 확인합니다. 실기와 인터럽트 동시성은 검증하지 않았습니다.

text_open: DMG
DMG
text_open: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:218

선언 주석 원문
Set the tile-space window, reset its cursor and redraw it immediately.
Opening does not reset the existing character speed or load font tiles.

kitaqgb/lib/text.c:187

c
void text_open(u8 x, u8 y, u8 w, u8 h)
{
    text_x = x;
    text_y = y;
    text_w = w;
    text_h = h;
    text_opened = 1;
    text_reset_cursor();
    text_draw_frame();
    text_clear_inside();
}
text_print

일반 포인터로 제어 스트림을 읽고 활성 창 커서 위치에 문자 타일을 씁니다. 줄바꿈, 시간 대기, 페이지 대기를 해석하며 내부 너비에서 자동 줄바꿈합니다. END에 도달해야 반환하므로 페이지 대기는 버튼을 누를 때까지 호출을 막을 수 있습니다.

사용 형식

c
void text_print(const u8* str);

매개변수

str

TEXT_CTRL_END(0)로 끝나는 스트림의 읽기 가능한 포인터입니다. WAIT 뒤 피연산자를 포함한 스트림 전체가 대기 중에도 계속 매핑되어 있어야 합니다. 버퍼 길이나 유효성은 검사하지 않습니다.

반환값

반환값은 없습니다. 그리기나 블로킹 대기는 반환 전에 수행됩니다.

사용 조건과 제한

유효한 BG 맵 사각형을 사용하고 글꼴·테두리 타일을 먼저 로드하세요. 소프트웨어 텍스트 영역은 LCDC 비트 3이 선택한 BG 맵을 사용하며 하드웨어 Window 레이어를 켜지 않습니다. CGB에서는 타일 번호에 VBK 0을 사용하고 색상 속성을 따로 설정하세요. 예제는 ASCII에 맞춘 글꼴, 테두리, 커서, 페이지 표시 타일을 제공합니다. 대화와 선택지 이름은 UTF-8을 해독하지 않고 바이트 크기의 타일 ID를 사용합니다. 제공 글꼴 밖의 문자를 표시하려면 글리프 타일을 제공하고 해당 ID로 텍스트를 인코딩하되, 대화 제어 바이트 값은 비워 두세요.

제어 바이트는 0x00=스트림 종료, 0x0A=다음 내부 행으로 이동, 0x01=다음 바이트를 0을 포함한 VBlank 대기 횟수로 사용, 0x02=페이지 넘김 대기 후 내부를 지우고 커서를 초기화입니다. 다른 바이트는 타일 ID입니다. WAIT의 피연산자 0은 END 표식이 아닙니다.

줄바꿈이나 자동 줄바꿈으로 마지막 내부 행 아래로 내려가면 페이지 대기 표식을 표시하고 A/B/START를 기다린 뒤 내부를 지우고 첫 셀에서 재개합니다. 행을 스크롤하는 대신 페이지를 교체합니다. 명시적인 0x02는 표식을 추가하지 않고 기다립니다. 페이지 입력 검사는 기억된 버튼이 없는 상태로 시작하므로 대기 시작 시 이미 누른 버튼도 페이지를 넘길 수 있습니다.

영역이 닫혀 있거나 사용 가능한 내부 공간이 없으면 일반 문자는 무시합니다. 제어 바이트는 여전히 해석하므로 WAIT는 대기할 수 있고 페이지 제어는 대기하거나 저장된 영역을 지울 수 있습니다. 따라서 닫힌 영역에 대한 text_print가 항상 아무 동작도 하지 않는 것은 아닙니다.

이 도우미들은 블로킹 방식이므로 기다리는 동안 게임 갱신, 음악 서비스, 렌더링 루프를 호출하지 않습니다. LCD가 꺼져 있으면 __wait_vblank가 즉시 반환하므로 문자 속도와 WAIT는 프레임 지연을 만들지 않습니다. 시간 제어 대화와 프레임 간격 입력 검사에는 LCD를 켜 두세요. 대화 중 다른 작업도 진행해야 한다면 게임 측 상태 머신을 사용하세요.

하위의 안전한 타일 쓰기는 LCD가 켜져 있으면 쓰기 가능한 모드를 기다리고, 쓰기 전후에 DI/EI를 사용합니다. 처음에 인터럽트가 꺼져 있었어도 그 상태를 보존하지 않고 켤 수 있습니다. 이 블로킹 도우미를 인터럽트 처리기에서 호출하거나, 비활성 상태 보존을 기대하지 마세요.

각 전체 예제는 text.c를 한 번 포함합니다. 라이브러리와 매뉴얼 샘플의 include 디렉터리로 빌드하고, lib/text.c를 별도의 원본 입력으로 또 추가하지 마세요. 원거리 스트림 예제는 뱅크 2 데이터가 들어가도록 MBC5와 64KiB ROM을 사용합니다.

사용 예

c
text_print(dialogue_near);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

일반 스트림은 NEAR, 줄바꿈, READY, 12회 대기 명령을 쓰고 END로 끝납니다. NEAR는 타일 (2,3), READY는 (2,4)에서 시작합니다. 뒤의 뱅크 스트림은 같은 커서에서 이어 쓰므로 처음 줄바꿈을 하면 BANK 2가 내부 세 번째 행에 놓입니다.

에뮬레이터 검사는 BG 맵 전체 내용과 샘플 이미지 4개를 비교합니다. 추가 실행은 열기·닫기 상태, 일반·뱅크 제어 스트림, 시간 대기, 명시적·자동 페이지 대기, A/B/START 진행, 버튼 유지, 순환 선택, 빈 목록, 동시 입력 우선순위를 다룹니다. 스크립트 입력 전후의 체크포인트로 페이지 대기가 실제로 막는지 확인합니다. 실기와 인터럽트 동시성은 검증하지 않았습니다.

text_print: DMG
DMG
text_print: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:224

선언 주석 원문
Decode an END-terminated stream of tile bytes and newline/wait/page controls.
WAIT consumes a following frame-count byte. The source must remain readable
through blocking waits; the routine does not validate stream length.

kitaqgb/lib/text.c:261

c
void text_print(const u8* str)
{
    while (*str != TEXT_CTRL_END) {
        u8 c = *str++;
        if (c == TEXT_CTRL_NEWLINE) {
            text_newline();
            continue;
        }
        if (c == TEXT_CTRL_WAIT) {
            u8 frames = *str++;
            text_delay_frames(frames);
            continue;
        }
        if (c == TEXT_CTRL_PAGE_WAIT) {
            text_wait_advance();
            text_clear_inside();
            text_reset_cursor();
            continue;
        }
        text_put_tile(c);
    }
}
text_print_far

같은 대화 제어 스트림을 해석하되 __farpeek8로 지정 ROM 뱅크에서 바이트마다 읽습니다. 현재 원본 뱅크 밖에 저장된 대화에 사용하세요. 문자 배치, 속도, 줄바꿈, 페이지 제어는 text_print와 같습니다.

사용 형식

c
void text_print_far(u8 bank, const u8* str);

매개변수

bank

부호 없는 8비트 원본 ROM 뱅크 번호입니다. 예제는 스트림을 뱅크 2에 저장하고 출력 후에도 호출자가 뱅크 1의 표식을 읽을 수 있는지 확인합니다.

str

지정한 뱅크 안에서 스트림의 CPU 주소입니다. 주소는 증가하지만 뱅크 번호는 고정되므로 전환 가능한 ROM 창을 넘어도 다음 뱅크로 자동 이어지지 않습니다.

반환값

반환값은 없습니다. 그리기나 블로킹 대기는 반환 전에 수행됩니다.

사용 조건과 제한

유효한 BG 맵 사각형을 사용하고 글꼴·테두리 타일을 먼저 로드하세요. 소프트웨어 텍스트 영역은 LCDC 비트 3이 선택한 BG 맵을 사용하며 하드웨어 Window 레이어를 켜지 않습니다. CGB에서는 타일 번호에 VBK 0을 사용하고 색상 속성을 따로 설정하세요. 예제는 ASCII에 맞춘 글꼴, 테두리, 커서, 페이지 표시 타일을 제공합니다. 대화와 선택지 이름은 UTF-8을 해독하지 않고 바이트 크기의 타일 ID를 사용합니다. 제공 글꼴 밖의 문자를 표시하려면 글리프 타일을 제공하고 해당 ID로 텍스트를 인코딩하되, 대화 제어 바이트 값은 비워 두세요.

제어 바이트는 0x00=스트림 종료, 0x0A=다음 내부 행으로 이동, 0x01=다음 바이트를 0을 포함한 VBlank 대기 횟수로 사용, 0x02=페이지 넘김 대기 후 내부를 지우고 커서를 초기화입니다. 다른 바이트는 타일 ID입니다. WAIT의 피연산자 0은 END 표식이 아닙니다.

줄바꿈이나 자동 줄바꿈으로 마지막 내부 행 아래로 내려가면 페이지 대기 표식을 표시하고 A/B/START를 기다린 뒤 내부를 지우고 첫 셀에서 재개합니다. 행을 스크롤하는 대신 페이지를 교체합니다. 명시적인 0x02는 표식을 추가하지 않고 기다립니다. 페이지 입력 검사는 기억된 버튼이 없는 상태로 시작하므로 대기 시작 시 이미 누른 버튼도 페이지를 넘길 수 있습니다.

영역이 닫혀 있거나 사용 가능한 내부 공간이 없으면 일반 문자는 무시합니다. 제어 바이트는 여전히 해석하므로 WAIT는 대기할 수 있고 페이지 제어는 대기하거나 저장된 영역을 지울 수 있습니다. 따라서 닫힌 영역에 대한 text_print가 항상 아무 동작도 하지 않는 것은 아닙니다.

이 도우미들은 블로킹 방식이므로 기다리는 동안 게임 갱신, 음악 서비스, 렌더링 루프를 호출하지 않습니다. LCD가 꺼져 있으면 __wait_vblank가 즉시 반환하므로 문자 속도와 WAIT는 프레임 지연을 만들지 않습니다. 시간 제어 대화와 프레임 간격 입력 검사에는 LCD를 켜 두세요. 대화 중 다른 작업도 진행해야 한다면 게임 측 상태 머신을 사용하세요.

하위의 안전한 타일 쓰기는 LCD가 켜져 있으면 쓰기 가능한 모드를 기다리고, 쓰기 전후에 DI/EI를 사용합니다. 처음에 인터럽트가 꺼져 있었어도 그 상태를 보존하지 않고 켤 수 있습니다. 이 블로킹 도우미를 인터럽트 처리기에서 호출하거나, 비활성 상태 보존을 기대하지 마세요.

각 전체 예제는 text.c를 한 번 포함합니다. 라이브러리와 매뉴얼 샘플의 include 디렉터리로 빌드하고, lib/text.c를 별도의 원본 입력으로 또 추가하지 마세요. 원거리 스트림 예제는 뱅크 2 데이터가 들어가도록 MBC5와 64KiB ROM을 사용합니다.

사용 예

c
text_print_far(2,dialogue_far);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

샘플은 ROM 뱅크 2에서 줄바꿈과 BANK 2를 읽습니다. 이후 호출자의 뱅크 1 표식을 읽어 BANK RESTORED에 161을 표시합니다. BANK 2 행은 타일 (2,5)에서 시작하고, 복원 확인 숫자는 (16,14)에 나타납니다.

에뮬레이터 검사는 BG 맵 전체 내용과 샘플 이미지 4개를 비교합니다. 추가 실행은 열기·닫기 상태, 일반·뱅크 제어 스트림, 시간 대기, 명시적·자동 페이지 대기, A/B/START 진행, 버튼 유지, 순환 선택, 빈 목록, 동시 입력 우선순위를 다룹니다. 스크립트 입력 전후의 체크포인트로 페이지 대기가 실제로 막는지 확인합니다. 실기와 인터럽트 동시성은 검증하지 않았습니다.

text_print_far: DMG
DMG
text_print_far: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:227

선언 주석 원문
Decode the same text controls while fetching each byte from the specified
ROM bank. The pointer advances within that bank; it does not roll into the next bank.

kitaqgb/lib/text.c:286

c
void text_print_far(u8 bank, const u8* str)
{
    const u8* p = str;
    while (1) {
        u8 c = __farpeek8(bank, p);
        p++;
        if (c == TEXT_CTRL_END) return;
        if (c == TEXT_CTRL_NEWLINE) {
            text_newline();
            continue;
        }
        if (c == TEXT_CTRL_WAIT) {
            u8 frames = __farpeek8(bank, p);
            p++;
            text_delay_frames(frames);
            continue;
        }
        if (c == TEXT_CTRL_PAGE_WAIT) {
            text_wait_advance();
            text_clear_inside();
            text_reset_cursor();
            continue;
        }
        text_put_tile(c);
    }
}
text_print_s16

부호 있는 16비트 값을 십진수로 그립니다. 음수는 빼기 기호 타일 다음에 절댓값을 표시하며, 0과 양수에는 부호를 붙이지 않습니다. 가장 긴 출력은 -32768로, 여섯 칸을 사용합니다.

사용 형식

c
void text_print_s16(u8 x, u8 y, s16 value);

매개변수

x

8×8 배경 맵 칸 단위의 시작 열입니다. 출력 전체가 0~31열 안에 들어가야 합니다. 배경을 스크롤하지 않으면 0~19열이 보입니다.

y

8×8 배경 맵 칸 단위의 시작 행으로, 범위는 0~31입니다. 배경을 스크롤하지 않으면 0~17행이 보입니다. 직사각형은 세로 방향으로도 맵 안에 들어가야 합니다.

value

−32768~32767 범위의 부호 있는 값입니다. 샘플은 16비트 패턴 32768(0x8000)을 s16으로 캐스팅해 −32768을 표시합니다.

반환값

반환값은 없습니다. 반환 전에 타일 맵 칸에 기록하며, 문자 수나 상태 코드는 반환하지 않습니다.

사용 조건과 제한

LCDC 비트 3으로 선택한 BG 맵에 그립니다. 텍스트 창은 이 맵 위의 소프트웨어 텍스트 영역이며, 하드웨어 Window 레이어가 아닙니다. 타일 번호를 기록할 때 CGB VBK를 0으로 유지하세요. 이 호출들은 색상 속성, 팔레트, 스크롤을 설정하지 않습니다.

그리기 전에 글꼴과 테두리 그래픽을 불러오세요. 기본 테두리 ID는 1~6, 채우기 타일은 0이며, 십진 숫자는 ASCII 0(타일 48)부터 시작합니다. 빼기 기호는 ASCII -(타일 45)입니다. 샘플은 테두리 타일 여섯 개와 글리프 ID가 ASCII에 대응하는 매뉴얼용 글꼴을 제공합니다.

직사각형과 텍스트가 32×32 맵 안에 들어가도록 하세요. 직사각형 채우기는 너비나 높이를 맵 경계에 맞춰 자르지 않습니다. 너비나 높이가 0이면 아무것도 채우지 않지만, text_window는 사용할 수 있는 내부가 없는 열린 영역으로 기록합니다.

공개 숫자 출력 함수는 새 값에 꼭 필요한 너비만 사용합니다. 오른쪽에 남은 칸은 지우지 않습니다. 같은 위치의 12345 위에 7을 쓰면 72345가 표시됩니다. 7만 표시하려면 출력 전에 text_clear_rect로 예약한 다섯 칸 필드를 지우세요. 부호 있는 16비트 필드는 여섯 칸을 확보하세요.

타일 쓰기 내장 함수는 LCD 상태를 확인합니다. LCD가 꺼져 있으면 즉시 쓰고, 켜져 있으면 쓰기 가능한 LCD 모드를 기다린 뒤 쓰기 전후에 DI/EI를 사용합니다. 이 경로는 반환 시 인터럽트를 활성화할 수 있으므로 비활성 상태가 유지된다고 가정하지 마세요. 여기의 샘플과 바이트 단위 테스트는 LCD를 끈 상태에서 기록합니다.

완전한 샘플은 text.c를 한 번 포함하여 라이브러리 구현을 프로그램과 함께 컴파일합니다. 이 샘플에서 lib/text.c를 별도의 입력 파일로도 넘기지 마세요. TEXT_* 타일 상수를 바꾸려면 rpg.h와 구현 파일을 포함하기 전에 정의하고, 라이브러리를 컴파일하는 모든 곳에 같은 정의를 적용하세요.

사용 예

c
text_print_s16(11,12,(s16)32768);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

S16 행은 (11,12)부터 빼기 기호를 포함한 여섯 칸에 -32768을 표시하며, CGB에서는 초록색입니다. 절댓값을 양수 s16으로 표현할 수 없는 부호 있는 16비트 최솟값을 다룹니다.

검증은 두 샘플 화면의 모든 가시 픽셀과 BG 맵 1024바이트 전체를 비교합니다. 별도의 DMG/CGB ROM으로 부호 없는 바이트 값 256개 전부, 십진 자릿수가 바뀌는 경계, 부호 있는 값의 양 끝을 확인하며, 각 숫자 옆의 점을 경계 감시용으로 유지합니다. 배치 검사는 빈 직사각형과 좁은 직사각형, 맵 가장자리 배치, 제어 코드 값의 타일 바이트를 그대로 쓰는 동작, 절대 위치 쓰기 후 창 커서를 포함합니다. 에뮬레이터 테스트이며 실기 테스트는 아닙니다.

text_print_s16: DMG
DMG
text_print_s16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:247

선언 주석 원문
Print a minus tile for negative values, followed by the unsigned magnitude.
Positive values use the unsigned decimal path; no plus sign is emitted.

kitaqgb/lib/text.c:246

c
void text_print_s16(u8 x, u8 y, s16 value)
{
    u16 magnitude;
    if (value < 0) {
        __settile_xy(x, y, (u8)'-');
        magnitude = (u16)((s16)0 - value);
        text_print_u16_width((u8)(x + 1), y, magnitude, text_dec_digits_u16(magnitude));
        return;
    }
    text_print_u16(x, y, (u16)value);
}
text_print_u16

지정한 타일 위치부터 부호 없는 16비트 값을 십진수로 그립니다. 앞에 0을 붙이지 않고 1~5칸을 사용합니다. 점수나 아이템 개수처럼 255를 넘을 수 있는 값에 사용하세요.

사용 형식

c
void text_print_u16(u8 x, u8 y, u16 value);

매개변수

x

8×8 배경 맵 칸 단위의 시작 열입니다. 출력 전체가 0~31열 안에 들어가야 합니다. 배경을 스크롤하지 않으면 0~19열이 보입니다.

y

8×8 배경 맵 칸 단위의 시작 행으로, 범위는 0~31입니다. 배경을 스크롤하지 않으면 0~17행이 보입니다. 직사각형은 세로 방향으로도 맵 안에 들어가야 합니다.

value

0~65535 범위의 부호 없는 값입니다.

반환값

반환값은 없습니다. 반환 전에 타일 맵 칸에 기록하며, 문자 수나 상태 코드는 반환하지 않습니다.

사용 조건과 제한

LCDC 비트 3으로 선택한 BG 맵에 그립니다. 텍스트 창은 이 맵 위의 소프트웨어 텍스트 영역이며, 하드웨어 Window 레이어가 아닙니다. 타일 번호를 기록할 때 CGB VBK를 0으로 유지하세요. 이 호출들은 색상 속성, 팔레트, 스크롤을 설정하지 않습니다.

그리기 전에 글꼴과 테두리 그래픽을 불러오세요. 기본 테두리 ID는 1~6, 채우기 타일은 0이며, 십진 숫자는 ASCII 0(타일 48)부터 시작합니다. 빼기 기호는 ASCII -(타일 45)입니다. 샘플은 테두리 타일 여섯 개와 글리프 ID가 ASCII에 대응하는 매뉴얼용 글꼴을 제공합니다.

직사각형과 텍스트가 32×32 맵 안에 들어가도록 하세요. 직사각형 채우기는 너비나 높이를 맵 경계에 맞춰 자르지 않습니다. 너비나 높이가 0이면 아무것도 채우지 않지만, text_window는 사용할 수 있는 내부가 없는 열린 영역으로 기록합니다.

공개 숫자 출력 함수는 새 값에 꼭 필요한 너비만 사용합니다. 오른쪽에 남은 칸은 지우지 않습니다. 같은 위치의 12345 위에 7을 쓰면 72345가 표시됩니다. 7만 표시하려면 출력 전에 text_clear_rect로 예약한 다섯 칸 필드를 지우세요. 부호 있는 16비트 필드는 여섯 칸을 확보하세요.

타일 쓰기 내장 함수는 LCD 상태를 확인합니다. LCD가 꺼져 있으면 즉시 쓰고, 켜져 있으면 쓰기 가능한 LCD 모드를 기다린 뒤 쓰기 전후에 DI/EI를 사용합니다. 이 경로는 반환 시 인터럽트를 활성화할 수 있으므로 비활성 상태가 유지된다고 가정하지 마세요. 여기의 샘플과 바이트 단위 테스트는 LCD를 끈 상태에서 기록합니다.

완전한 샘플은 text.c를 한 번 포함하여 라이브러리 구현을 프로그램과 함께 컴파일합니다. 이 샘플에서 lib/text.c를 별도의 입력 파일로도 넘기지 마세요. TEXT_* 타일 상수를 바꾸려면 rpg.h와 구현 파일을 포함하기 전에 정의하고, 라이브러리를 컴파일하는 모든 곳에 같은 정의를 적용하세요.

사용 예

c
text_print_u16(11,10,65535);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

U16 행은 (11,10)에 다섯 칸을 사용해 65535를 표시하며, CGB에서는 파란색입니다. OVERWRITE에는 다섯 칸 필드를 먼저 지우지 않고 12345 위에 7을 써서 72345가 표시됩니다.

검증은 두 샘플 화면의 모든 가시 픽셀과 BG 맵 1024바이트 전체를 비교합니다. 별도의 DMG/CGB ROM으로 부호 없는 바이트 값 256개 전부, 십진 자릿수가 바뀌는 경계, 부호 있는 값의 양 끝을 확인하며, 각 숫자 옆의 점을 경계 감시용으로 유지합니다. 배치 검사는 빈 직사각형과 좁은 직사각형, 맵 가장자리 배치, 제어 코드 값의 타일 바이트를 그대로 쓰는 동작, 절대 위치 쓰기 후 창 커서를 포함합니다. 에뮬레이터 테스트이며 실기 테스트는 아닙니다.

text_print_u16: DMG
DMG
text_print_u16: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:244

선언 주석 원문
Print an unsigned word in decimal using only the required number of cells.

kitaqgb/lib/text.c:239

c
void text_print_u16(u8 x, u8 y, u16 value)
{
    text_print_u16_width(x, y, value, text_dec_digits_u16(value));
}
text_print_u8

지정한 타일 위치부터 부호 없는 8비트 값을 십진수로 그립니다. 앞에 0을 붙이지 않고 1~3칸을 사용하며, 값 0은 한 칸입니다. 목숨이나 탄약 수처럼 작은 카운터에 적합합니다.

사용 형식

c
void text_print_u8(u8 x, u8 y, u8 value);

매개변수

x

8×8 배경 맵 칸 단위의 시작 열입니다. 출력 전체가 0~31열 안에 들어가야 합니다. 배경을 스크롤하지 않으면 0~19열이 보입니다.

y

8×8 배경 맵 칸 단위의 시작 행으로, 범위는 0~31입니다. 배경을 스크롤하지 않으면 0~17행이 보입니다. 직사각형은 세로 방향으로도 맵 안에 들어가야 합니다.

value

0~255 범위의 부호 없는 값입니다. 더 넓은 타입의 식은 함수 매개변수에서 u8로 변환됩니다.

반환값

반환값은 없습니다. 반환 전에 타일 맵 칸에 기록하며, 문자 수나 상태 코드는 반환하지 않습니다.

사용 조건과 제한

LCDC 비트 3으로 선택한 BG 맵에 그립니다. 텍스트 창은 이 맵 위의 소프트웨어 텍스트 영역이며, 하드웨어 Window 레이어가 아닙니다. 타일 번호를 기록할 때 CGB VBK를 0으로 유지하세요. 이 호출들은 색상 속성, 팔레트, 스크롤을 설정하지 않습니다.

그리기 전에 글꼴과 테두리 그래픽을 불러오세요. 기본 테두리 ID는 1~6, 채우기 타일은 0이며, 십진 숫자는 ASCII 0(타일 48)부터 시작합니다. 빼기 기호는 ASCII -(타일 45)입니다. 샘플은 테두리 타일 여섯 개와 글리프 ID가 ASCII에 대응하는 매뉴얼용 글꼴을 제공합니다.

직사각형과 텍스트가 32×32 맵 안에 들어가도록 하세요. 직사각형 채우기는 너비나 높이를 맵 경계에 맞춰 자르지 않습니다. 너비나 높이가 0이면 아무것도 채우지 않지만, text_window는 사용할 수 있는 내부가 없는 열린 영역으로 기록합니다.

공개 숫자 출력 함수는 새 값에 꼭 필요한 너비만 사용합니다. 오른쪽에 남은 칸은 지우지 않습니다. 같은 위치의 12345 위에 7을 쓰면 72345가 표시됩니다. 7만 표시하려면 출력 전에 text_clear_rect로 예약한 다섯 칸 필드를 지우세요. 부호 있는 16비트 필드는 여섯 칸을 확보하세요.

타일 쓰기 내장 함수는 LCD 상태를 확인합니다. LCD가 꺼져 있으면 즉시 쓰고, 켜져 있으면 쓰기 가능한 LCD 모드를 기다린 뒤 쓰기 전후에 DI/EI를 사용합니다. 이 경로는 반환 시 인터럽트를 활성화할 수 있으므로 비활성 상태가 유지된다고 가정하지 마세요. 여기의 샘플과 바이트 단위 테스트는 LCD를 끈 상태에서 기록합니다.

완전한 샘플은 text.c를 한 번 포함하여 라이브러리 구현을 프로그램과 함께 컴파일합니다. 이 샘플에서 lib/text.c를 별도의 입력 파일로도 넘기지 마세요. TEXT_* 타일 상수를 바꾸려면 rpg.h와 구현 파일을 포함하기 전에 정의하고, 라이브러리를 컴파일하는 모든 곳에 같은 정의를 적용하세요.

사용 예

c
text_print_u8(11,8,255);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

U8 행은 (11,8)부터 정확히 세 칸에 255를 표시합니다. CGB에서는 파란색입니다. OVERWRITE와 CLEAN 행은 더 짧은 값으로 바꿀 때 필드를 명시적으로 지워야 하는 이유를 보여 줍니다.

검증은 두 샘플 화면의 모든 가시 픽셀과 BG 맵 1024바이트 전체를 비교합니다. 별도의 DMG/CGB ROM으로 부호 없는 바이트 값 256개 전부, 십진 자릿수가 바뀌는 경계, 부호 있는 값의 양 끝을 확인하며, 각 숫자 옆의 점을 경계 감시용으로 유지합니다. 배치 검사는 빈 직사각형과 좁은 직사각형, 맵 가장자리 배치, 제어 코드 값의 타일 바이트를 그대로 쓰는 동작, 절대 위치 쓰기 후 창 커서를 포함합니다. 에뮬레이터 테스트이며 실기 테스트는 아닙니다.

text_print_u8: DMG
DMG
text_print_u8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:242

선언 주석 원문
Print an unsigned byte in decimal using only the required number of cells.

kitaqgb/lib/text.c:233

c
void text_print_u8(u8 x, u8 y, u8 value)
{
    text_print_u16_width(x, y, (u16)value, text_dec_digits_u16((u16)value));
}
text_print_xy

절대 배경 맵 좌표에서 시작해 0으로 끝나는 타일 번호열을 가로로 그립니다. 창 경계 자르기, 자동 줄 바꿈, 텍스트 제어 코드 해석, 문자별 지연을 적용하지 않습니다. text_print가 사용하는 커서도 이동하지 않습니다.

사용 형식

c
void text_print_xy(u8 x, u8 y, const u8* str);

매개변수

x

8×8 배경 맵 칸 단위의 시작 열입니다. 출력 전체가 0~31열 안에 들어가야 합니다. 배경을 스크롤하지 않으면 0~19열이 보입니다.

y

8×8 배경 맵 칸 단위의 시작 행으로, 범위는 0~31입니다. 배경을 스크롤하지 않으면 0~17행이 보입니다. 직사각형은 세로 방향으로도 맵 안에 들어가야 합니다.

str

0으로 끝나는 타일 바이트열의 읽기 가능한 포인터입니다. 각 바이트를 타일 번호로 그대로 사용합니다. ASCII 문자열은 해당 타일 ID에 알맞은 글리프가 있을 때만 문자로 표시됩니다. 호출이 반환될 때까지 원본을 매핑된 읽기 가능한 상태로 유지하세요. 이 함수들은 UTF-8을 해석하거나 글리프를 불러오지 않습니다. 멀티바이트 텍스트를 표시하려면 게임에서 정의한 인코딩과 이에 대응하는 타일 데이터를 먼저 준비해야 합니다.

반환값

반환값은 없습니다. 반환 전에 타일 맵 칸에 기록하며, 문자 수나 상태 코드는 반환하지 않습니다.

사용 조건과 제한

LCDC 비트 3으로 선택한 BG 맵에 그립니다. 텍스트 창은 이 맵 위의 소프트웨어 텍스트 영역이며, 하드웨어 Window 레이어가 아닙니다. 타일 번호를 기록할 때 CGB VBK를 0으로 유지하세요. 이 호출들은 색상 속성, 팔레트, 스크롤을 설정하지 않습니다.

그리기 전에 글꼴과 테두리 그래픽을 불러오세요. 기본 테두리 ID는 1~6, 채우기 타일은 0이며, 십진 숫자는 ASCII 0(타일 48)부터 시작합니다. 빼기 기호는 ASCII -(타일 45)입니다. 샘플은 테두리 타일 여섯 개와 글리프 ID가 ASCII에 대응하는 매뉴얼용 글꼴을 제공합니다.

직사각형과 텍스트가 32×32 맵 안에 들어가도록 하세요. 직사각형 채우기는 너비나 높이를 맵 경계에 맞춰 자르지 않습니다. 너비나 높이가 0이면 아무것도 채우지 않지만, text_window는 사용할 수 있는 내부가 없는 열린 영역으로 기록합니다.

타일 쓰기 내장 함수는 LCD 상태를 확인합니다. LCD가 꺼져 있으면 즉시 쓰고, 켜져 있으면 쓰기 가능한 LCD 모드를 기다린 뒤 쓰기 전후에 DI/EI를 사용합니다. 이 경로는 반환 시 인터럽트를 활성화할 수 있으므로 비활성 상태가 유지된다고 가정하지 마세요. 여기의 샘플과 바이트 단위 테스트는 LCD를 끈 상태에서 기록합니다.

완전한 샘플은 text.c를 한 번 포함하여 라이브러리 구현을 프로그램과 함께 컴파일합니다. 이 샘플에서 lib/text.c를 별도의 입력 파일로도 넘기지 마세요. TEXT_* 타일 상수를 바꾸려면 rpg.h와 구현 파일을 포함하기 전에 정의하고, 라이브러리를 컴파일하는 모든 곳에 같은 정의를 적용하세요.

사용 예

c
text_print_xy(2,3,"HELLO!");

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

HELLO!는 CGB의 빨간 테두리 안쪽, 타일 (2,3), 픽셀 (16,24)에서 시작합니다. BG 맵의 절대 위치이므로 텍스트 영역을 열어도 x나 y에 오프셋이 더해지지 않습니다.

검증은 두 샘플 화면의 모든 가시 픽셀과 BG 맵 1024바이트 전체를 비교합니다. 별도의 DMG/CGB ROM으로 부호 없는 바이트 값 256개 전부, 십진 자릿수가 바뀌는 경계, 부호 있는 값의 양 끝을 확인하며, 각 숫자 옆의 점을 경계 감시용으로 유지합니다. 배치 검사는 빈 직사각형과 좁은 직사각형, 맵 가장자리 배치, 제어 코드 값의 타일 바이트를 그대로 쓰는 동작, 절대 위치 쓰기 후 창 커서를 포함합니다. 에뮬레이터 테스트이며 실기 테스트는 아닙니다.

text_print_xy: DMG
DMG
text_print_xy: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:240

선언 주석 원문
Draw a zero-terminated tile string at absolute tile coordinates, without
window clipping, control codes or the windowed printing delay.

kitaqgb/lib/text.c:227

c
void text_print_xy(u8 x, u8 y, const u8* str)
{
    text_draw_string_at(x, y, str);
}
text_set_speed

text_print 또는 text_print_far가 일반 문자를 쓴 뒤 수행할 VBlank 대기 횟수를 설정합니다. 0이면 문자별 대기를 생략합니다. 영역을 열거나 닫아도 이 설정은 초기화되지 않습니다. 문자 속도가 0이어도 명시적인 WAIT 명령은 대기합니다.

사용 형식

c
void text_set_speed(u8 speed);

매개변수

speed

문자마다 표시 후 수행할 VBlank 대기 횟수 0~255입니다. 밀리초가 아니라 대기 횟수입니다. text_print_xy, 숫자 도우미, 선택 목록에는 영향을 주지 않습니다.

반환값

반환값은 없습니다. 그리기나 블로킹 대기는 반환 전에 수행됩니다.

사용 조건과 제한

유효한 BG 맵 사각형을 사용하고 글꼴·테두리 타일을 먼저 로드하세요. 소프트웨어 텍스트 영역은 LCDC 비트 3이 선택한 BG 맵을 사용하며 하드웨어 Window 레이어를 켜지 않습니다. CGB에서는 타일 번호에 VBK 0을 사용하고 색상 속성을 따로 설정하세요. 예제는 ASCII에 맞춘 글꼴, 테두리, 커서, 페이지 표시 타일을 제공합니다. 대화와 선택지 이름은 UTF-8을 해독하지 않고 바이트 크기의 타일 ID를 사용합니다. 제공 글꼴 밖의 문자를 표시하려면 글리프 타일을 제공하고 해당 ID로 텍스트를 인코딩하되, 대화 제어 바이트 값은 비워 두세요.

이 도우미들은 블로킹 방식이므로 기다리는 동안 게임 갱신, 음악 서비스, 렌더링 루프를 호출하지 않습니다. LCD가 꺼져 있으면 __wait_vblank가 즉시 반환하므로 문자 속도와 WAIT는 프레임 지연을 만들지 않습니다. 시간 제어 대화와 프레임 간격 입력 검사에는 LCD를 켜 두세요. 대화 중 다른 작업도 진행해야 한다면 게임 측 상태 머신을 사용하세요.

하위의 안전한 타일 쓰기는 LCD가 켜져 있으면 쓰기 가능한 모드를 기다리고, 쓰기 전후에 DI/EI를 사용합니다. 처음에 인터럽트가 꺼져 있었어도 그 상태를 보존하지 않고 켤 수 있습니다. 이 블로킹 도우미를 인터럽트 처리기에서 호출하거나, 비활성 상태 보존을 기대하지 마세요.

각 전체 예제는 text.c를 한 번 포함합니다. 라이브러리와 매뉴얼 샘플의 include 디렉터리로 빌드하고, lib/text.c를 별도의 원본 입력으로 또 추가하지 마세요. 원거리 스트림 예제는 뱅크 2 데이터가 들어가도록 MBC5와 64KiB ROM을 사용합니다.

사용 예

c
text_set_speed(2);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

흐름 예제는 일반·뱅크 대화에 속도 2를 사용하고 WAIT 피연산자 12를 포함합니다. 완성 이미지는 대기를 마친 뒤의 글자이며, 별도 프레임 추적으로 속도 3, 명시적인 5회 대기, 닫힌 상태의 4회 대기를 검사합니다. 마지막 스크린샷만으로 타이밍을 검증하지는 않습니다.

에뮬레이터 검사는 BG 맵 전체 내용과 샘플 이미지 4개를 비교합니다. 추가 실행은 열기·닫기 상태, 일반·뱅크 제어 스트림, 시간 대기, 명시적·자동 페이지 대기, A/B/START 진행, 버튼 유지, 순환 선택, 빈 목록, 동시 입력 우선순위를 다룹니다. 스크립트 입력 전후의 체크포인트로 페이지 대기가 실제로 막는지 확인합니다. 실기와 인터럽트 동시성은 검증하지 않았습니다.

text_set_speed: DMG
DMG
text_set_speed: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\dialogue_flow.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\dialogue_flow.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:233

선언 주석 원문
Set VBlank waits per windowed character; zero prints without character delays.

kitaqgb/lib/text.c:208

c
void text_set_speed(u8 speed)
{
    text_speed = speed;
}
text_window

배경 타일 맵에 테두리가 있는 텍스트 영역을 그리고, 창 안에 출력할 때 사용할 활성 영역으로 설정합니다. text_open의 별칭으로, 창 커서를 내부 첫 칸으로 되돌리고 테두리를 다시 그린 뒤 내부를 지웁니다. 현재 문자 출력 지연은 유지합니다.

사용 형식

c
void text_window(u8 x, u8 y, u8 w, u8 h);

매개변수

x

8×8 배경 맵 칸 단위의 시작 열입니다. 출력 전체가 0~31열 안에 들어가야 합니다. 배경을 스크롤하지 않으면 0~19열이 보입니다.

y

8×8 배경 맵 칸 단위의 시작 행으로, 범위는 0~31입니다. 배경을 스크롤하지 않으면 0~17행이 보입니다. 직사각형은 세로 방향으로도 맵 안에 들어가야 합니다.

w

타일 칸 단위 너비입니다. text_window에서는 양쪽 테두리 열을 포함하므로 내부는 max(w−2, 0)열입니다. text_clear_rect에서는 각 행에서 채울 칸 수입니다.

h

타일 칸 단위 높이입니다. text_window에서는 위아래 테두리를 포함하므로 내부는 max(h−2, 0)행입니다. text_clear_rect에서는 채울 행 수입니다.

반환값

반환값은 없습니다. 반환 전에 타일 맵 칸에 기록하며, 문자 수나 상태 코드는 반환하지 않습니다.

사용 조건과 제한

LCDC 비트 3으로 선택한 BG 맵에 그립니다. 텍스트 창은 이 맵 위의 소프트웨어 텍스트 영역이며, 하드웨어 Window 레이어가 아닙니다. 타일 번호를 기록할 때 CGB VBK를 0으로 유지하세요. 이 호출들은 색상 속성, 팔레트, 스크롤을 설정하지 않습니다.

그리기 전에 글꼴과 테두리 그래픽을 불러오세요. 기본 테두리 ID는 1~6, 채우기 타일은 0이며, 십진 숫자는 ASCII 0(타일 48)부터 시작합니다. 빼기 기호는 ASCII -(타일 45)입니다. 샘플은 테두리 타일 여섯 개와 글리프 ID가 ASCII에 대응하는 매뉴얼용 글꼴을 제공합니다.

직사각형과 텍스트가 32×32 맵 안에 들어가도록 하세요. 직사각형 채우기는 너비나 높이를 맵 경계에 맞춰 자르지 않습니다. 너비나 높이가 0이면 아무것도 채우지 않지만, text_window는 사용할 수 있는 내부가 없는 열린 영역으로 기록합니다.

타일 쓰기 내장 함수는 LCD 상태를 확인합니다. LCD가 꺼져 있으면 즉시 쓰고, 켜져 있으면 쓰기 가능한 LCD 모드를 기다린 뒤 쓰기 전후에 DI/EI를 사용합니다. 이 경로는 반환 시 인터럽트를 활성화할 수 있으므로 비활성 상태가 유지된다고 가정하지 마세요. 여기의 샘플과 바이트 단위 테스트는 LCD를 끈 상태에서 기록합니다.

완전한 샘플은 text.c를 한 번 포함하여 라이브러리 구현을 프로그램과 함께 컴파일합니다. 이 샘플에서 lib/text.c를 별도의 입력 파일로도 넘기지 마세요. TEXT_* 타일 상수를 바꾸려면 rpg.h와 구현 파일을 포함하기 전에 정의하고, 라이브러리를 컴파일하는 모든 곳에 같은 정의를 적용하세요.

사용 예

c
text_window(1,2,18,5);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

샘플은 (1,2)에 18×5칸 영역을 열며, 내부는 16×3칸입니다. 제공된 테두리의 선 두께는 1픽셀이고, 바깥쪽에 보이는 선은 x=11~147, y=19~51픽셀에 걸쳐 있습니다. CGB에서는 빨간색, DMG에서는 검은색입니다.

검증은 두 샘플 화면의 모든 가시 픽셀과 BG 맵 1024바이트 전체를 비교합니다. 별도의 DMG/CGB ROM으로 부호 없는 바이트 값 256개 전부, 십진 자릿수가 바뀌는 경계, 부호 있는 값의 양 끝을 확인하며, 각 숫자 옆의 점을 경계 감시용으로 유지합니다. 배치 검사는 빈 직사각형과 좁은 직사각형, 맵 가장자리 배치, 제어 코드 값의 타일 바이트를 그대로 쓰는 동작, 절대 위치 쓰기 후 창 커서를 포함합니다. 에뮬레이터 테스트이며 실기 테스트는 아닙니다.

text_window: DMG
DMG
text_window: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\text_layout.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\text_layout.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:235

선언 주석 원문
Open and redraw a window using the same tile-space arguments as text_open.

kitaqgb/lib/text.c:214

c
void text_window(u8 x, u8 y, u8 w, u8 h)
{
    text_open(x, y, w, h);
}
unit_attack_range

맨해튼 거리가 atk_min부터 atk_max까지인 셀을 표시합니다. 양 끝값도 포함합니다.

사용 형식

c
u8 unit_attack_range(unit_t* u, u8* out_mask);

매개변수

u

유효한 unit_t입니다. 셀 위치, 단계 수 단위의 move, 양 끝을 포함하는 atk_min/atk_max 범위, 행동 가능 여부에 쓰는 hp와 acted를 담습니다.

out_mask

쓰기 가능한 width*height바이트입니다. 셀마다 0 또는 1을 받습니다.

반환값

맵을 사용할 수 있으면 1, 크기가 0이면 0을 반환합니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

장애물, 시야, 아군 유닛은 무시합니다. 평가할 거리는 255 이하로 유지하세요. 최소 사거리가 최대 사거리보다 크면 모든 셀이 0이 됩니다.

사용 예

c
result[46]=unit_attack_range(&hero,mask);result[47]=mask[12];result[48]=mask[14];

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

unit_attack_range: DMG
DMG
unit_attack_range: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:352

선언 주석 원문
Mark cells whose Manhattan distance falls within the inclusive attack range.
This geometric mask does not test obstacles, line of sight or other units.

kitaqgb/lib/slg_unit.c:38

c
u8 unit_attack_range(unit_t* u, u8* out_mask)
{
    u8 w = map_current_width();
    u8 h = map_current_height();
    u8 y;

    if (w == 0 || h == 0) return 0;

    __memset(out_mask, 0, (u16)((u16)w * (u16)h));
    y = 0;
    while (y < h) {
        u8 x = 0;
        while (x < w) {
            u8 dist = __manhattan(u->x, u->y, x, y);
            if (dist >= u->atk_min && dist <= u->atk_max) {
                out_mask[__map_index(x, y, w)] = 1;
            }
            x++;
        }
        y++;
    }
    return 1;
}
unit_can_act

유닛에 HP가 남아 있고 아직 행동하지 않았는지 확인합니다.

사용 형식

c
u8 unit_can_act(const unit_t* u);

매개변수

u

유효한 unit_t입니다. 셀 위치, 단계 수 단위의 move, 양 끝을 포함하는 atk_min/atk_max 범위, 행동 가능 여부에 쓰는 hp와 acted를 담습니다.

반환값

hp가 0이 아니고 acted가 0이면 1, 아니면 0을 반환합니다. 유닛은 변경하지 않습니다.

사용 예

c
result[11]=unit_can_act(&hero);hero.acted=1;result[12]=unit_can_act(&hero);hero.acted=0;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

unit_can_act: DMG
DMG
unit_can_act: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:355

선언 주석 원문
A unit can act only while HP is nonzero and its acted flag is clear.
The unit pointer must refer to a valid record.

kitaqgb/lib/slg_unit.c:5

c
u8 unit_can_act(const unit_t* u)
{
    if (u->hp == 0) return 0;
    if (u->acted != 0) return 0;
    return 1;
}
unit_move_range

유닛의 이동 허용량 안에서 도달할 수 있는 셀의 마스크를 만듭니다.

사용 형식

c
u8 unit_move_range(unit_t* u, u8* out_mask);

매개변수

u

유효한 unit_t입니다. 셀 위치, 단계 수 단위의 move, 양 끝을 포함하는 atk_min/atk_max 범위, 행동 가능 여부에 쓰는 hp와 acted를 담습니다.

out_mask

쓰기 가능한 width*height바이트입니다. 셀마다 0 또는 1을 받습니다.

반환값

맵을 사용할 수 있으면 1, 크기가 0이면 0을 반환합니다. 유닛의 출발점은 맵 안에 있어야 합니다.

사용 조건과 제한

좌표는 현재 맵의 셀을 가리킵니다. 일반 타일은 8×8픽셀, 메타타일은 16×16픽셀입니다.

탐색에는 약 4KiB의 공유 작업 공간을 사용하며 재진입할 수 없습니다. 맵은 1024셀, 탐색 거리는 254 이하로 제한하세요. 거리 0xFF는 미도달을 뜻하므로 255단계 경로는 표현할 수 없습니다. 비용·마스크 출력에는 width*height바이트의 쓰기 가능한 공간이 필요합니다.

출발점은 막혀 있어도 도달 가능한 셀로 초기화합니다. HP, acted, 다른 유닛은 이동 마스크에 영향을 주지 않습니다.

사용 예

c
result[43]=unit_move_range(&hero,mask);result[44]=mask[12];result[45]=mask[14];

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

왼쪽 격자는 세 걸음 이내의 이동 비용, 오른쪽은 S에서 G까지의 최단 경로를 보여 줍니다. 초록 별표는 빨간 세 칸 벽을 우회하는 아홉 걸음을 나타내며, 파란 숫자는 비용입니다. DMG는 같은 배치를 검은색으로 표시합니다. RAM 검사에서는 공격 마스크가 벽을 무시하는 것도 확인합니다.

unit_move_range: DMG
DMG
unit_move_range: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch3_map_path.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch3_map_path.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k --ramsize=none
구현과 소스

kitaqgb/lib/rpg.h:349

선언 주석 원문
Build movement costs, then convert reachable cells to one and unreachable
0xFF cells to zero. The caller provides one output byte per current-map cell
and a valid unit origin; path-search workspace limits also apply.

kitaqgb/lib/slg_unit.c:15

c
u8 unit_move_range(unit_t* u, u8* out_mask)
{
    u8 w = map_current_width();
    u8 h = map_current_height();
    u16 total;
    u16 i;

    if (w == 0 || h == 0) return 0;

    // A valid origin is required: the fill leaves storage unchanged on invalid origins, but this loop still converts it.
    range_fill_move(u->x, u->y, u->move, out_mask);
    total = (u16)((u16)w * (u16)h);
    i = 0;
    while (i < total) {
        out_mask[i] = (u8)((out_mask[i] == 0xFF) ? 0 : 1);
        i++;
    }
    return 1;
}
weighted_choice

상대적인 바이트 가중치 목록에서 항목 인덱스를 고릅니다. 가중치를 합하고 rng16 한 번의 값을 합계로 나눈 나머지를 구한 뒤, 그 값을 포함하는 첫 누적 구간을 찾습니다. 가중치 [1, 3, 6]이면 인덱스 0, 1, 2의 구간은 각각 0, 1–3, 4–9입니다.

사용 형식

c
u8 weighted_choice(const u8* weights, u8 count);

매개변수

weights

읽기 가능한 u8 가중치 count개를 가리키는 포인터입니다. 배열은 변경하지 않습니다. 합계가 양수이면 가중치 0인 항목은 건너뜁니다. count == 0이면 포인터를 읽지 않으므로 null이어도 됩니다. 그 외에는 유효한 배열을 전달하세요.

count

가중치 수 0–255입니다. 최대 255개의 255를 더해도 65025이므로 함수의 u16 누산기에 들어갑니다. 함수는 목록을 훑어 합계를 구한 뒤 선택된 구간을 찾을 때까지 다시 훑습니다.

반환값

합계가 양수이면 바이트를 두 번 추출한 뒤 0부터 count−1까지의 인덱스를 반환합니다. count가 0이거나 모든 가중치가 0이면 추출 없이 0을 반환합니다. 이 대체값은 인덱스 0의 정상 선택과 구별할 수 없으므로 구별이 필요하면 빈 목록이나 전부 0인 목록을 직접 검사하세요.

사용 조건과 제한

가중치는 관찰되는 백분율을 보장하는 것이 아니라 구간의 상대 크기를 정합니다. 실제 빈도에는 rng16 출력 분포와 합계로 나누는 나머지 연산이 모두 영향을 줍니다. 합계가 양수이면 가중치가 0이 아닌 항목이 하나뿐이어도 항상 바이트를 두 번 추출합니다.

이 호출들은 지속되는 상태를 공유합니다. 재현하려면 대상 기종, 시드, 다른 보조 함수가 호출하는 경우를 포함한 호출 순서가 같아야 합니다. 시드 설정과 추출은 한 실행 문맥에서 수행하세요. 이 검증은 인터럽트 핸들러에서의 안전한 동시 사용을 입증하지 않습니다.

GB와 FC는 서로 다른 알고리즘을 사용하므로 같은 시드에 같은 수열을 보장하지 않습니다. 게임용 결정적 생성기이며 암호학적 난수원이 아닙니다. 테스트는 구현 동작을 검사하며 통계적 품질이나 주기를 검사하지 않습니다.

라이브러리 함수를 사용할 때는 rpg.h를 포함하고 게임과 함께 lib/rng.c를 컴파일하세요. __rng_seed와 __rng8 내장 함수는 컴파일러가 직접 생성하므로 이 둘만 쓰는 프로그램에는 rng.c 오브젝트가 필요 없습니다.

사용 예

c
weights[0]=1;weights[1]=3;weights[2]=6;
rng_seed(0x1234);
chosen=weighted_choice(weights,3); // 546 % 10 = 6 selects index 2.
empty=weighted_choice((const u8*)0,0); // No items: 0 is a fallback, not a chosen item.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

세 항목에 가중치 1, 3, 6을 주는 샘플입니다. 시드로 얻은 워드 546의 나머지는 6으로, 인덱스 2의 구간 4–9에 속하므로 WEIGHT INDEX는 00002입니다. EMPTY LIST의 00000은 빈 목록 대체값이며 항목 0을 정상적으로 선택한 것이 아닙니다.

전체 프로그램은 흰 배경에 십진수 결과를 표시합니다. DMG는 검은 글자, CGB는 파란 글자입니다. FAILED는 00000이어야 합니다. 그림은 이 샘플의 실제 에뮬레이터 출력입니다.

검증에서는 독립적인 호스트 모델과 사례별 출력 32개 및 후속 바이트 추출 8개를 비교했습니다. GB 93사례와 FC 18사례로, 상수·런타임 시드와 GB의 범위·확률·가중치 경곗값을 포함합니다. 학습용 화면은 에뮬레이터 240프레임 후 검사했습니다. 실기와 통계적 품질은 시험하지 않았습니다.

weighted_choice: DMG
DMG
weighted_choice: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\rng_choices.c .\kitaqgb\lib\rng.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\rng_choices.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/rpg.h:203

선언 주석 원문
Select an index from cumulative byte weights using a 16-bit random draw.
A zero total, including an empty list, returns zero; callers must distinguish
that case from a valid index. Modulo reduction can introduce a small bias.

kitaqgb/lib/rng.c:61

c
u8 weighted_choice(const u8* weights, u8 count)
{
    u8 i;
    u16 total;
    u16 pick;
    u16 acc;

    // At most 255 byte weights sum to 65025, so this accumulator fits u16.
    // A nonempty list requires count readable weight bytes.
    total = 0;
    i = 0;
    while (i < count) {
        total = (u16)(total + (u16)weights[i]);
        i++;
    }

    if (total == 0) return 0;

    pick = (u16)(rng16() % total);
    acc = 0;
    i = 0;
    while (i < count) {
        acc = (u16)(acc + (u16)weights[i]);
        if (pick < acc) return i;
        i++;
    }

    return (u8)(count - 1);
}

scene.h — 장면 등록, 전환, 갱신

장면 테이블의 enter, update, draw, exit 처리 함수를 호출하여 타이틀 화면과 게임 화면 등의 장면을 전환합니다.

scene_change

현재 활성 장면이 있으면 종료하고, 지정한 장면으로 진입합니다.

사용 형식

c
void scene_change(u8 scene_id);

매개변수

scene_id

진입할 장면의 인덱스입니다. 범위는 0부터 count−1까지입니다.

반환값

반환값은 없습니다.

사용 조건과 제한

범위를 벗어난 ID는 무시합니다. 유효한 전환에서는 exit를 실행하고 새 ID와 변경 플래그를 저장한 다음 enter를 실행합니다. 같은 ID를 선택해도 exit와 enter를 실행합니다. 장면 테이블의 소유권은 호출자에게 있습니다. 사용하는 동안 테이블과 일반 함수 포인터가 가리키는 함수를 유효하게 유지하세요. null 콜백은 건너뜁니다. enter/exit 콜백 안에서 재귀적으로 장면을 전환하거나 테이블을 교체하지 마세요.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
scene_change(0);scene_change(9);result[11]=events;result[12]=scene_was_changed();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

장면 0을 활성화하고, 유효하지 않은 ID 9를 무시하며, 0→1 전환과 1→1 재진입을 수행하여 콜백 순서를 확인합니다.

scene_change: DMG
DMG
scene_change: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scene.h:20

선언 주석 원문
Ignore invalid IDs; otherwise exit the current scene and enter the requested one.
Selecting the current ID still performs exit/enter. Callbacks run synchronously.

kitaqgb/lib/scene.c:27

c
void scene_change(u8 scene_id)
{
    SceneFunc fn;

    if (scene_id >= scene_count) return;

    // Exit/enter handlers must not recursively change scenes or replace this shared table.
    if (scene_has_current != 0) {
        fn = scene_table[(__safe_index u8)scene_current].exit;
        if (fn != 0) fn();
    }

    scene_current = scene_id;
    scene_has_current = 1;
    scene_changed = 1;

    fn = scene_table[(__safe_index u8)scene_current].enter;
    if (fn != 0) fn();
}
scene_draw

활성 장면의 draw 콜백을 한 번 호출합니다.

사용 형식

c
void scene_draw();

반환값

반환값은 없습니다.

사용 조건과 제한

활성 장면이 없거나 draw 콜백이 null이면 아무 동작도 하지 않습니다. 변경 플래그는 지우지 않습니다. 화면 데이터 전송과 프레임 타이밍은 콜백 또는 이를 호출하는 게임 루프에서 관리하세요. 장면 테이블의 소유권은 호출자에게 있습니다. 사용하는 동안 테이블과 일반 함수 포인터가 가리키는 함수를 유효하게 유지하세요. null 콜백은 건너뜁니다. enter/exit 콜백 안에서 재귀적으로 장면을 전환하거나 테이블을 교체하지 마세요.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
scene_draw();result[15]=events;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이벤트 열에는 장면 0의 draw에서 기록한 12와 장면 1의 draw에서 기록한 22가 포함됩니다.

scene_draw: DMG
DMG
scene_draw: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scene.h:25

선언 주석 원문
Call the active scene's draw handler if one exists; no current scene is a no-op.

kitaqgb/lib/scene.c:60

c
void scene_draw()
{
    SceneFunc fn;

    if (scene_has_current == 0) return;
    fn = scene_table[(__safe_index u8)scene_current].draw;
    if (fn != 0) fn();
}
scene_get_current

저장된 현재 장면 ID를 읽습니다.

사용 형식

c
u8 scene_get_current();

반환값

저장된 8비트 ID를 반환합니다. 초기화 직후에도 이 값은 0입니다.

사용 조건과 제한

반환값이 0이라는 사실만으로는 장면 0이 활성 상태인지 알 수 없습니다. 초기화 후 첫 scene_change() 호출이 있었는지 별도로 관리하세요.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
result[16]=scene_get_current();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

장면 0을 활성화한 뒤에는 0, 장면 1로 전환한 뒤에는 1이 읽히는 것을 확인합니다.

scene_get_current: DMG
DMG
scene_get_current: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scene.h:27

선언 주석 원문
Return the stored scene ID; zero is also returned before the first transition.

kitaqgb/lib/scene.c:70

c
u8 scene_get_current()
{
    return scene_current;
}
scene_init

활성 장면 없이 장면 테이블을 등록합니다.

사용 형식

c
void scene_init(const SceneDef* scenes, u8 count);

매개변수

scenes

enter, update, draw, exit 콜백을 담은 SceneDef 항목의 배열입니다.

count

항목 수입니다. 0이면 유효한 장면 ID가 없습니다.

반환값

반환값은 없습니다.

사용 조건과 제한

저장된 ID와 변경 플래그를 0으로 초기화합니다. enter는 호출하지 않습니다. 장면을 활성화하려면 scene_change()를 사용하세요. 장면 테이블의 소유권은 호출자에게 있습니다. 사용하는 동안 테이블과 일반 함수 포인터가 가리키는 함수를 유효하게 유지하세요. null 콜백은 건너뜁니다. enter/exit 콜백 안에서 재귀적으로 장면을 전환하거나 테이블을 교체하지 마세요.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
scene_init(scenes,2);scene_update();scene_draw();result[9]=events;result[10]=scene_was_changed();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

두 장면을 등록하고, 장면을 활성화하기 전에 update와 draw를 호출해도 이벤트가 발생하지 않는지 확인하는 샘플입니다.

scene_init: DMG
DMG
scene_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scene.h:15

선언 주석 원문
Attach the caller-owned scene table and clear current-scene state without invoking callbacks.

kitaqgb/lib/scene.c:10

c
void scene_init(const SceneDef* scenes, u8 count)
{
    scene_table = scenes;
    scene_count = count;
    scene_current = 0;
    scene_changed = 0;
    scene_has_current = 0;
}
scene_set_table

장면 테이블을 교체하고 활성 장면이 없는 상태로 만듭니다.

사용 형식

c
void scene_set_table(const SceneDef* scenes, u8 count);

매개변수

scenes

enter, update, draw, exit 콜백을 담은 SceneDef 항목의 배열입니다.

count

항목 수입니다. 0이면 유효한 장면 ID가 없습니다.

반환값

반환값은 없습니다.

사용 조건과 제한

scene_init()과 같이 상태를 초기화하며, 이전 exit 콜백이나 새 enter 콜백을 호출하지 않습니다. 장면 테이블의 소유권은 호출자에게 있습니다. 사용하는 동안 테이블과 일반 함수 포인터가 가리키는 함수를 유효하게 유지하세요. null 콜백은 건너뜁니다. enter/exit 콜백 안에서 재귀적으로 장면을 전환하거나 테이블을 교체하지 마세요.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
scene_set_table(scenes,2);result[23]=events;result[24]=scene_was_changed();scene_draw();result[25]=events;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

이벤트가 9개 발생한 뒤 테이블을 교체해도 이벤트 수는 9로 유지됩니다. 변경 플래그는 0이 되고, 이후 draw를 호출해도 아무 동작도 하지 않습니다.

scene_set_table: DMG
DMG
scene_set_table: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scene.h:17

선언 주석 원문
Replace the table by resetting scene state; this does not call the old scene's exit handler.

kitaqgb/lib/scene.c:20

c
void scene_set_table(const SceneDef* scenes, u8 count)
{
    scene_init(scenes, count);
}
scene_update

활성 장면의 update 콜백을 한 번 호출합니다.

사용 형식

c
void scene_update();

반환값

반환값은 없습니다.

사용 조건과 제한

활성 장면이 없으면 아무 동작도 하지 않습니다. 활성 장면이 있으면 콜백 호출 전에 변경 플래그를 지웁니다. 따라서 update 안에서 발생한 전환은 호출이 끝난 뒤에도 플래그로 확인할 수 있습니다. 장면 테이블의 소유권은 호출자에게 있습니다. 사용하는 동안 테이블과 일반 함수 포인터가 가리키는 함수를 유효하게 유지하세요. null 콜백은 건너뜁니다. enter/exit 콜백 안에서 재귀적으로 장면을 전환하거나 테이블을 교체하지 마세요.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
scene_update();result[13]=events;result[14]=scene_was_changed();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

장면 0의 update는 이벤트 11을 기록합니다. 일반적인 이 갱신을 마치면 변경 플래그는 1에서 0으로 바뀝니다.

scene_update: DMG
DMG
scene_update: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scene.h:23

선언 주석 원문
Clear the change flag before calling the active scene's update handler, so a
transition made during that handler is visible afterward.

kitaqgb/lib/scene.c:49

c
void scene_update()
{
    SceneFunc fn;

    if (scene_has_current == 0) return;
    scene_changed = 0;
    fn = scene_table[(__safe_index u8)scene_current].update;
    if (fn != 0) fn();
}
scene_was_changed

장면 전환이 현재 기록되어 있는지 읽습니다.

사용 형식

c
u8 scene_was_changed();

반환값

전환 플래그가 설정되어 있으면 1, 아니면 0을 반환합니다.

사용 조건과 제한

읽기만으로 플래그가 지워지지는 않습니다. 초기화, 테이블 교체, 활성 장면의 update 시작 시 플래그를 지웁니다. 유효하지 않은 장면 ID는 플래그를 바꾸지 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
result[17]=scene_was_changed();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

전환 직후에는 1, 일반적인 update 후에는 0, 테이블 교체 후에는 0인지 확인합니다.

scene_was_changed: DMG
DMG
scene_was_changed: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scene.h:29

선언 주석 원문
Read the transition flag, which is cleared at the start of an active scene update.

kitaqgb/lib/scene.c:76

c
u8 scene_was_changed()
{
    return scene_changed;
}

scroll.h — 배경·윈도·분할 스크롤

배경·윈도우의 즉시 및 버퍼 스크롤과 최대 8개의 래스터 분할을 제어합니다. getter가 관리하는 현재값, 실제 하드웨어 레지스터, 보류값을 구별하세요.

Scroll_BgAdd

추적 중인 배경 좌표에 부호 있는 변위를 더하고 즉시 적용합니다.

사용 형식

c
void Scroll_BgAdd(s8 dx, s8 dy);

매개변수

dx

부호 있는 가로 픽셀 변위이며, 범위는 −128~127입니다.

dy

부호 있는 세로 픽셀 변위이며, 범위는 −128~127입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

대기하지 않습니다. 즉시 설정·가산 함수는 영향을 받는 보류 좌표 쌍을 현재값과 동기화하고 변경 플래그를 지웁니다. 한 축만 즉시 설정해도 같은 좌표 쌍의 다른 축에 있던 보류값이 취소됩니다. 결과는 256을 법으로 순환합니다. 가산은 보류값이나 임시 래스터 레지스터 값이 아니라 추적 중인 현재값에서 시작합니다. 이 함수는 __scroll_bg_add의 래퍼입니다.

사용 예

c
Scroll_BgAdd(-20,3);result[22]=M_SCX;result[23]=M_SCY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_BgAdd: DMG
DMG
Scroll_BgAdd: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_BgAdd: DMG
DMG
Scroll_BgAdd: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:73

선언 주석 원문
Apply signed deltas to the byte-sized background-scroll coordinates.

kitaqgb/lib/scroll.c:41

c
void Scroll_BgAdd(s8 dx, s8 dy) { __scroll_bg_add(dx, dy); }
Scroll_Flush

변경된 배경·윈도우 좌표를 추적 상태와 하드웨어에 반영하고 보류 플래그를 지웁니다.

사용 형식

c
void Scroll_Flush();

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

변경되지 않은 좌표 쌍은 그대로 둡니다. 인터럽트를 마스킹하거나 VBlank를 기다리지 않으므로 필요한 타이밍은 호출자가 맞춰야 합니다. 이 함수는 __scroll_flush의 래퍼입니다.

사용 예

c
Scroll_Flush();result[18]=M_SCX;result[19]=M_SCY;result[20]=M_WX;result[21]=M_WY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_Flush: DMG
DMG
Scroll_Flush: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_Flush: DMG
DMG
Scroll_Flush: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:70

선언 주석 원문
Apply the buffered scroll/window state through the compiler runtime.

kitaqgb/lib/scroll.c:38

c
void Scroll_Flush() { __scroll_flush(); }
Scroll_GetBgX

라이브러리가 추적하는 현재 가로 배경 스크롤 값을 읽습니다.

사용 형식

c
u8 Scroll_GetBgX();

반환값

추적 중인 현재 바이트 값(0~255)을 반환합니다. WX에는 하드웨어의 7픽셀 오프셋이 포함됩니다.

사용 조건과 제한

하드웨어 레지스터를 읽는 기능이 아닙니다. 아직 반영하지 않은 버퍼 값, 레지스터에 직접 쓴 값, 래스터 분할에서 임시로 적용한 값은 포함하지 않습니다. 이 함수는 __scroll_bg_x_get의 래퍼입니다.

사용 예

c
result[6]=Scroll_GetBgX();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_GetBgX: DMG
DMG
Scroll_GetBgX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_GetBgX: DMG
DMG
Scroll_GetBgX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:50

선언 주석 원문
Read the tracked current background X; this is not a direct SCX register read.

kitaqgb/lib/scroll.c:18

c
u8 Scroll_GetBgX() { return __scroll_bg_x_get(); }
Scroll_GetBgY

라이브러리가 추적하는 현재 세로 배경 스크롤 값을 읽습니다.

사용 형식

c
u8 Scroll_GetBgY();

반환값

추적 중인 현재 바이트 값(0~255)을 반환합니다. WX에는 하드웨어의 7픽셀 오프셋이 포함됩니다.

사용 조건과 제한

하드웨어 레지스터를 읽는 기능이 아닙니다. 아직 반영하지 않은 버퍼 값, 레지스터에 직접 쓴 값, 래스터 분할에서 임시로 적용한 값은 포함하지 않습니다. 이 함수는 __scroll_bg_y_get의 래퍼입니다.

사용 예

c
result[7]=Scroll_GetBgY();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_GetBgY: DMG
DMG
Scroll_GetBgY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_GetBgY: DMG
DMG
Scroll_GetBgY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:52

선언 주석 원문
Read the tracked current background Y; pending and raster-only values are excluded.

kitaqgb/lib/scroll.c:20

c
u8 Scroll_GetBgY() { return __scroll_bg_y_get(); }
Scroll_GetWindowX

라이브러리가 추적하는 현재 윈도우 WX 값을 읽습니다.

사용 형식

c
u8 Scroll_GetWindowX();

반환값

추적 중인 현재 바이트 값(0~255)을 반환합니다. WX에는 하드웨어의 7픽셀 오프셋이 포함됩니다.

사용 조건과 제한

하드웨어 레지스터를 읽는 기능이 아닙니다. 아직 반영하지 않은 버퍼 값, 레지스터에 직접 쓴 값, 래스터 분할에서 임시로 적용한 값은 포함하지 않습니다. 이 함수는 __scroll_win_x_get의 래퍼입니다.

사용 예

c
result[12]=Scroll_GetWindowX();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_GetWindowX: DMG
DMG
Scroll_GetWindowX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_GetWindowX: DMG
DMG
Scroll_GetWindowX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:61

선언 주석 원문
Read tracked current WX, including its seven-pixel offset; not a live hardware read.

kitaqgb/lib/scroll.c:29

c
u8 Scroll_GetWindowX() { return __scroll_win_x_get(); }
Scroll_GetWindowY

라이브러리가 추적하는 현재 윈도우 WY 값을 읽습니다.

사용 형식

c
u8 Scroll_GetWindowY();

반환값

추적 중인 현재 바이트 값(0~255)을 반환합니다. WX에는 하드웨어의 7픽셀 오프셋이 포함됩니다.

사용 조건과 제한

하드웨어 레지스터를 읽는 기능이 아닙니다. 아직 반영하지 않은 버퍼 값, 레지스터에 직접 쓴 값, 래스터 분할에서 임시로 적용한 값은 포함하지 않습니다. 이 함수는 __scroll_win_y_get의 래퍼입니다.

사용 예

c
result[13]=Scroll_GetWindowY();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_GetWindowY: DMG
DMG
Scroll_GetWindowY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_GetWindowY: DMG
DMG
Scroll_GetWindowY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:63

선언 주석 원문
Read tracked current WY; pending and raster-only values are excluded.

kitaqgb/lib/scroll.c:31

c
u8 Scroll_GetWindowY() { return __scroll_win_y_get(); }
Scroll_Init

배경 스크롤을 (0,0), 윈도우 위치를 WX=7, WY=0으로 초기화합니다.

사용 형식

c
void Scroll_Init();

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

현재 좌표와 보류 좌표를 동기화합니다. 윈도우 표시 상태나 분할 테이블은 초기화하지 않습니다.

사용 예

c
Scroll_Init();result[0]=M_SCX;result[1]=M_SCY;result[2]=M_WX;result[3]=M_WY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_Init: DMG
DMG
Scroll_Init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_Init: DMG
DMG
Scroll_Init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:42

선언 주석 원문
Reset background scroll to zero and place the window at screen origin
using hardware WX=7 and WY=0.

kitaqgb/lib/scroll.c:5

c
void Scroll_Init()
{
    __scroll_bg_set(0, 0);
    __scroll_win_set(7, 0);
}
Scroll_SetBg

두 배경 스크롤 좌표를 즉시 설정합니다.

사용 형식

c
void Scroll_SetBg(u8 scx, u8 scy);

매개변수

scx

가로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 왼쪽으로 이동합니다.

scy

세로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 위쪽으로 이동합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

__scroll_bg_set의 래퍼입니다. VBlank를 기다리지 않고 현재값, 보류값, 하드웨어값을 동기화하고 BG 변경 플래그를 지웁니다.

사용 예

c
Scroll_SetBg(8,16);result[28]=M_SCX;result[29]=M_SCY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_SetBg: DMG
DMG
Scroll_SetBg: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_SetBg: DMG
DMG
Scroll_SetBg: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:44

선언 주석 원문
Write both hardware background-scroll bytes immediately.

kitaqgb/lib/scroll.c:12

c
void Scroll_SetBg(u8 scx, u8 scy) { __scroll_bg_set(scx, scy); }
Scroll_SetBgBuffered

두 배경 스크롤 좌표를 나중에 반영할 값으로 저장합니다.

사용 형식

c
void Scroll_SetBgBuffered(u8 scx, u8 scy);

매개변수

scx

가로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 왼쪽으로 이동합니다.

scy

세로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 위쪽으로 이동합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

추적 중인 현재값이나 레지스터는 변경하지 않습니다. __scroll_flush 또는 Scroll_Flush로 반영하세요. 값을 저장하는 이 단계는 VBlank를 기다리지 않습니다. 이 함수는 __scroll_bg_set_buffered의 래퍼입니다.

사용 예

c
Scroll_SetBgBuffered(16,24);result[14]=M_SCX;result[15]=Scroll_GetBgX();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_SetBgBuffered: DMG
DMG
Scroll_SetBgBuffered: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_SetBgBuffered: DMG
DMG
Scroll_SetBgBuffered: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:66

선언 주석 원문
Stage background-scroll values in the intrinsic buffer for a later flush.

kitaqgb/lib/scroll.c:34

c
void Scroll_SetBgBuffered(u8 scx, u8 scy) { __scroll_bg_set_buffered(scx, scy); }
Scroll_SetBgX

배경의 가로 스크롤을 즉시 설정합니다.

사용 형식

c
void Scroll_SetBgX(u8 scx);

매개변수

scx

가로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 왼쪽으로 이동합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

대기하지 않습니다. 즉시 설정·가산 함수는 영향을 받는 보류 좌표 쌍을 현재값과 동기화하고 변경 플래그를 지웁니다. 한 축만 즉시 설정해도 같은 좌표 쌍의 다른 축에 있던 보류값이 취소됩니다. 이 함수는 __scroll_bg_x_set의 래퍼입니다.

사용 예

c
Scroll_SetBgX(250);result[4]=M_SCX;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_SetBgX: DMG
DMG
Scroll_SetBgX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_SetBgX: DMG
DMG
Scroll_SetBgX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:46

선언 주석 원문
Write horizontal background scroll while leaving vertical scroll unchanged.

kitaqgb/lib/scroll.c:14

c
void Scroll_SetBgX(u8 scx) { __scroll_bg_x_set(scx); }
Scroll_SetBgY

배경의 세로 스크롤을 즉시 설정합니다.

사용 형식

c
void Scroll_SetBgY(u8 scy);

매개변수

scy

세로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 위쪽으로 이동합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

대기하지 않습니다. 즉시 설정·가산 함수는 영향을 받는 보류 좌표 쌍을 현재값과 동기화하고 변경 플래그를 지웁니다. 한 축만 즉시 설정해도 같은 좌표 쌍의 다른 축에 있던 보류값이 취소됩니다. 이 함수는 __scroll_bg_y_set의 래퍼입니다.

사용 예

c
Scroll_SetBgY(2);result[5]=M_SCY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_SetBgY: DMG
DMG
Scroll_SetBgY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_SetBgY: DMG
DMG
Scroll_SetBgY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:48

선언 주석 원문
Write vertical background scroll while leaving horizontal scroll unchanged.

kitaqgb/lib/scroll.c:16

c
void Scroll_SetBgY(u8 scy) { __scroll_bg_y_set(scy); }
Scroll_SetWindow

윈도우의 WX와 WY를 즉시 설정합니다.

사용 형식

c
void Scroll_SetWindow(u8 wx, u8 wy);

매개변수

wx

가공하지 않은 WX 바이트 값이며 범위는 0~255입니다. 원하는 화면 X 좌표에 7을 더하세요. 왼쪽 가장자리는 7입니다.

wy

화면 Y 픽셀 단위의 윈도우 상단 위치입니다. 범위는 0~255이고, 화면에 보이는 행은 0~143입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

대기하지 않습니다. 즉시 설정·가산 함수는 영향을 받는 보류 좌표 쌍을 현재값과 동기화하고 변경 플래그를 지웁니다. 한 축만 즉시 설정해도 같은 좌표 쌍의 다른 축에 있던 보류값이 취소됩니다. 이 함수는 __scroll_win_set의 래퍼입니다.

사용 예

c
Scroll_SetWindow(15,8);result[8]=M_WX;result[9]=M_WY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_SetWindow: DMG
DMG
Scroll_SetWindow: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_SetWindow: DMG
DMG
Scroll_SetWindow: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:55

선언 주석 원문
Write raw hardware WX/WY values; callers add seven to a screen-space window X.

kitaqgb/lib/scroll.c:23

c
void Scroll_SetWindow(u8 wx, u8 wy) { __scroll_win_set(wx, wy); }
Scroll_SetWindowBuffered

두 윈도우 좌표를 나중에 반영할 값으로 저장합니다.

사용 형식

c
void Scroll_SetWindowBuffered(u8 wx, u8 wy);

매개변수

wx

가공하지 않은 WX 바이트 값이며 범위는 0~255입니다. 원하는 화면 X 좌표에 7을 더하세요. 왼쪽 가장자리는 7입니다.

wy

화면 Y 픽셀 단위의 윈도우 상단 위치입니다. 범위는 0~255이고, 화면에 보이는 행은 0~143입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

추적 중인 현재값이나 레지스터는 변경하지 않습니다. __scroll_flush 또는 Scroll_Flush로 반영하세요. 값을 저장하는 이 단계는 VBlank를 기다리지 않습니다. 이 함수는 __scroll_win_set_buffered의 래퍼입니다.

사용 예

c
Scroll_SetWindowBuffered(39,32);result[16]=M_WX;result[17]=Scroll_GetWindowX();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_SetWindowBuffered: DMG
DMG
Scroll_SetWindowBuffered: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_SetWindowBuffered: DMG
DMG
Scroll_SetWindowBuffered: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:68

선언 주석 원문
Stage raw window-coordinate values for a later flush.

kitaqgb/lib/scroll.c:36

c
void Scroll_SetWindowBuffered(u8 wx, u8 wy) { __scroll_win_set_buffered(wx, wy); }
Scroll_SetWindowX

윈도우의 원시 WX 좌표만 즉시 설정합니다.

사용 형식

c
void Scroll_SetWindowX(u8 wx);

매개변수

wx

가공하지 않은 WX 바이트 값이며 범위는 0~255입니다. 원하는 화면 X 좌표에 7을 더하세요. 왼쪽 가장자리는 7입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

대기하지 않습니다. 즉시 설정·가산 함수는 영향을 받는 보류 좌표 쌍을 현재값과 동기화하고 변경 플래그를 지웁니다. 한 축만 즉시 설정해도 같은 좌표 쌍의 다른 축에 있던 보류값이 취소됩니다. 이 함수는 __scroll_win_x_set의 래퍼입니다.

사용 예

c
Scroll_SetWindowX(23);result[10]=M_WX;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_SetWindowX: DMG
DMG
Scroll_SetWindowX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_SetWindowX: DMG
DMG
Scroll_SetWindowX: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:57

선언 주석 원문
Write raw hardware WX without converting a screen-space X coordinate.

kitaqgb/lib/scroll.c:25

c
void Scroll_SetWindowX(u8 wx) { __scroll_win_x_set(wx); }
Scroll_SetWindowY

윈도우의 WY 좌표만 즉시 설정합니다.

사용 형식

c
void Scroll_SetWindowY(u8 wy);

매개변수

wy

화면 Y 픽셀 단위의 윈도우 상단 위치입니다. 범위는 0~255이고, 화면에 보이는 행은 0~143입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

대기하지 않습니다. 즉시 설정·가산 함수는 영향을 받는 보류 좌표 쌍을 현재값과 동기화하고 변경 플래그를 지웁니다. 한 축만 즉시 설정해도 같은 좌표 쌍의 다른 축에 있던 보류값이 취소됩니다. 이 함수는 __scroll_win_y_set의 래퍼입니다.

사용 예

c
Scroll_SetWindowY(16);result[11]=M_WY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_SetWindowY: DMG
DMG
Scroll_SetWindowY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_SetWindowY: DMG
DMG
Scroll_SetWindowY: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:59

선언 주석 원문
Write the window Y coordinate through the intrinsic.

kitaqgb/lib/scroll.c:27

c
void Scroll_SetWindowY(u8 wy) { __scroll_win_y_set(wy); }
Scroll_SplitCommit

기본 윈도우 표시 상태를 저장하고 분할 테이블의 첫 주사선 이벤트를 준비합니다.

사용 형식

c
void Scroll_SplitCommit();

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

공유 테이블에는 항목 8개가 들어갑니다. 추가할 때 즉시 적용하거나 정렬하지 않으며, 초과 항목은 무시합니다. 안전한 프레임 경계에서 reset→push→commit 순서로 재구성하고, 처리 함수가 끝날 수 있도록 이벤트 사이에 충분한 간격을 두세요. 인터럽트 지연 때문에 지정한 주사선과 처음 영향을 받는 픽셀이 일치하지 않을 수 있습니다. 테이블이 비어 있지 않으면 IE에서 VBlank/STAT를 활성화하고 EI를 실행합니다. 빈 테이블은 LYC 소스를 비활성화하지만 IE나 CPU 인터럽트 상태를 복원하지는 않습니다. 이 함수는 __scroll_split_commit의 래퍼입니다.

사용 예

c
Scroll_SplitCommit();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 래퍼로 배경을 세 스크롤 구간으로 나눕니다. LY=64와 104의 이벤트가 X를 8과 16으로 바꾸어 24×16 사각형을 (32,16), (24,80), (16,112)에 배치합니다. 이미지에서 각 구간의 변위를 확인할 수 있습니다.

Scroll_SplitCommit: DMG
DMG
Scroll_SplitCommit: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:92

선언 주석 원문
Publish the pending split configuration through the compiler runtime.

kitaqgb/lib/scroll.c:66

c
void Scroll_SplitCommit() { __scroll_split_commit(); }
Scroll_SplitPush

지정한 주사선 이벤트에서 배경 스크롤을 바꾸는 분할 항목을 추가합니다.

사용 형식

c
void Scroll_SplitPush(u8 ly, u8 scx, u8 scy);

매개변수

ly

주사선 이벤트 번호입니다. 가시 영역의 이벤트에는 0~143을 사용하고 오름차순으로 추가하세요. 첫 항목이 0이면 VBlank 중에 적용됩니다.

scx

가로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 왼쪽으로 이동합니다.

scy

세로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 위쪽으로 이동합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

공유 테이블에는 항목 8개가 들어갑니다. 추가할 때 즉시 적용하거나 정렬하지 않으며, 초과 항목은 무시합니다. 안전한 프레임 경계에서 reset→push→commit 순서로 재구성하고, 처리 함수가 끝날 수 있도록 이벤트 사이에 충분한 간격을 두세요. 인터럽트 지연 때문에 지정한 주사선과 처음 영향을 받는 픽셀이 일치하지 않을 수 있습니다. 이 함수는 __scroll_split_push의 래퍼입니다.

사용 예

c
Scroll_SplitPush(64,8,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 래퍼로 배경을 세 스크롤 구간으로 나눕니다. LY=64와 104의 이벤트가 X를 8과 16으로 바꾸어 24×16 사각형을 (32,16), (24,80), (16,112)에 배치합니다. 이미지에서 각 구간의 변위를 확인할 수 있습니다.

Scroll_SplitPush: DMG
DMG
Scroll_SplitPush: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:85

선언 주석 원문
Append a background-scroll split directly. Use Raster_Push when caller-side
scanline ordering and capacity validation are desired.

kitaqgb/lib/scroll.c:53

c
void Scroll_SplitPush(u8 ly, u8 scx, u8 scy) { __scroll_split_push(ly, scx, scy); }
Scroll_SplitPushBgColor0

CGB 배경 팔레트 0의 색상 0을 바꾸는 이벤트를 추가합니다.

사용 형식

c
void Scroll_SplitPushBgColor0(u8 ly, u16 rgb15);

매개변수

ly

주사선 이벤트 번호입니다. 가시 영역의 이벤트에는 0~143을 사용하고 오름차순으로 추가하세요. 첫 항목이 0이면 VBlank 중에 적용됩니다.

rgb15

15비트 RGB555 색상입니다. 빨강은 비트 0~4, 초록은 5~9, 파랑은 10~14에 배치합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

CGB 전용입니다. 확장 분할 작업을 통해 8칸 분할 테이블의 한 항목을 사용합니다. 팔레트 쓰기는 PPU에 접근할 수 있는 시간을 기다립니다. 일반 속도로 동작하는 이 CGB 샘플에서는 LY=64/112 이벤트의 효과가 66/114행부터 보입니다. 이벤트 행과 처음 그려지는 행을 같다고 보지 마세요.

사용 예

c
Scroll_SplitPushBgColor0(0,0x7C00);Scroll_SplitPushBgColor0(64,0x001F);Scroll_SplitPushBgColor0(112,0x03E0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

프레임 도중 CGB 배경의 색상 0을 바꿉니다. 일반 속도에서 이 샘플은 0~65행을 파란색, 66~113행을 빨간색, 114~143행을 초록색으로 그립니다. 이벤트는 0, 64, 112에 예약되며 인터럽트 처리와 팔레트 접근 때문에 지연이 발생합니다. DMG에는 이 색상 팔레트가 없습니다.

Scroll_SplitPushBgColor0: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_color.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_color.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:90

선언 주석 원문
Reuse the two background-scroll fields to carry the low/high RGB15 bytes
for a split whose operation flag selects background color zero.

kitaqgb/lib/scroll.c:61

c
void Scroll_SplitPushBgColor0(u8 ly, u16 rgb15)
{
    __scroll_split_push_ex(ly, (u8)rgb15, (u8)(rgb15 >> 8), 0, 0, KQ_SCROLL_SPLIT_BG_COLOR0);
}
Scroll_SplitPushEx

플래그로 배경, 윈도우, 표시 여부 또는 배경 색상 0 작업을 선택하는 분할 항목을 추가합니다.

사용 형식

c
void Scroll_SplitPushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);

매개변수

ly

주사선 이벤트 번호입니다. 가시 영역의 이벤트에는 0~143을 사용하고 오름차순으로 추가하세요. 첫 항목이 0이면 VBlank 중에 적용됩니다.

scx

가로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 왼쪽으로 이동합니다.

scy

세로 배경 스크롤이며, 범위는 0~255픽셀입니다. 값을 늘리면 배경이 위쪽으로 이동합니다.

wx

가공하지 않은 WX 바이트 값이며 범위는 0~255입니다. 원하는 화면 X 좌표에 7을 더하세요. 왼쪽 가장자리는 7입니다.

wy

화면 Y 픽셀 단위의 윈도우 상단 위치입니다. 범위는 0~255이고, 화면에 보이는 행은 0~143입니다.

flags

작업 비트는 BG=1, 윈도우 위치=2, 표시=4, 숨기기=8, CGB 배경 팔레트 0의 색상 0=16입니다. 알 수 없는 비트는 버립니다. 색상 0 모드에서는 scx/scy를 RGB15의 하위·상위 바이트로 재사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

공유 테이블에는 항목 8개가 들어갑니다. 추가할 때 즉시 적용하거나 정렬하지 않으며, 초과 항목은 무시합니다. 안전한 프레임 경계에서 reset→push→commit 순서로 재구성하고, 처리 함수가 끝날 수 있도록 이벤트 사이에 충분한 간격을 두세요. 인터럽트 지연 때문에 지정한 주사선과 처음 영향을 받는 픽셀이 일치하지 않을 수 있습니다. 표시·숨기기 비트가 모두 설정되면 표시가 우선합니다. 색상 0 기능은 CGB 전용이며, BG 이동과 함께 사용하면 같은 scx/scy 바이트를 두 용도로 사용합니다. 이 함수는 __scroll_split_push_ex의 래퍼입니다.

사용 예

c
Scroll_SplitPushEx(104,16,0,7,0,KQ_SCROLL_SPLIT_USE_BG|KQ_SCROLL_SPLIT_WIN_HIDE);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 래퍼로 배경을 세 스크롤 구간으로 나눕니다. LY=64와 104의 이벤트가 X를 8과 16으로 바꾸어 24×16 사각형을 (32,16), (24,80), (16,112)에 배치합니다. 이미지에서 각 구간의 변위를 확인할 수 있습니다.

Scroll_SplitPushEx: DMG
DMG
Scroll_SplitPushEx: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:87

선언 주석 원문
Append an extended split with raw background/window fields and operation flags.

kitaqgb/lib/scroll.c:55

c
void Scroll_SplitPushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags)
{
    __scroll_split_push_ex(ly, scx, scy, wx, wy, flags);
}
Scroll_SplitReset

분할 항목 수와 인덱스를 지우고 분할 처리를 비활성화하며, STAT의 LYC 인터럽트 허용 비트를 지웁니다.

사용 형식

c
void Scroll_SplitReset();

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

공유 테이블에는 항목 8개가 들어갑니다. 추가할 때 즉시 적용하거나 정렬하지 않으며, 초과 항목은 무시합니다. 안전한 프레임 경계에서 reset→push→commit 순서로 재구성하고, 처리 함수가 끝날 수 있도록 이벤트 사이에 충분한 간격을 두세요. 인터럽트 지연 때문에 지정한 주사선과 처음 영향을 받는 픽셀이 일치하지 않을 수 있습니다. 테이블의 바이트를 지우거나 IE를 초기화하거나 CPU 인터럽트를 비활성화하지는 않습니다. 이 함수는 __scroll_split_reset의 래퍼입니다.

사용 예

c
Scroll_SplitReset();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 래퍼로 배경을 세 스크롤 구간으로 나눕니다. LY=64와 104의 이벤트가 X를 8과 16으로 바꾸어 24×16 사각형을 (32,16), (24,80), (16,112)에 배치합니다. 이미지에서 각 구간의 변위를 확인할 수 있습니다.

Scroll_SplitReset: DMG
DMG
Scroll_SplitReset: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_split_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_split_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:82

선언 주석 원문
Clear the pending split table before building a new raster configuration.

kitaqgb/lib/scroll.c:50

c
void Scroll_SplitReset() { __scroll_split_reset(); }
Scroll_WindowAdd

추적 중인 윈도우 좌표에 부호 있는 변위를 더하고 즉시 적용합니다.

사용 형식

c
void Scroll_WindowAdd(s8 dx, s8 dy);

매개변수

dx

부호 있는 가로 픽셀 변위이며, 범위는 −128~127입니다.

dy

부호 있는 세로 픽셀 변위이며, 범위는 −128~127입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

대기하지 않습니다. 즉시 설정·가산 함수는 영향을 받는 보류 좌표 쌍을 현재값과 동기화하고 변경 플래그를 지웁니다. 한 축만 즉시 설정해도 같은 좌표 쌍의 다른 축에 있던 보류값이 취소됩니다. 결과는 256을 법으로 순환합니다. 가산은 보류값이나 임시 래스터 레지스터 값이 아니라 추적 중인 현재값에서 시작합니다. 이 함수는 __scroll_win_add의 래퍼입니다.

사용 예

c
Scroll_WindowAdd(4,-40);result[24]=M_WX;result[25]=M_WY;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_WindowAdd: DMG
DMG
Scroll_WindowAdd: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_WindowAdd: DMG
DMG
Scroll_WindowAdd: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:75

선언 주석 원문
Apply signed deltas to the byte-sized hardware window coordinates.

kitaqgb/lib/scroll.c:43

c
void Scroll_WindowAdd(s8 dx, s8 dy) { __scroll_win_add(dx, dy); }
Scroll_WindowHide

LCDC의 윈도우 비트와 추적 중인 윈도우 표시 상태를 끕니다.

사용 형식

c
void Scroll_WindowHide();

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표나 맵 선택은 바꾸지 않습니다. 실제로 보이려면 LCD와 배경·윈도우 기능이 활성화되어 있어야 하며, 윈도우가 가시 영역 안에 있어야 합니다. 이 함수는 __scroll_win_hide의 래퍼입니다.

사용 예

c
Scroll_WindowHide();result[27]=M_LCDC&32;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_WindowHide: DMG
DMG
Scroll_WindowHide: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_WindowHide: DMG
DMG
Scroll_WindowHide: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:79

선언 주석 원문
Request that the window be hidden through the compiler intrinsic.

kitaqgb/lib/scroll.c:47

c
void Scroll_WindowHide() { __scroll_win_hide(); }
Scroll_WindowShow

LCDC의 윈도우 비트와 추적 중인 윈도우 표시 상태를 켭니다.

사용 형식

c
void Scroll_WindowShow();

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

좌표나 맵 선택은 바꾸지 않습니다. 실제로 보이려면 LCD와 배경·윈도우 기능이 활성화되어 있어야 하며, 윈도우가 가시 영역 안에 있어야 합니다. 이 함수는 __scroll_win_show의 래퍼입니다.

사용 예

c
Scroll_WindowShow();result[26]=M_LCDC&32;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

Scroll 함수로 즉시 갱신, 값 보류, 반영, 가산, 표시 제어를 익힙니다. 반영하면 BG X는 250에서 16으로, WX는 23에서 39로 바뀝니다. 윈도우 비트는 표시 후 32, 숨긴 후 0입니다.

Scroll_WindowShow: DMG
DMG
Scroll_WindowShow: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_scroll_wrappers.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_scroll_wrappers.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k

사용 예

c
Camera_Init(&view);
Camera_Set(&view,2048,4096);
Camera_ApplyBg(&view);
Scroll_SetWindow(103,80);
Scroll_WindowShow();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

카메라가 (8,16)이면 빨간 32×24 사각형이 화면 (24,16)에 나타납니다. 윈도우에는 (96,80)의 파란 64×64 테두리와 (112,96)의 초록 16×16 정사각형이 표시됩니다. DMG에서는 모든 도형이 검은색입니다.

Scroll_WindowShow: DMG
DMG
Scroll_WindowShow: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_camera_view.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_camera_view.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/scroll.h:77

선언 주석 원문
Request window visibility through the compiler intrinsic.

kitaqgb/lib/scroll.c:45

c
void Scroll_WindowShow() { __scroll_win_show(); }

slg.h — 보드, 수 목록, 되돌리기

바이트 값 보드, 용량이 제한된 수 목록, 되돌리기 레코드 스택을 제공합니다. 게임은 이 연산들을 조합하여 수나 되돌리기 레코드를 보드에 적용합니다.

slg_board_clear

보드의 모든 셀을 지정한 값으로 채웁니다.

사용 형식

c
void slg_board_clear(SLGBoard* board, u8 value);

매개변수

board

처리할 SLGBoard입니다. 초기화에는 NULL이 아닌 저장 공간이 필요합니다.

value

저장할 바이트 값입니다. 말이나 지형 종류 등 이 값의 의미는 게임에서 정합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
slg_board_clear(&board,0);result[1]=cells[0];result[2]=cells[11];

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_board_clear: DMG
DMG
slg_board_clear: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:33

선언 주석 원문
Fill every cell with value; a null board is ignored. A valid board must own
enough accessible cell storage for its declared dimensions.

kitaqgb/lib/slg_board.c:36

c
void slg_board_clear(SLGBoard* board, u8 value)
{
    u16 total;
    u16 i;
    u8* p;
    if (board == 0) return;
    total = (u16)((u16)board->width * (u16)board->height);
    i = 0;
    p = board->cells;
    while (i < total) {
        *p = value;
        p++;
        i++;
    }
}
slg_board_get

셀 하나를 읽습니다. 보드가 NULL이거나 좌표가 범위를 벗어나면 0을 반환합니다.

사용 형식

c
u8 slg_board_get(const SLGBoard* board, u8 x, u8 y);

매개변수

board

처리할 SLGBoard입니다. 초기화에는 NULL이 아닌 저장 공간이 필요합니다.

x

왼쪽에서 0부터 세는 셀 열입니다. 수를 기록할 때 보드 경계는 검사하지 않습니다.

y

위쪽에서 0부터 세는 셀 행입니다. 수를 기록할 때 보드 경계는 검사하지 않습니다.

반환값

셀의 바이트 값이며, 유효하지 않은 조회이면 0입니다. 0만으로는 빈 셀과 유효하지 않은 좌표를 구별할 수 없습니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
result[3]=slg_board_get(&board,1,1);result[4]=slg_board_get(&board,4,1);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_board_get: DMG
DMG
slg_board_get: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:36

선언 주석 원문
Return zero for a null board or out-of-range coordinate; otherwise read the
cell. Zero therefore cannot distinguish an invalid lookup from an empty cell.

kitaqgb/lib/slg_board.c:54

c
u8 slg_board_get(const SLGBoard* board, u8 x, u8 y)
{
    u8* p;
    if (board == 0) return 0;
    if (x >= board->width || y >= board->height) return 0;
    p = slg_cell_ptr((SLGBoard*)board, x, y);
    return *p;
}
slg_board_init

보드 크기와 셀 배열을 연결하며 배열의 기존 내용은 유지합니다.

사용 형식

c
void slg_board_init(SLGBoard* board, u8 width, u8 height, u8* cells);

매개변수

board

처리할 SLGBoard입니다. 초기화에는 NULL이 아닌 저장 공간이 필요합니다.

width

셀 단위의 보드 너비이며, 다음 행까지의 간격이기도 합니다.

height

보드의 행 수입니다.

cells

최소 width*height바이트의 셀을 저장하는 쓰기 가능한 행 우선 배열입니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
cells[0]=9;slg_board_init(&board,4,3,cells);result[0]=slg_board_get(&board,0,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_board_init: DMG
DMG
slg_board_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:30

선언 주석 원문
Attach width * height bytes of caller-owned cell storage without clearing it.

kitaqgb/lib/slg_board.c:27

c
void slg_board_init(SLGBoard* board, u8 width, u8 height, u8* cells)
{
    board->width = width;
    board->height = height;
    board->cells = cells;
}
slg_board_set

보드의 유효한 셀 하나에 씁니다. 보드가 NULL이거나 좌표가 범위를 벗어나면 무시합니다.

사용 형식

c
void slg_board_set(SLGBoard* board, u8 x, u8 y, u8 value);

매개변수

board

처리할 SLGBoard입니다. 초기화에는 NULL이 아닌 저장 공간이 필요합니다.

x

왼쪽에서 0부터 세는 셀 열입니다. 수를 기록할 때 보드 경계는 검사하지 않습니다.

y

위쪽에서 0부터 세는 셀 행입니다. 수를 기록할 때 보드 경계는 검사하지 않습니다.

value

저장할 바이트 값입니다. 말이나 지형 종류 등 이 값의 의미는 게임에서 정합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
slg_board_set(&board,1,1,7);slg_board_set(&board,4,1,9);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_board_set: DMG
DMG
slg_board_set: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:38

선언 주석 원문
Write a cell only when the board and coordinate are valid.

kitaqgb/lib/slg_board.c:64

c
void slg_board_set(SLGBoard* board, u8 x, u8 y, u8 value)
{
    u8* p;
    if (board == 0) return;
    if (x >= board->width || y >= board->height) return;
    p = slg_cell_ptr(board, x, y);
    *p = value;
}
slg_move_list_clear

저장된 레코드를 지우지 않고 수 개수를 초기화합니다.

사용 형식

c
void slg_move_list_clear(SLGMoveList* list);

매개변수

list

처리할 수 목록입니다. 초기화에는 NULL이 아닌 포인터가 필요합니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
slg_move_list_clear(&moves);result[10]=moves.count;result[11]=move_data[0].value;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_move_list_clear: DMG
DMG
slg_move_list_clear: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:42

선언 주석 원문
Forget the moves without erasing their storage; a null list is ignored.

kitaqgb/lib/slg_board.c:83

c
void slg_move_list_clear(SLGMoveList* list)
{
    if (list == 0) return;
    list->count = 0;
}
slg_move_list_init

수 목록의 저장 공간과 용량을 연결하고 개수를 0으로 설정합니다.

사용 형식

c
void slg_move_list_init(SLGMoveList* list, SLGMove* items, u8 capacity);

매개변수

list

처리할 수 목록입니다. 초기화에는 NULL이 아닌 포인터가 필요합니다.

items

최소 capacity개의 SLGMove 레코드를 담을 수 있는 호출자 소유 배열입니다.

capacity

최대 레코드 수입니다. 0이면 추가할 수 없습니다. 각 레코드는 x, y, 값의 3바이트로 구성됩니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
slg_move_list_init(&moves,move_data,2);result[5]=moves.count;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_move_list_init: DMG
DMG
slg_move_list_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:40

선언 주석 원문
Attach caller-owned move storage and reset the list length.

kitaqgb/lib/slg_board.c:75

c
void slg_move_list_init(SLGMoveList* list, SLGMove* items, u8 capacity)
{
    list->items = items;
    list->capacity = capacity;
    list->count = 0;
}
slg_move_list_push

보드를 변경하지 않고 좌표와 값을 수 목록에 추가합니다.

사용 형식

c
u8 slg_move_list_push(SLGMoveList* list, u8 x, u8 y, u8 value);

매개변수

list

처리할 수 목록입니다. 초기화에는 NULL이 아닌 포인터가 필요합니다.

x

왼쪽에서 0부터 세는 셀 열입니다. 수를 기록할 때 보드 경계는 검사하지 않습니다.

y

위쪽에서 0부터 세는 셀 행입니다. 수를 기록할 때 보드 경계는 검사하지 않습니다.

value

저장할 바이트 값입니다. 말이나 지형 종류 등 이 값의 의미는 게임에서 정합니다.

반환값

추가하면 1, NULL이거나 저장 공간이 가득 차면 0입니다. 실패해도 개수와 기존 레코드는 유지됩니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
result[6]=slg_move_list_push(&moves,1,1,7);result[7]=slg_move_list_push(&moves,2,1,8);result[8]=slg_move_list_push(&moves,3,1,9);result[9]=moves.count;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_move_list_push: DMG
DMG
slg_move_list_push: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:45

선언 주석 원문
Append coordinates and a value to the bounded move list. Return zero on a
null/full list without replacing any existing move.

kitaqgb/lib/slg_board.c:91

c
u8 slg_move_list_push(SLGMoveList* list, u8 x, u8 y, u8 value)
{
    SLGMove* move;
    if (list == 0) return 0;
    if (list->count >= list->capacity) return 0;
    move = &list->items[(__safe_index u8)list->count];
    move->x = x;
    move->y = y;
    move->value = value;
    list->count++;
    return 1;
}
slg_undo_init

되돌리기 저장 공간과 용량을 연결하고 빈 스택으로 시작합니다.

사용 형식

c
void slg_undo_init(SLGUndoStack* stack, SLGMove* items, u8 capacity);

매개변수

stack

처리할 되돌리기 스택입니다. 초기화에는 NULL이 아닌 포인터가 필요합니다.

items

최소 capacity개의 SLGMove 레코드를 담을 수 있는 호출자 소유 배열입니다.

capacity

최대 레코드 수입니다. 0이면 추가할 수 없습니다. 각 레코드는 x, y, 값의 3바이트로 구성됩니다.

반환값

반환값은 없습니다. 변경되는 상태와 적용 시점은 이 항목에서 설명합니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
slg_undo_init(&undo,undo_data,2);result[12]=undo.count;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_undo_init: DMG
DMG
slg_undo_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:47

선언 주석 원문
Attach caller-owned undo records and initialize an empty stack.

kitaqgb/lib/slg_board.c:106

c
void slg_undo_init(SLGUndoStack* stack, SLGMove* items, u8 capacity)
{
    stack->items = items;
    stack->capacity = capacity;
    stack->count = 0;
}
slg_undo_pop

가장 최근의 되돌리기 레코드를 꺼냅니다. 보드에 반영하는 것은 호출자의 몫입니다.

사용 형식

c
u8 slg_undo_pop(SLGUndoStack* stack, SLGMove* out_move);

매개변수

stack

처리할 되돌리기 스택입니다. 초기화에는 NULL이 아닌 포인터가 필요합니다.

out_move

꺼낸 레코드의 저장 대상입니다. NULL이면 복사하지 않고 버립니다.

반환값

레코드를 꺼내면 1, 스택이 NULL이거나 비어 있으면 0입니다. 빈 스택에서는 출력이 바뀌지 않습니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
result[15]=slg_undo_pop(&undo,&old);result[16]=old.value;result[17]=slg_board_get(&board,1,1);slg_undo_pop(&undo,&old);slg_board_set(&board,old.x,old.y,old.value);result[18]=slg_board_get(&board,1,1);result[19]=slg_undo_pop(&undo,&old);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_undo_pop: DMG
DMG
slg_undo_pop: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:53

선언 주석 원문
Remove the newest undo record and optionally copy it out. A null output
still discards the record; a null or empty stack returns zero.

kitaqgb/lib/slg_board.c:128

c
u8 slg_undo_pop(SLGUndoStack* stack, SLGMove* out_move)
{
    if (stack == 0) return 0;
    if (stack->count == 0) return 0;
    stack->count--;
    if (out_move != 0) {
        out_move->x = stack->items[stack->count].x;
        out_move->y = stack->items[stack->count].y;
        out_move->value = stack->items[stack->count].value;
    }
    return 1;
}
slg_undo_push

보드를 변경하지 않고 셀의 이전 값을 되돌리기 스택에 넣습니다.

사용 형식

c
u8 slg_undo_push(SLGUndoStack* stack, u8 x, u8 y, u8 old_value);

매개변수

stack

처리할 되돌리기 스택입니다. 초기화에는 NULL이 아닌 포인터가 필요합니다.

x

왼쪽에서 0부터 세는 셀 열입니다. 수를 기록할 때 보드 경계는 검사하지 않습니다.

y

위쪽에서 0부터 세는 셀 행입니다. 수를 기록할 때 보드 경계는 검사하지 않습니다.

old_value

셀의 이전 바이트 값입니다. 함수가 보드에서 자동으로 읽어 주지는 않습니다.

반환값

추가하면 1, NULL이거나 저장 공간이 가득 차면 0입니다. 실패해도 개수와 기존 레코드는 유지됩니다.

사용 조건과 제한

저장 공간은 호출자가 제공합니다. 초기화는 공간을 할당하거나 지우지 않습니다. 보드 좌표의 단위는 셀입니다.

사용 예

c
result[13]=slg_undo_push(&undo,1,1,slg_board_get(&board,1,1));slg_board_set(&board,1,1,8);slg_undo_push(&undo,1,1,8);result[14]=slg_undo_push(&undo,0,0,9);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

보드, 수 목록, 되돌리기 레코드의 역할 차이를 익히는 예제입니다. 보드 초기화는 값 9를 유지하고, 두 칸짜리 목록에 세 번째로 추가하면 0을 반환합니다. 꺼내기만 하면 보드 값은 8 그대로이며, 꺼낸 레코드를 명시적으로 적용해야 7로 복원됩니다.

slg_undo_push: DMG
DMG
slg_undo_push: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch2_board.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch2_board.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/slg.h:50

선언 주석 원문
Record a cell's previous value for later undo. Return zero if the stack is
null or full; this function does not change the board itself.

kitaqgb/lib/slg_board.c:115

c
u8 slg_undo_push(SLGUndoStack* stack, u8 x, u8 y, u8 old_value)
{
    if (stack == 0) return 0;
    if (stack->count >= stack->capacity) return 0;
    stack->items[stack->count].x = x;
    stack->items[stack->count].y = y;
    stack->items[stack->count].value = old_value;
    stack->count++;
    return 1;
}

sprite.h — OBJ 할당·배치, 메타스프라이트, 애니메이션

스프라이트는 보통 8×8 또는 8×16픽셀 크기의 이동 가능한 하드웨어 오브젝트로, OAM(Object Attribute Memory) 항목으로 지정합니다. 슬롯을 확보하고 섀도 OAM에 위치, 타일, 속성을 설정한 뒤 전송합니다. 여러 슬롯을 하나의 오브젝트로 묶은 것이 메타스프라이트입니다. GB는 40슬롯과 주사선당 10개, FC는 64슬롯과 주사선당 8개를 제공합니다.

GB 속성은 비트 4가 DMG OBP1 선택, 5/6이 X/Y 반전, 7이 색 번호 0이 아닌 배경 뒤로 배치하는 기능입니다. CGB에서는 0~2가 오브젝트 팔레트, 3이 타일 데이터 VRAM 뱅크이며 DMG 팔레트 선택 비트는 기본 CGB 색상에 쓰이지 않습니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

anim_update

SpriteAnim 타이머를 진행하고 선택된 타일 번호를 반환합니다. ticks_per_frame번 호출할 때마다 다음 연속 타일로 이동하며 frame_count 프레임 뒤 처음으로 돌아갑니다. 호출한 쪽에서 반환값을 sprite_set_tile에 적용합니다.

사용 형식

c
u8 anim_update(SpriteAnim* anim);

매개변수

anim

first_tile, frame_count, frame, ticks, ticks_per_frame이 있는 쓰기 가능한 SpriteAnim 상태입니다. 해당 개수가 0이 아니면 frame은 frame_count 미만, ticks는 ticks_per_frame 미만으로 유지하세요.

반환값

선택된 8비트 타일 번호이며 상태 포인터가 널이면 0입니다. OAM에는 기록하지 않습니다.

사용 조건과 제한

frame_count가 0이면 진행 없이 first_tile을 반환하고 ticks_per_frame이 0이면 현재 프레임을 유지합니다. 타이머는 영상 프레임이 아니라 호출 횟수로 진행합니다. 타일 번호는 256에서 순환하며 8×16 모드에서도 한 칸씩 증가합니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_example_animation.first_tile=128;sprite_example_animation.frame_count=2;
sprite_example_animation.frame=0;sprite_example_animation.ticks=0;
sprite_example_animation.ticks_per_frame=2;
sprite_example_expect(anim_update(&sprite_example_animation)==128);
tile=anim_update(&sprite_example_animation);
sprite_example_expect(tile==129);sprite_set_tile(5,tile);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

시작 타일 128, 두 프레임, 프레임당 두 호출로 설정하면 첫 갱신은 화살표 타일 128, 두 번째는 정사각형 타일 129를 반환합니다. ANIMATION 옆의 정사각형으로 반환값이 OAM에 적용되었음을 확인합니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

anim_update: DMG
DMG
anim_update: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:86

선언 주석 원문
Advance animation ticks/frame with wrapping frame selection and return the
resulting tile. Zero ticks-per-frame freezes animation; null state returns zero.

kitaqgb/lib/sprite.c:211

c
u8 anim_update(SpriteAnim* anim)
{
    if (anim == 0) return 0;
    if (anim->frame_count == 0) return anim->first_tile;
    if (anim->ticks_per_frame == 0) return (u8)(anim->first_tile + anim->frame);

    anim->ticks++;
    if (anim->ticks >= anim->ticks_per_frame) {
        anim->ticks = 0;
        anim->frame++;
        if (anim->frame >= anim->frame_count) anim->frame = 0;
    }
    return (u8)(anim->first_tile + anim->frame);
}
metasprite_draw

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

개수를 지정한 스프라이트 조각 배열을 연속 슬롯에 배치합니다. 각 조각에는 부호 있는 오프셋, 타일, 속성이 들어갑니다. 빈 슬롯을 활성화하고 사용 중인 슬롯은 덮어쓰며 슬롯 한도에서 멈춥니다.

사용 형식

c
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);

매개변수

first_id

0부터 SPRITE_MAX-1까지의 슬롯 ID입니다. 기본값은 GB 0~39, FC 0~63입니다. 범위를 벗어나면 무시합니다.

x

픽셀 단위의 가로 위치를 부호 없는 8비트 값으로 전달합니다. 타일 좌표가 아닙니다.

y

화면 Y 좌표를 픽셀 단위로 전달합니다. GB 래퍼는 16을 더해 OAM에 저장합니다.

parts

count개 이상의 MetaSpritePart를 읽을 수 있는 배열입니다. 각 4바이트 레코드는 부호 있는 dx/dy, 타일, 속성 순서이며 종료 표시는 없습니다.

count

조각 수를 부호 없는 8비트 값으로 지정합니다. 0이면 쓰지 않습니다. 연속 슬롯이 SPRITE_MAX에 도달하면 그 전까지의 조각만 기록합니다.

반환값

실제로 기록한 조각 수를 0~count로 반환합니다. 슬롯 한도에서 잘렸는지는 이 값으로 확인합니다.

사용 조건과 제한

위치, 타일, 속성, 숨기기는 섀도 데이터만 바꿉니다. 슬롯을 할당하거나 하드웨어 OAM을 즉시 바꾸지 않습니다. 한 프레임의 갱신을 마친 뒤 sprite_flush_oam으로 전송하세요.

부호 있는 8비트 오프셋을 기준 좌표에 더한 뒤 결과를 8비트로 순환시킵니다. 호출 동안 조각 배열 전체를 읽을 수 있어야 합니다. 활성 슬롯도 덮어쓰므로 다른 오브젝트의 슬롯을 보호하지 않습니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_example_expect(metasprite_draw(10,88,SPRITE_EXAMPLE_Y(64),sprite_example_pair,2)==2);
sprite_example_expect(sprite_count_used()==9); // Sparse IDs count actual active slots.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

초기화 직후 할당 수는 0입니다. 여덟 번 할당하면 ID 0~7을 반환합니다. 슬롯 6을 숨겨도 8이고, 슬롯 7을 두 번 해제하면 7이며, 10과 11에 두 조각을 놓으면 9가 됩니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

metasprite_draw: DMG
DMG
metasprite_draw: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:83

선언 주석 원문
Place consecutive parts, counting each newly activated slot once. Existing
active slots are overwritten without increasing the allocation count. Return
the number written; an invalid first slot or zero count writes nothing.

kitaqgb/lib/sprite.c:191

c
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count)
{
    u8 i = 0;
    while (i < count) {
        u8 id = (u8)(first_id + i);
        if (id >= SPRITE_MAX) return i;
        if (kq_sprite_active[id] == 0) {
            kq_sprite_active[id] = 1;
            kq_sprite_used = (u8)(kq_sprite_used + 1);
        }
        sprite_set_pos(id, (u8)(x + parts[i].dx), (u8)(y + parts[i].dy));
        sprite_set_tile(id, parts[i].tile);
        sprite_set_flags(id, parts[i].flags);
        i++;
    }
    return count;
}
sprite_alloc

첫 번째 빈 스프라이트 슬롯을 확보하고 위치를 지정할 때까지 숨깁니다. 숨겨진 동안에도 할당은 유지됩니다. 표시하기 전에 타일과 속성을 설정하세요.

사용 형식

c
u8 sprite_alloc();

반환값

할당된 슬롯 ID를 반환하며, 모든 슬롯이 사용 중이면 0xFF입니다.

사용 조건과 제한

위치, 타일, 속성, 숨기기는 섀도 데이터만 바꿉니다. 슬롯을 할당하거나 하드웨어 OAM을 즉시 바꾸지 않습니다. 한 프레임의 갱신을 마친 뒤 sprite_flush_oam으로 전송하세요.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
for(i=0;i<8;i++) sprite_example_expect(sprite_alloc()==i);
sprite_example_expect(sprite_count_used()==8);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

초기화 직후 할당 수는 0입니다. 여덟 번 할당하면 ID 0~7을 반환합니다. 슬롯 6을 숨겨도 8이고, 슬롯 7을 두 번 해제하면 7이며, 10과 11에 두 조각을 놓으면 9가 됩니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_alloc: DMG
DMG
sprite_alloc: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:53

선언 주석 원문
Claim the first free slot, hide it, and return its ID; return 0xFF when full.
Previously stored tile/flag bytes are retained until the caller replaces them.

kitaqgb/lib/sprite.c:60

c
u8 sprite_alloc()
{
    u8 i = 0;
    while (i < SPRITE_MAX) {
        if (kq_sprite_active[i] == 0) {
            kq_sprite_active[i] = 1;
            kq_sprite_used++;
            sprite_hide(i);
            return i;
        }
        i++;
    }
    return 0xFF;
}
sprite_count_used

숨겨진 스프라이트와 metasprite_draw로 활성화한 슬롯을 포함해 할당 수를 반환합니다. 화면에 보이는 수가 아니라 할당된 슬롯 수입니다.

사용 형식

c
u8 sprite_count_used();

반환값

0부터 SPRITE_MAX까지의 부호 없는 8비트 값입니다.

사용 조건과 제한

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_example_expect(sprite_count_used()==9); // After hiding, freeing and drawing the pair.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

초기화 직후 할당 수는 0입니다. 여덟 번 할당하면 ID 0~7을 반환합니다. 슬롯 6을 숨겨도 8이고, 슬롯 7을 두 번 해제하면 7이며, 10과 11에 두 조각을 놓으면 9가 됩니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_count_used: DMG
DMG
sprite_count_used: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:73

선언 주석 원문
Return the number of active slots, including slots activated by metasprite_draw.
Hidden allocated slots remain active until sprite_free releases them.

kitaqgb/lib/sprite.c:148

c
u8 sprite_count_used()
{
    return kq_sprite_used;
}
sprite_flush_oam

VBlank를 기다린 뒤 sprite_flush_oam_now로 섀도 OAM을 전송합니다.

사용 형식

c
void sprite_flush_oam();

반환값

없음(void).

사용 조건과 제한

GB 루틴은 HRAM에서 DMA 코드를 실행해 정렬된 섀도 OAM의 160바이트를 복사합니다. 전송 중 인터럽트를 끄고 끝나면 항상 켭니다. 호출 전 비활성 상태를 복원하지는 않습니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
while(1) { sprite_flush_oam(); } // Transfer prepared sprites at the next frame boundary.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_flush_oam: DMG
DMG
sprite_flush_oam: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:70

선언 주석 원문
Wait for VBlank, then transfer shadow OAM using the immediate DMA routine.

kitaqgb/lib/sprite.c:139

c
void sprite_flush_oam()
{
    __wait_vblank();
    sprite_flush_oam_now();
}
sprite_flush_oam_now

섀도 OAM을 즉시 하드웨어로 전송합니다. 안전한 표시 구간을 기다리지 않으므로 호출하는 쪽에서 실행 시점을 정해야 합니다.

사용 형식

c
void sprite_flush_oam_now();

반환값

없음(void).

사용 조건과 제한

GB 루틴은 HRAM에서 DMA 코드를 실행해 정렬된 섀도 OAM의 160바이트를 복사합니다. 전송 중 인터럽트를 끄고 끝나면 항상 켭니다. 호출 전 비활성 상태를 복원하지는 않습니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
// Rendering is disabled here; all shadow entries have been prepared.
sprite_flush_oam_now();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_flush_oam_now: DMG
DMG
sprite_flush_oam_now: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:68

선언 주석 원문
Install the HRAM stub lazily and execute OAM DMA with interrupts disabled.
This routine does not wait for VBlank and always enables interrupts afterward;
it does not restore the caller's previous interrupt-enable state.

kitaqgb/lib/sprite.c:122

c
void sprite_flush_oam_now()
{
    SpriteDmaRoutine dma;
    if (kq_sprite_dma_ready == 0) {
        sprite_install_dma_stub();
    }
    dma = (SpriteDmaRoutine)kq_sprite_dma_stub;
    __asm {
        DI
    }
    dma();
    __asm {
        EI
    }
}
sprite_free

할당된 슬롯을 해제하고 숨긴 뒤 사용 수를 하나 줄입니다. 범위를 벗어난 ID나 이미 해제된 슬롯에는 아무 작업도 하지 않습니다.

사용 형식

c
void sprite_free(u8 id);

매개변수

id

0부터 SPRITE_MAX-1까지의 슬롯 ID입니다. 기본값은 GB 0~39, FC 0~63입니다. 범위를 벗어나면 무시합니다.

반환값

없음(void).

사용 조건과 제한

위치, 타일, 속성, 숨기기는 섀도 데이터만 바꿉니다. 슬롯을 할당하거나 하드웨어 OAM을 즉시 바꾸지 않습니다. 한 프레임의 갱신을 마친 뒤 sprite_flush_oam으로 전송하세요.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_free(7);sprite_free(7);
sprite_example_expect(sprite_count_used()==7); // Repeated release is ignored.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

초기화 직후 할당 수는 0입니다. 여덟 번 할당하면 ID 0~7을 반환합니다. 슬롯 6을 숨겨도 8이고, 슬롯 7을 두 번 해제하면 7이며, 10과 11에 두 조각을 놓으면 9가 됩니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_free: DMG
DMG
sprite_free: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:55

선언 주석 원문
Release an allocated valid slot and hide it. Repeated frees do not decrement the count.

kitaqgb/lib/sprite.c:78

c
void sprite_free(u8 id)
{
    if (sprite_valid(id) == 0) return;
    if (kq_sprite_active[id] == 0) return;
    kq_sprite_active[id] = 0;
    if (kq_sprite_used != 0) kq_sprite_used--;
    sprite_hide(id);
}
sprite_hide

섀도 위치를 바꿔 스프라이트를 숨깁니다. 할당, 타일, 속성은 유지되므로 보이는 위치로 옮기면 다시 할당하지 않고 표시할 수 있습니다.

사용 형식

c
void sprite_hide(u8 id);

매개변수

id

0부터 SPRITE_MAX-1까지의 슬롯 ID입니다. 기본값은 GB 0~39, FC 0~63입니다. 범위를 벗어나면 무시합니다.

반환값

없음(void).

사용 조건과 제한

위치, 타일, 속성, 숨기기는 섀도 데이터만 바꿉니다. 슬롯을 할당하거나 하드웨어 OAM을 즉시 바꾸지 않습니다. 한 프레임의 갱신을 마친 뒤 sprite_flush_oam으로 전송하세요.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_hide(6);
sprite_example_expect(sprite_count_used()==8); // Hiding retains allocation.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

초기화 직후 할당 수는 0입니다. 여덟 번 할당하면 ID 0~7을 반환합니다. 슬롯 6을 숨겨도 8이고, 슬롯 7을 두 번 해제하면 7이며, 10과 11에 두 조각을 놓으면 9가 됩니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_hide: DMG
DMG
sprite_hide: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:64

선언 주석 원문
Move a valid shadow slot off screen without freeing it.

kitaqgb/lib/sprite.c:112

c
void sprite_hide(u8 id)
{
    if (sprite_valid(id) == 0) return;
    kq_sprite_oam[id].y = 0;
    kq_sprite_oam[id].x = 0;
}
sprite_init

스프라이트 할당 상태를 초기화하고 섀도 OAM의 모든 슬롯을 숨깁니다. 소프트웨어상의 높이는 8픽셀이 됩니다. 하드웨어 크기 설정과 OAM 전송은 별도로 수행합니다.

사용 형식

c
void sprite_init();

반환값

없음(void).

사용 조건과 제한

GB 초기화는 각 섀도 슬롯의 네 바이트를 지우고 HRAM DMA 루틴의 설치 상태를 초기화합니다. 별도 DMA 원본에 160바이트 전체를 확보하지 않는다면 기본 SPRITE_MAX=40을 사용하세요.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_init();
sprite_example_expect(sprite_count_used()==0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

초기화 직후 할당 수는 0입니다. 여덟 번 할당하면 ID 0~7을 반환합니다. 슬롯 6을 숨겨도 8이고, 슬롯 7을 두 번 해제하면 7이며, 10과 11에 두 조각을 놓으면 9가 됩니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_init: DMG
DMG
sprite_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:50

선언 주석 원문
Clear allocation and shadow OAM state and reset the DMA-stub installation flag.
The default height is eight pixels; the hardware display mode is configured elsewhere.

kitaqgb/lib/sprite.c:22

c
void sprite_init()
{
    u8 i = 0;
    kq_sprite_used = 0;
    kq_sprite_height = 8;
    kq_sprite_dma_ready = 0;
    while (i < SPRITE_MAX) {
        kq_sprite_active[i] = 0;
        kq_sprite_oam[i].y = 0;
        kq_sprite_oam[i].x = 0;
        kq_sprite_oam[i].tile = 0;
        kq_sprite_oam[i].flags = 0;
        i++;
    }
}
sprite_max_scanline_count

관리 중인 세로 위치와 kq_sprite_height를 바탕으로 표시 영역의 한 주사선에 겹치는 활성 스프라이트의 최대 수를 추정합니다.

사용 형식

c
u8 sprite_max_scanline_count();

반환값

0부터 SPRITE_MAX까지의 부호 없는 8비트 값입니다.

사용 조건과 제한

kq_sprite_height를 하드웨어 높이인 8 또는 16으로 맞추세요. 이 추정은 투명 픽셀, 가로 가시성, 하드웨어 우선순위를 고려하지 않습니다. FC는 라이브러리의 좌표를 읽으므로 OAM 내장 함수로 직접 바꾼 위치는 반영하지 않습니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_example_expect(sprite_max_scanline_count()==SPRITE_EXAMPLE_LINE_COUNT);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

sprite_max_scanline_count: DMG
DMG
sprite_max_scanline_count: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:79

선언 주석 원문
Estimate the largest overlap of active, non-hidden shadow sprites across
visible scanlines using the configured sprite height. This is a software
overlap count, not a rendered-pixel or hardware-priority simulation.

kitaqgb/lib/sprite.c:158

c
u8 sprite_max_scanline_count()
{
    u8 line = 0;
    u8 best = 0;
    while (line < 144) {
        u8 i = 0;
        u8 count = 0;
        u8 ly_oam = (u8)(line + 16);
        while (i < SPRITE_MAX) {
            u8 sy = kq_sprite_oam[i].y;
            if (kq_sprite_active[i] != 0 && sy != 0) {
                if (ly_oam >= sy && ly_oam < (u8)(sy + kq_sprite_height)) {
                    count++;
                }
            }
            i++;
        }
        if (count > best) best = count;
        line++;
    }
    return best;
}
sprite_set_flags

스프라이트 속성 바이트 전체를 바꿉니다. 해당 기종의 플래그 상수를 조합해 반전, 팔레트, 배경 우선순위를 지정합니다. 지정하지 않은 비트는 0이 됩니다.

사용 형식

c
void sprite_set_flags(u8 id, u8 flags);

매개변수

id

0부터 SPRITE_MAX-1까지의 슬롯 ID입니다. 기본값은 GB 0~39, FC 0~63입니다. 범위를 벗어나면 무시합니다.

flags

해당 기종의 SPRITE_FLAG_* 상수로 구성한 전체 속성 바이트입니다. 여러 플래그는 비트 OR(|)로 조합합니다.

반환값

없음(void).

사용 조건과 제한

위치, 타일, 속성, 숨기기는 섀도 데이터만 바꿉니다. 슬롯을 할당하거나 하드웨어 OAM을 즉시 바꾸지 않습니다. 한 프레임의 갱신을 마친 뒤 sprite_flush_oam으로 전송하세요.

GB 속성은 비트 4가 DMG OBP1 선택, 5/6이 X/Y 반전, 7이 색 번호 0이 아닌 배경 뒤로 배치하는 기능입니다. CGB에서는 0~2가 오브젝트 팔레트, 3이 타일 데이터 VRAM 뱅크이며 DMG 팔레트 선택 비트는 기본 CGB 색상에 쓰이지 않습니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_set_flags(1,SPRITE_FLAG_XFLIP);
sprite_set_flags(2,SPRITE_FLAG_YFLIP);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_set_flags: DMG
DMG
sprite_set_flags: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:62

선언 주석 원문
Replace a valid shadow slot's complete hardware attribute byte.

kitaqgb/lib/sprite.c:105

c
void sprite_set_flags(u8 id, u8 flags)
{
    if (sprite_valid(id) == 0) return;
    kq_sprite_oam[id].flags = flags;
}
sprite_set_pos

화면 픽셀 좌표로 GB 스프라이트의 섀도 OAM 위치를 바꿉니다. 하드웨어 오프셋으로 X에 8, Y에 16을 더합니다.

사용 형식

c
void sprite_set_pos(u8 id, u8 x, u8 y);

매개변수

id

0부터 SPRITE_MAX-1까지의 슬롯 ID입니다. 기본값은 GB 0~39, FC 0~63입니다. 범위를 벗어나면 무시합니다.

x

픽셀 단위의 가로 위치를 부호 없는 8비트 값으로 전달합니다. 타일 좌표가 아닙니다.

y

화면 Y 좌표를 픽셀 단위로 전달합니다. GB 래퍼는 16을 더해 OAM에 저장합니다.

반환값

없음(void).

사용 조건과 제한

위치, 타일, 속성, 숨기기는 섀도 데이터만 바꿉니다. 슬롯을 할당하거나 하드웨어 OAM을 즉시 바꾸지 않습니다. 한 프레임의 갱신을 마친 뒤 sprite_flush_oam으로 전송하세요.

좌표 덧셈은 8비트 연산이며 256을 기준으로 순환합니다. 화면 범위로 자르지 않습니다. 유효한 슬롯은 할당되지 않았어도 수정할 수 있습니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_set_pos(0,88,SPRITE_EXAMPLE_Y(16)); // Visible top-left: (88,16).

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_set_pos: DMG
DMG
sprite_set_pos: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:58

선언 주석 원문
Convert screen coordinates to OAM coordinates by adding X=8 and Y=16.
The byte additions wrap; this updates shadow storage even for an unallocated slot.

kitaqgb/lib/sprite.c:89

c
void sprite_set_pos(u8 id, u8 x, u8 y)
{
    if (sprite_valid(id) == 0) return;
    kq_sprite_oam[id].x = (u8)(x + 8);
    kq_sprite_oam[id].y = (u8)(y + 16);
}
sprite_set_tile

섀도 OAM 한 슬롯의 타일 번호를 바꿉니다. 타일 메모리에 있는 그래픽을 선택할 뿐, 그래픽 전송이나 스프라이트 할당은 하지 않습니다.

사용 형식

c
void sprite_set_tile(u8 id, u8 tile);

매개변수

id

0부터 SPRITE_MAX-1까지의 슬롯 ID입니다. 기본값은 GB 0~39, FC 0~63입니다. 범위를 벗어나면 무시합니다.

tile

8비트 타일 번호입니다. 그래픽을 먼저 로드하세요. 8×16 스프라이트의 하드웨어 규칙은 그대로 적용되며 두 타일 묶음에 맞게 번호를 보정하지 않습니다.

반환값

없음(void).

사용 조건과 제한

위치, 타일, 속성, 숨기기는 섀도 데이터만 바꿉니다. 슬롯을 할당하거나 하드웨어 OAM을 즉시 바꾸지 않습니다. 한 프레임의 갱신을 마친 뒤 sprite_flush_oam으로 전송하세요.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_set_tile(5,129); // Select the green square beside ANIMATION.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

시작 타일 128, 두 프레임, 프레임당 두 호출로 설정하면 첫 갱신은 화살표 타일 128, 두 번째는 정사각형 타일 129를 반환합니다. ANIMATION 옆의 정사각형으로 반환값이 OAM에 적용되었음을 확인합니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

sprite_set_tile: DMG
DMG
sprite_set_tile: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:60

선언 주석 원문
Set a valid shadow slot's tile byte; allocation and hardware transfer are separate.

kitaqgb/lib/sprite.c:98

c
void sprite_set_tile(u8 id, u8 tile)
{
    if (sprite_valid(id) == 0) return;
    kq_sprite_oam[id].tile = tile;
}
sprite_warn_scanline_overflow

sprite_max_scanline_count를 GB는 10개, FC는 8개인 주사선당 한도와 비교합니다. 소프트웨어 추정 결과이며 하드웨어 오버플로 플래그를 읽지는 않습니다.

사용 형식

c
u8 sprite_warn_scanline_overflow();

반환값

추정값이 주사선당 한도를 넘으면 1, 아니면 0입니다.

사용 조건과 제한

kq_sprite_height를 하드웨어 높이인 8 또는 16으로 맞추세요. 이 추정은 투명 픽셀, 가로 가시성, 하드웨어 우선순위를 고려하지 않습니다. FC는 라이브러리의 좌표를 읽으므로 OAM 내장 함수로 직접 바꾼 위치는 반영하지 않습니다.

예제는 GB 스프라이트 라이브러리의 전체 기능을 사용합니다. KQ_SPRITE_MINIMAL_RUNTIME을 정의하면 sprite.c에서 sprite_free, sprite_set_pos, sprite_count_used, 두 주사선 조회 함수, metasprite_draw, anim_update가 제외됩니다. 해당 함수를 사용할 때는 정의하지 마세요.

사용 예

c
sprite_example_expect(sprite_warn_scanline_overflow()==1);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

SCAN LIMIT 아래 줄은 (8,128)에서 시작합니다. GB는 11개, FC는 9개를 같은 줄에 배치해 의도적으로 하나 초과합니다. GB에서는 화살표 10개, FC에서는 8개가 보이고 마지막 것은 보이지 않아야 합니다. 소프트웨어 최대 수와 경고 검사는 각각 11/9와 1이어야 합니다.

스프라이트 할당, 위치, 반전, 복합 오브젝트, 겹침, 애니메이션, 주사선 한도를 배우는 프로그램입니다. 오른쪽 위의 두 숫자는 모든 내부 검사가 통과했음을 뜻하는 00이어야 합니다. 화살표와 정사각형은 각각 8×8 타일입니다.

NORMAL은 (88,16)의 오른쪽 화살표, FLIP X는 (88,32)의 왼쪽 화살표, FLIP Y는 (88,48)의 상하 반전 화살표입니다. META는 (88,64)와 (96,64)에 두 화살표를 놓습니다. OVERLAP에서는 (88,80)의 화살표가 (92,80)의 정사각형 앞에 놓이며 투명한 부분으로 정사각형이 보입니다. ANIMATION은 (88,96)의 정사각형입니다. (120,16)과 (120,32)는 숨기기와 해제 후 비어 있어야 합니다.

CGB와 FC의 화살표는 녹색 몸통, 빨간 윤곽, 파란 끝부분을 사용하며 정사각형은 녹색입니다. 투명한 부분에는 GB의 흰 배경 또는 FC의 검은 배경이 보입니다. DMG는 빨강·초록·파랑 대신 밝은 회색·짙은 회색·검정을 사용합니다.

sprite_warn_scanline_overflow: DMG
DMG
sprite_warn_scanline_overflow: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite.h:75

선언 주석 원문
Report whether the software overlap estimate exceeds ten sprites on a scanline.

kitaqgb/lib/sprite.c:182

c
u8 sprite_warn_scanline_overflow()
{
    return (u8)(sprite_max_scanline_count() > 10);
}

sprite_order.h — 우선순위와 순환에 따른 스프라이트 선택

sprite_order는 중요한 오브젝트를 앞에 놓고 같은 우선순위의 OAM 순서를 순환시킵니다. 최대 255개 후보에서 40개까지 출력해 주사선당 10개 제한을 관리합니다. sprite 라이브러리는 슬롯 할당과 DMA를, sprite_order는 후보 선택 순서를 담당합니다.

sprite_order.h를 포함하고 sprite_order.c를 정확히 한 번 컴파일하세요. 초기화 후 매 프레임 begin, 후보별 push, build 순서로 호출합니다. 순서 제어 라이브러리 자체에는 sprite.c나 전역 변수 정의가 필요 없습니다.

하드웨어는 각 주사선에 걸친 오브젝트 중 OAM 순서의 앞 10개를 선택합니다. 작은 우선순위 값을 먼저 놓으면 혼잡한 줄에서 중요한 오브젝트를 보호합니다. 순환은 같은 우선순위 안에서 동일한 표시 빈도를 보장하지 않습니다. 높은 우선순위가 10칸을 모두 채우면 그 줄의 낮은 우선순위는 계속 보이지 않습니다.

SpriteOrderOamEntry는 Y, X, tile, flags의 4바이트입니다. sprite.h의 섀도 OAM을 쓰려면 (SpriteOrderOamEntry*)kq_sprite_oam에 출력하세요. 표준 SPRITE_MAX 40을 유지하고 할당기가 관리하는 슬롯 ID와 재정렬된 출력을 혼용하지 마세요. build는 할당기 기록을 갱신하지 않습니다.

sprite_order_begin

저장 공간, 높이, 순환 위상을 유지하며 새 프레임의 제출 개수를 지웁니다. 매 프레임 재초기화하는 것과 달리 순환을 계속할 수 있습니다.

사용 형식

c
void sprite_order_begin(SpriteOrder* order);

매개변수

order

호출자가 소유한 SpriteOrder의 주소입니다. 사용 전에 초기화하고 갱신은 메인 코드에서 수행하세요.

반환값

반환값은 없습니다. order가 null이면 무시합니다. 이전 항목 바이트나 이미 구성한 OAM은 지우지 않습니다.

사용 조건과 제한

sprite_order.h를 포함하고 sprite_order.c를 정확히 한 번 컴파일하세요. 초기화 후 매 프레임 begin, 후보별 push, build 순서로 호출합니다. 순서 제어 라이브러리 자체에는 sprite.c나 전역 변수 정의가 필요 없습니다.

하드웨어는 각 주사선에 걸친 오브젝트 중 OAM 순서의 앞 10개를 선택합니다. 작은 우선순위 값을 먼저 놓으면 혼잡한 줄에서 중요한 오브젝트를 보호합니다. 순환은 같은 우선순위 안에서 동일한 표시 빈도를 보장하지 않습니다. 높은 우선순위가 10칸을 모두 채우면 그 줄의 낮은 우선순위는 계속 보이지 않습니다.

사용 예

c
sprite_order_begin(&order_demo);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.

sprite_order_begin: DMG / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
DMG / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
sprite_order_begin: CGB / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
CGB / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
sprite_order_begin: CGB / 위상 08 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
CGB / 위상 08 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_order_demo.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_order_demo.gb --cgb=cgb --profile=dev --rst-disable --stack-bank=fixed --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite_order.h:42

선언 주석 원문
Discard this frame's submissions while preserving storage, height and phase.
A null state is ignored. Call once before submitting the next frame's sprites.

kitaqgb/lib/sprite_order.c:24

c
void sprite_order_begin(SpriteOrder* order)
{
    if (order != 0) order->count = 0;
}
sprite_order_build

제출 후보를 우선순위와 순환 순서로 배치해 섀도 OAM 160바이트를 구성합니다. 미사용 슬롯은 모두 0으로 숨기고 다음 구성을 위해 위상을 진행합니다. 제출 저장 공간은 재정렬하지 않습니다.

사용 형식

c
u8 sprite_order_build(SpriteOrder* order, SpriteOrderOamEntry* output, u8 limit);

매개변수

order

호출자가 소유한 SpriteOrder의 주소입니다. 사용 전에 초기화하고 갱신은 메인 코드에서 수행하세요.

output

SpriteOrderOamEntry 40개로 된 쓰기 가능한 배열입니다. limit가 0이거나 40 미만이어도 160바이트 전체를 씁니다.

limit

최대 출력 개수 0..40이며 더 큰 값은 40으로 제한합니다. 주사선별 제한이 아닌 OAM 전체 제한입니다.

반환값

출력 개수 0..40을 반환합니다. 유효한 빈 큐는 모든 슬롯을 지우고 phase=0으로 만듭니다. 그 외에는 phase를 count로 나눈 나머지로 정규화해 오름차순 각 우선순위 그룹의 순환 시작점으로 사용한 뒤, 위상을 증가시켜 순환합니다. limit=0이어도 위상은 진행합니다. order/output null, 비활성 상태, 잘못된 높이, count>capacity는 출력이나 위상을 바꾸지 않고 0을 반환합니다.

사용 조건과 제한

하드웨어는 각 주사선에 걸친 오브젝트 중 OAM 순서의 앞 10개를 선택합니다. 작은 우선순위 값을 먼저 놓으면 혼잡한 줄에서 중요한 오브젝트를 보호합니다. 순환은 같은 우선순위 안에서 동일한 표시 빈도를 보장하지 않습니다. 높은 우선순위가 10칸을 모두 채우면 그 줄의 낮은 우선순위는 계속 보이지 않습니다.

priority 인수는 배경 뒤 속성과 독립적으로 선택 순서를 제어합니다. DMG에서 선택된 오브젝트가 겹치면 작은 X 좌표가 우선하고 같으면 OAM 순서로 결정합니다. 일반 CGB 컬러 모드는 OAM 순서를 사용하지만 OPRI로 DMG식 순서를 선택한 설정도 적용됩니다. 이 라이브러리는 하드웨어 우선순위 규칙을 바꾸지 않습니다.

SpriteOrderOamEntry는 Y, X, tile, flags의 4바이트입니다. sprite.h의 섀도 OAM을 쓰려면 (SpriteOrderOamEntry*)kq_sprite_oam에 출력하세요. 표준 SPRITE_MAX 40을 유지하고 할당기가 관리하는 슬롯 ID와 재정렬된 출력을 혼용하지 마세요. build는 할당기 기록을 갱신하지 않습니다.

build는 RAM만 씁니다. 상태나 제출 저장 공간과 겹치지 않는 160바이트 출력 배열을 준비하세요. OAM DMA 버퍼는 256바이트 경계에서 시작해야 합니다. VBlank 전송 전에 구성을 끝내고, 인터럽트가 미완성 버퍼를 전송하지 않게 하세요. 샘플은 sprite_flush_oam을 사용합니다.

제출 한 번의 작업량은 제한되어 있습니다. 구성은 섀도 OAM 160바이트를 지우고 제출 배열을 최대 4번 훑습니다. 배열 자체를 정렬하거나 임시 정렬 버퍼를 쓰지 않습니다. 후보 255개가 게임의 프레임 예산에 들어간다는 보장은 아니므로 장면에 필요한 후보만 제출하세요.

사용 예

c
order_demo_state[1]=sprite_order_build(&order_demo,(SpriteOrderOamEntry*)kq_sprite_oam,40);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.

sprite_order_build: DMG / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
DMG / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
sprite_order_build: CGB / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
CGB / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
sprite_order_build: CGB / 위상 08 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
CGB / 위상 08 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_order_demo.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_order_demo.gb --cgb=cgb --profile=dev --rst-disable --stack-bank=fixed --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite_order.h:62

선언 주석 원문
Write a complete 160-byte shadow OAM: ascending priority, then cyclic order
within each priority. Clamp limit to 40, return the number emitted and zero
all unused entries (including Y) so they cannot consume scanline slots.
Advance phase once for a nonempty valid queue, even when limit is zero.
Empty queues reset phase to zero. Null/disabled/corrupt state or null output
returns 0 without modifying output or phase.
Output must provide 40 entries and must not overlap item/state storage.
This only writes RAM. Build in foreground, then transfer during VBlank.
DMG overlap priority also depends on X: this cannot override that hardware
rule. OAM order chooses the first ten sprites per scanline on both DMG/CGB.
It neither updates sprite_alloc's bookkeeping nor performs OAM DMA.

kitaqgb/lib/sprite_order.c:57

c
u8 sprite_order_build(SpriteOrder* order, SpriteOrderOamEntry* output, u8 limit)
{
    u8 i;
    u8 count;
    u8 phase;
    u8 priority;
    u8 visited;
    u8 written;
    SpriteOrderItem* item;
    if (order == 0 || output == 0) return 0;
    if (order->items == 0 || order->capacity == 0) return 0;
    if (order->count > order->capacity) return 0;
    if (order->height != 8 && order->height != 16) return 0;
    // Clear all hardware slots regardless of the requested emission limit.
    for (i = 0; i < SPRITE_ORDER_OAM_COUNT; i++) {
        output[i].y = 0;
        output[i].x = 0;
        output[i].tile = 0;
        output[i].flags = 0;
    }
    count = order->count;
    if (count == 0) {
        order->phase = 0;
        return 0;
    }
    if (limit > SPRITE_ORDER_OAM_COUNT) limit = SPRITE_ORDER_OAM_COUNT;
    phase = order->phase;
    while (phase >= count) phase = (u8)(phase - count);
    written = 0;
    for (priority = 0; priority < SPRITE_ORDER_LEVELS && written < limit; priority++) {
        i = phase;
        visited = 0;
        while (visited < count && written < limit) {
            item = &order->items[i];
            if (item->priority == priority) {
                output[written].y = item->oam.y;
                output[written].x = item->oam.x;
                output[written].tile = item->oam.tile;
                output[written].flags = item->oam.flags;
                written++;
            }
            visited++;
            i++;
            if (i >= count) i = 0;
        }
    }
    phase++;
    if (phase >= count) phase = 0;
    order->phase = phase;
    return written;
}
sprite_order_init

제출 저장 공간을 순서 상태에 연결하고 개수와 순환 위상을 초기화합니다. 장면 시작이나 저장 공간 변경 때 사용합니다.

사용 형식

c
u8 sprite_order_init(SpriteOrder* order, SpriteOrderItem* items, u8 capacity, u8 height);

매개변수

order

호출자가 소유한 SpriteOrder의 주소입니다. 사용 전에 초기화하고 갱신은 메인 코드에서 수행하세요.

items

항목당 5바이트의 쓰기 가능한 SpriteOrderItem 배열입니다. capacity개를 할당하고 사용하는 동안 유효하게 유지하세요.

capacity

배열 용량 1..255항목입니다. 바이트 수나 하드웨어 슬롯 수가 아닙니다.

height

높이는 모든 오브젝트가 공유합니다. LCDC의 8×8/8×16 설정에 맞게 8 또는 16을 전달하세요. 라이브러리는 LCDC를 설정하지 않습니다. 8×16 모드에서 하드웨어는 타일 번호의 최하위 비트를 무시합니다.

반환값

성공하면 1, items가 null이거나 용량 0, 높이가 8/16이 아니거나 order가 null이면 0입니다. order가 유효한 실패는 items=NULL, capacity=count=phase=0, height=8로 비활성 상태를 남깁니다. 항목 배열은 건드리지 않습니다.

사용 조건과 제한

sprite_order.h를 포함하고 sprite_order.c를 정확히 한 번 컴파일하세요. 초기화 후 매 프레임 begin, 후보별 push, build 순서로 호출합니다. 순서 제어 라이브러리 자체에는 sprite.c나 전역 변수 정의가 필요 없습니다.

사용 예

c
sprite_init();sprite_order_init(&order_demo,order_demo_items,14,8);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.

sprite_order_init: DMG / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
DMG / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
sprite_order_init: CGB / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
CGB / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
sprite_order_init: CGB / 위상 08 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
CGB / 위상 08 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_order_demo.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_order_demo.gb --cgb=cgb --profile=dev --rst-disable --stack-bank=fixed --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite_order.h:38

선언 주석 원문
Bind writable item storage and select the hardware sprite height (8 or 16).
Return 1 on success. Invalid storage, zero capacity or another height returns
0 and leaves a non-null state disabled. A null state returns 0 without writes.

kitaqgb/lib/sprite_order.c:6

c
u8 sprite_order_init(SpriteOrder* order, SpriteOrderItem* items, u8 capacity, u8 height)
{
    if (order == 0) return 0;
    order->items = 0;
    order->capacity = 0;
    order->count = 0;
    order->height = 8;
    order->phase = 0;
    if (items == 0 || capacity == 0) return 0;
    if (height != 8 && height != 16) return 0;
    order->items = items;
    order->capacity = capacity;
    order->height = height;
    return 1;
}
sprite_order_push

가시 화면과 최소 1픽셀 겹치는 스프라이트 하나를 제출합니다. 완전히 화면 밖인 후보는 OAM 선택 슬롯을 소비하기 전에 거부합니다.

사용 형식

c
u8 sprite_order_push(SpriteOrder* order, s16 x, s16 y, u8 tile, u8 flags, u8 priority);

매개변수

order

호출자가 소유한 SpriteOrder의 주소입니다. 사용 전에 초기화하고 갱신은 메인 코드에서 수행하세요.

x

왼쪽 위 기준 부호 있는 화면 X입니다. 왼쪽 가장자리 −7..159를 허용하며 −8 이하나 160 이상은 완전히 화면 밖입니다. 저장 시 OAM 좌표용으로 8을 더합니다.

y

왼쪽 위 기준 부호 있는 화면 Y입니다. 높이 8은 −7..143, 높이 16은 −15..143을 허용합니다. 저장 시 OAM 좌표용으로 16을 더합니다.

tile

타일 번호 0..255이며 그대로 저장합니다. 8×16 모드는 높이 설명을 참조하세요.

flags

하드웨어 속성 바이트를 그대로 저장합니다. 반전, 배경 뒤 우선순위, DMG/CGB 팔레트, CGB VRAM 뱅크 비트는 기존 하드웨어 의미대로입니다.

priority

소프트웨어 선택 우선순위 0..3이며 0이 먼저입니다. 4 이상은 거부합니다. 하드웨어 flags 바이트와는 별도입니다.

반환값

수락하면 1을 반환하고 count를 늘립니다. null/비활성 상태, 잘못된 높이, 저장 공간 부족, 잘못된 우선순위, 완전히 화면 밖인 오브젝트는 items와 count를 바꾸지 않고 0을 반환합니다.

사용 조건과 제한

높이는 모든 오브젝트가 공유합니다. LCDC의 8×8/8×16 설정에 맞게 8 또는 16을 전달하세요. 라이브러리는 LCDC를 설정하지 않습니다. 8×16 모드에서 하드웨어는 타일 번호의 최하위 비트를 무시합니다.

하드웨어는 각 주사선에 걸친 오브젝트 중 OAM 순서의 앞 10개를 선택합니다. 작은 우선순위 값을 먼저 놓으면 혼잡한 줄에서 중요한 오브젝트를 보호합니다. 순환은 같은 우선순위 안에서 동일한 표시 빈도를 보장하지 않습니다. 높은 우선순위가 10칸을 모두 채우면 그 줄의 낮은 우선순위는 계속 보이지 않습니다.

priority 인수는 배경 뒤 속성과 독립적으로 선택 순서를 제어합니다. DMG에서 선택된 오브젝트가 겹치면 작은 X 좌표가 우선하고 같으면 OAM 순서로 결정합니다. 일반 CGB 컬러 모드는 OAM 순서를 사용하지만 OPRI로 DMG식 순서를 선택한 설정도 적용됩니다. 이 라이브러리는 하드웨어 우선순위 규칙을 바꾸지 않습니다.

사용 예

c
sprite_order_push(&order_demo,8,64,128,0,0);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.

sprite_order_push: DMG / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
DMG / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
sprite_order_push: CGB / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
CGB / 위상 04 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
sprite_order_push: CGB / 위상 08 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.
CGB / 위상 08 — 한 줄에 오브젝트 14개를 놓아 주사선 선택을 보여 줍니다. HIGH 아래 마름모 2개는 높은 우선순위, NORMAL 아래 정사각형 12개는 일반 우선순위입니다. CGB는 빨간 마름모·파란 정사각형, DMG는 회색·검은색입니다. 마름모 2개는 계속 보이고 정사각형은 8개만 보입니다. 0..B는 정사각형 위치입니다. PHASE 04는 4..B, PHASE 08은 8..B와 0..3을 보여 줍니다. 일반 빌드는 프레임 대기 60회마다 PHASE를 진행합니다. 공개 캡처는 같은 프로그램의 위상을 고정했으며 실행판에서도 정사각형 선택 변화가 확인되었습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\sprite_order_demo.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\sprite_order_demo.gb --cgb=cgb --profile=dev --rst-disable --stack-bank=fixed --no-cache --no-disasm
구현과 소스

kitaqgb/lib/sprite_order.h:49

선언 주석 원문
Submit one sprite at signed, top-left SCREEN pixel coordinates. Preserve the
tile and attribute bytes; use priority 0 (first) through 3 (last). Fully
off-screen sprites, invalid priorities, disabled state and full storage return
0 without consuming a slot. Partly visible sprites are accepted. Return 1 on
acceptance. Hardware 8x16 mode still ignores the tile index's low bit.

kitaqgb/lib/sprite_order.c:31

c
u8 sprite_order_push(SpriteOrder* order, s16 x, s16 y, u8 tile, u8 flags, u8 priority)
{
    SpriteOrderItem* item;
    if (order == 0) return 0;
    if (order->items == 0 || order->capacity == 0) return 0;
    if (order->height != 8 && order->height != 16) return 0;
    if (order->count >= order->capacity || priority >= SPRITE_ORDER_LEVELS) return 0;
    if (x <= -8 || x >= 160 || y >= 144) return 0;
    if (order->height == 16) {
        if (y <= -16) return 0;
    } else {
        if (y <= -8) return 0;
    }
    item = &order->items[order->count];
    item->oam.y = (u8)(y + 16);
    item->oam.x = (u8)(x + 8);
    item->oam.tile = tile;
    item->oam.flags = flags;
    item->priority = priority;
    order->count++;
    return 1;
}

system.h — 시작, 프레임 수, 대기, 인터럽트

프레임 대기 횟수, 대기 후 콜백, 마스킹 가능한 CPU 인터럽트를 관리합니다.

gb_disable_interrupts

gb_disable_interrupts는 system_disable_interrupts의 별칭입니다. GB의 CPU 인터럽트를 비활성화합니다.

마스킹 가능한 CPU 인터럽트를 비활성화합니다.

사용 형식

c
void gb_disable_interrupts();

반환값

반환값은 없습니다.

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

보호된 갱신 구간은 짧게 유지하고, 끝난 뒤 인터럽트를 적절히 복원하세요. 인터럽트 마스킹과 프레임 대기 함수의 실행 조건은 별개의 문제입니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

system_disable_interrupts

사용 예

c
gb_disable_interrupts();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 비활성화와 활성화를 짝지어 사용합니다. 별도의 검증 프로그램에서는 CPU 인터럽트 상태도 확인합니다.

gb_disable_interrupts: DMG
DMG
gb_disable_interrupts: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:32

c
#define gb_disable_interrupts system_disable_interrupts

kitaqgb/lib/system.c:52

c
void system_disable_interrupts()
{
    __asm {
        DI
        RET
    }
}
gb_enable_interrupts

gb_enable_interrupts는 system_enable_interrupts의 별칭입니다. GB의 CPU 인터럽트를 활성화합니다.

마스킹 가능한 CPU 인터럽트를 활성화합니다.

사용 형식

c
void gb_enable_interrupts();

반환값

반환값은 없습니다.

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

활성화 전에 인터럽트 소스와 핸들러를 준비하세요. FC에서는 NMI의 활성화·비활성화와 별개입니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

system_enable_interrupts

사용 예

c
gb_enable_interrupts();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 인터럽트를 복원합니다. FC 프로그램은 처리 후 해제하지 않은 IRQ가 반복 실행되지 않도록 먼저 APU 프레임 IRQ와 DMC IRQ 소스를 비활성화합니다.

gb_enable_interrupts: DMG
DMG
gb_enable_interrupts: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:31

c
#define gb_enable_interrupts system_enable_interrupts

kitaqgb/lib/system.c:43

c
void system_enable_interrupts()
{
    __asm {
        EI
        RET
    }
}
gb_frame_count

gb_frame_count는 system_get_frame의 별칭입니다. 래퍼의 대기가 완료된 횟수를 나타내는 16비트 소프트웨어 카운터를 읽습니다.

프레임 대기 래퍼의 16비트 카운터를 읽습니다.

사용 형식

c
u16 gb_frame_count();

반환값

현재 카운터 값인 0~65535를 반환합니다.

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

카운터는 이 래퍼를 통한 대기 횟수를 셉니다. 실제 하드웨어에서 경과한 프레임 수를 자동 측정하지 않습니다. 16비트 범위를 넘으면 0으로 순환합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

system_get_frame

사용 예

c
result[3]=gb_frame_count();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 세 번 대기한 뒤 3을 읽습니다. 순환 검사를 위해 카운터를 명시적으로 65535로 설정하고, 다음 대기 후 0이 되는지 확인합니다.

gb_frame_count: DMG
DMG
gb_frame_count: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:30

c
#define gb_frame_count system_get_frame

kitaqgb/lib/system.c:31

c
u16 system_get_frame()
{
    return kq_system_frame;
}
gb_init

gb_init은 system_init의 별칭입니다. 소프트웨어 프레임 수와 콜백 등록을 초기화합니다.

카운터와 등록된 콜백을 지워 프레임 관리를 초기화합니다.

사용 형식

c
void gb_init();

반환값

반환값은 없습니다.

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

카운터는 이 래퍼를 통한 대기 횟수를 셉니다. 실제 하드웨어에서 경과한 프레임 수를 자동 측정하지 않습니다. 16비트 범위를 넘으면 0으로 순환합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

system_init

사용 예

c
gb_init();result[0]=gb_frame_count();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 콜백을 등록하기 전에 초기 프레임 번호가 0인지 확인합니다.

gb_init: DMG
DMG
gb_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:27

c
#define gb_init system_init

kitaqgb/lib/system.c:7

c
void system_init()
{
    kq_system_frame = 0;
    system_vblank_callback = 0;
}
gb_set_vblank_callback

gb_set_vblank_callback은 system_set_vblank_callback의 별칭입니다. 프레임 대기 후 동기적으로 실행되는 콜백을 등록하거나 해제합니다.

프레임 대기 뒤에 호출할 함수를 등록하거나 교체하거나 해제합니다.

사용 형식

c
void gb_set_vblank_callback(SystemCallback callback);

매개변수

callback

호출할 함수입니다. 0을 지정하면 콜백을 해제합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

인수와 반환값이 없는 함수를 가리키는 일반 포인터입니다. 뱅크 번호를 포함하지 않으므로 호출될 수 있는 동안 대상 코드가 매핑되어 있어야 합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

system_set_vblank_callback

사용 예

c
gb_set_vblank_callback(on_frame);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

콜백을 세 번 호출한 뒤 0을 등록하면 호출이 해제됩니다. 다음 대기에서는 프레임 값이 4가 되지만 콜백 횟수는 3으로 유지됩니다.

gb_set_vblank_callback: DMG
DMG
gb_set_vblank_callback: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:29

c
#define gb_set_vblank_callback system_set_vblank_callback

kitaqgb/lib/system.c:25

c
void system_set_vblank_callback(SystemCallback callback)
{
    system_vblank_callback = callback;
}
gb_wait_vblank

gb_wait_vblank는 system_wait_vblank의 별칭입니다. 프레임 경계를 기다리고 소프트웨어 프레임 수를 증가시킨 뒤 등록된 콜백을 호출합니다.

다음 프레임을 기다리고 카운터를 증가시킨 뒤 등록된 콜백을 호출합니다.

사용 형식

c
void gb_wait_vblank();

반환값

반환값은 없습니다.

사용 조건과 제한

헤더는 구현 이름으로 확장되는 객체형 매크로를 정의합니다. 인수, 반환값, 상태 접근은 대상 함수와 같으며 별칭 때문에 별도의 상태나 처리가 추가되지는 않습니다. 완전한 예제와 빌드 명령처럼 입력에는 input.h/input.c를, 프레임 서비스에는 system.h/system.c를 사용하세요.

콜백은 이 함수 안에서 동기적으로 실행됩니다. 콜백을 등록한다고 인터럽트 핸들러가 설치되는 것은 아닙니다. 카운터는 이 래퍼의 대기 횟수를 세며 실제 하드웨어 프레임 경과를 자동 측정하지 않습니다. 16비트 범위를 넘으면 0으로 순환합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

system_wait_vblank

사용 예

c
gb_wait_vblank();gb_wait_vblank();gb_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

세 번 대기하면 콜백도 세 번 호출되며, 마지막 콜백 안에서 읽은 카운터 값은 3입니다.

gb_wait_vblank: DMG
DMG
gb_wait_vblank: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\system_aliases.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\system_aliases.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:28

c
#define gb_wait_vblank system_wait_vblank

kitaqgb/lib/system.c:15

c
void system_wait_vblank()
{
    __wait_vblank();
    kq_system_frame++;
    if (system_vblank_callback != 0) {
        system_vblank_callback();
    }
}
system_disable_interrupts

마스킹 가능한 CPU 인터럽트를 비활성화합니다.

사용 형식

c
void system_disable_interrupts();

반환값

반환값은 없습니다.

사용 조건과 제한

보호된 갱신 구간은 짧게 유지하고, 끝난 뒤 인터럽트를 적절히 복원하세요. 인터럽트 마스킹과 프레임 대기 함수의 실행 조건은 별개의 문제입니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
system_disable_interrupts();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 비활성화와 활성화를 짝지어 사용합니다. 별도의 검증 프로그램에서는 CPU 인터럽트 상태도 확인합니다.

system_disable_interrupts: DMG
DMG
system_disable_interrupts: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:25

선언 주석 원문
Disable CPU interrupts and return; callers must explicitly re-enable them later.

kitaqgb/lib/system.c:52

c
void system_disable_interrupts()
{
    __asm {
        DI
        RET
    }
}
system_enable_interrupts

마스킹 가능한 CPU 인터럽트를 활성화합니다.

사용 형식

c
void system_enable_interrupts();

반환값

반환값은 없습니다.

사용 조건과 제한

활성화 전에 인터럽트 소스와 핸들러를 준비하세요. FC에서는 NMI의 활성화·비활성화와 별개입니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
system_enable_interrupts();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 인터럽트를 복원합니다. FC 프로그램은 처리 후 해제하지 않은 IRQ가 반복 실행되지 않도록 먼저 APU 프레임 IRQ와 DMC IRQ 소스를 비활성화합니다.

system_enable_interrupts: DMG
DMG
system_enable_interrupts: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:23

선언 주석 원문
Enable CPU interrupts and return using the inline-assembly function body.

kitaqgb/lib/system.c:43

c
void system_enable_interrupts()
{
    __asm {
        EI
        RET
    }
}
system_get_frame

프레임 대기 래퍼의 16비트 카운터를 읽습니다.

사용 형식

c
u16 system_get_frame();

반환값

현재 카운터 값인 0~65535를 반환합니다.

사용 조건과 제한

카운터는 이 래퍼를 통한 대기 횟수를 셉니다. 실제 하드웨어에서 경과한 프레임 수를 자동 측정하지 않습니다. 16비트 범위를 넘으면 0으로 순환합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
result[3]=system_get_frame();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 세 번 대기한 뒤 3을 읽습니다. 순환 검사를 위해 카운터를 명시적으로 65535로 설정하고, 다음 대기 후 0이 되는지 확인합니다.

system_get_frame: DMG
DMG
system_get_frame: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:19

선언 주석 원문
Read the software count of completed system_wait_vblank calls.

kitaqgb/lib/system.c:31

c
u16 system_get_frame()
{
    return kq_system_frame;
}
system_get_frame8

짧은 주기의 반복에 사용할 수 있도록 프레임 카운터의 하위 8비트를 읽습니다.

사용 형식

c
u8 system_get_frame8();

반환값

하위 바이트인 0~255를 반환합니다.

사용 조건과 제한

카운터는 이 래퍼를 통한 대기 횟수를 셉니다. 실제 하드웨어에서 경과한 프레임 수를 자동 측정하지 않습니다. 16비트 범위를 넘으면 0으로 순환합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
result[4]=system_get_frame8();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 세 번 대기한 뒤 3을 읽고, 16비트 카운터가 순환하면 0을 읽습니다.

system_get_frame8: DMG
DMG
system_get_frame8: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:21

선언 주석 원문
Return the low byte of the software frame counter for wrapping 8-bit timing.

kitaqgb/lib/system.c:37

c
u8 system_get_frame8()
{
    return (u8)kq_system_frame;
}
system_init

카운터와 등록된 콜백을 지워 프레임 관리를 초기화합니다.

사용 형식

c
void system_init();

반환값

반환값은 없습니다.

사용 조건과 제한

카운터는 이 래퍼를 통한 대기 횟수를 셉니다. 실제 하드웨어에서 경과한 프레임 수를 자동 측정하지 않습니다. 16비트 범위를 넘으면 0으로 순환합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
system_init();result[0]=system_get_frame();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

예제는 콜백을 등록하기 전에 초기 프레임 번호가 0인지 확인합니다.

system_init: DMG
DMG
system_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:12

선언 주석 원문
Reset the software frame counter and remove any registered callback.

kitaqgb/lib/system.c:7

c
void system_init()
{
    kq_system_frame = 0;
    system_vblank_callback = 0;
}
system_set_vblank_callback

프레임 대기 뒤에 호출할 함수를 등록하거나 교체하거나 해제합니다.

사용 형식

c
void system_set_vblank_callback(SystemCallback callback);

매개변수

callback

호출할 함수입니다. 0을 지정하면 콜백을 해제합니다.

반환값

반환값은 없습니다.

사용 조건과 제한

인수와 반환값이 없는 함수를 가리키는 일반 포인터입니다. 뱅크 번호를 포함하지 않으므로 호출될 수 있는 동안 대상 코드가 매핑되어 있어야 합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
system_set_vblank_callback(on_frame);

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

콜백을 세 번 호출한 뒤 0을 등록하면 호출이 해제됩니다. 다음 대기에서는 프레임 값이 4가 되지만 콜백 횟수는 3으로 유지됩니다.

system_set_vblank_callback: DMG
DMG
system_set_vblank_callback: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:17

선언 주석 원문
Replace the callback used by system_wait_vblank; null disables the callback.

kitaqgb/lib/system.c:25

c
void system_set_vblank_callback(SystemCallback callback)
{
    system_vblank_callback = callback;
}
system_wait_vblank

다음 프레임을 기다리고 카운터를 증가시킨 뒤 등록된 콜백을 호출합니다.

사용 형식

c
void system_wait_vblank();

반환값

반환값은 없습니다.

사용 조건과 제한

콜백은 이 함수 안에서 동기적으로 실행됩니다. 콜백을 등록한다고 인터럽트 핸들러가 설치되는 것은 아닙니다. 카운터는 이 래퍼의 대기 횟수를 세며 실제 하드웨어 프레임 경과를 자동 측정하지 않습니다. 16비트 범위를 넘으면 0으로 순환합니다.

GB에서는 LCD가 꺼져 있으면 대기가 즉시 끝나지만, 래퍼는 여전히 카운터를 증가시키고 콜백을 호출합니다. 초기화만으로 LCD나 인터럽트 소스가 설정되지는 않습니다.

이 완전한 예제는 기본 Legacy ABI로 빌드하세요. 콜백이 함수 포인터 호출을 사용하는데 컴파일러는 --abi=stack에서 이를 미지원으로 거부합니다. 별칭을 써도 같은 제한이 적용됩니다.

사용 예

c
system_wait_vblank();system_wait_vblank();system_wait_vblank();result[1]=frame_calls;result[2]=frame_seen;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

세 번 대기하면 콜백도 세 번 호출되며, 마지막 콜백 안에서 읽은 카운터 값은 3입니다.

system_wait_vblank: DMG
DMG
system_wait_vblank: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\batch_services.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\batch_services.gb --no-cache --no-disasm --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --cart=mbc5 --romsize=64k
구현과 소스

kitaqgb/lib/system.h:15

선언 주석 원문
Wait for VBlank, count this wrapper call, then invoke the callback synchronously.
The counter wraps at 16 bits and is not an independent hardware frame clock.

kitaqgb/lib/system.c:15

c
void system_wait_vblank()
{
    __wait_vblank();
    kq_system_frame++;
    if (system_vblank_callback != 0) {
        system_vblank_callback();
    }
}

vram.h — 큐를 통한 VRAM 갱신과 전송

나중에 실행할 VRAM 쓰기 명령 큐를 비우고 오버플로 기록을 지웁니다. 화면을 지우거나 타일 그래픽을 전송하거나 하드웨어 VRAM을 할당하지는 않습니다.

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

__wait_vblank로 기다린 뒤 vram_flush_now를 호출합니다. 소량의 화면 갱신을 묶어 실행할 때 사용합니다. 한 번 기다린다고 전송량이 제한되거나 전체 작업이 한 VBlank 안에 끝나는 것은 아닙니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

vram_clear_queue

대기 중인 VRAM 명령을 실행하지 않고 버리며 넘침 플래그도 지웁니다.

사용 형식

c
void vram_clear_queue();

반환값

없음(void).

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
vram_clear_queue();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_clear_queue: DMG
DMG
vram_clear_queue: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:41

선언 주석 원문
Discard pending commands and clear the latched overflow flag without writing VRAM.

kitaqgb/lib/vram.c:41

c
void vram_clear_queue()
{
    kq_vram_queue_used = 0;
    kq_vram_queue_overflowed = 0;
}
vram_flush

__wait_vblank로 기다린 뒤 vram_flush_now를 호출합니다. 소량의 화면 갱신을 묶어 실행할 때 사용합니다. 한 번 기다린다고 전송량이 제한되거나 전체 작업이 한 VBlank 안에 끝나는 것은 아닙니다.

사용 형식

c
void vram_flush();

반환값

없음(void).

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

VRAM의 대상 바이트 주소(0x8000–0x9FFF)입니다. 뱅크는 실행 시 선택된 값을 따릅니다. 연속 주소로 전송하며 타일맵 행 끝에서 줄을 바꾸지 않습니다. 대상 범위 전체가 유효해야 합니다. LCD가 켜진 상태의 안전한 쓰기 경로는 인터럽트를 활성화할 수 있어 호출 전의 인터럽트 금지 상태를 보존하지 않습니다.

사용 예

c
vram_flush(); // One small write through the VBlank/NMI path.

if (vram_get_queue_used()!=0) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_flush: DMG
DMG
vram_flush: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:64

선언 주석 원문
Wait for VBlank before executing the queue. Waiting once does not itself limit
the queued workload to the available VBlank duration.

kitaqgb/lib/vram.c:148

c
void vram_flush()
{
    __wait_vblank();
    vram_flush_now();
}
vram_flush_now

등록된 모든 명령을 순서대로 실행한 뒤 사용 수를 0으로 만듭니다. 이 함수 자체는 VBlank를 기다리지 않습니다. LCD가 켜져 있으면 호출된 안전한 VRAM 내장 함수가 쓰기 가능한 구간을 기다리지만, 큰 큐는 여러 주사선이나 프레임에 걸칠 수 있습니다. 오버플로 기록은 유지됩니다.

사용 형식

c
void vram_flush_now();

반환값

없음(void).

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

VRAM의 대상 바이트 주소(0x8000–0x9FFF)입니다. 뱅크는 실행 시 선택된 값을 따릅니다. 연속 주소로 전송하며 타일맵 행 끝에서 줄을 바꾸지 않습니다. 대상 범위 전체가 유효해야 합니다. LCD가 켜진 상태의 안전한 쓰기 경로는 인터럽트를 활성화할 수 있어 호출 전의 인터럽트 금지 상태를 보존하지 않습니다.

사용 예

c
// Rendering is stopped here. On FC, commit readiness before direct execution.

vram_flush_now();
after_flush=vram_get_queue_used();
if (after_flush!=0) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_flush_now: DMG
DMG
vram_flush_now: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:61

선언 주석 원문
Execute pending commands in insertion order without waiting for VBlank here.
The caller must arrange suitable VRAM access timing and a sufficient transfer budget.
Only the used count is cleared; overflow stays latched until an explicit reset.

kitaqgb/lib/vram.c:125

c
void vram_flush_now()
{
    u8 i = 0;
    while (i < kq_vram_queue_used) {
        VramCommand* cmd = &kq_vram_queue[(__safe_index u8)i];
        if (cmd->kind == VRAM_CMD_BG_TILE) {
            __settile_xy(cmd->x, cmd->y, cmd->value);
        } else if (cmd->kind == VRAM_CMD_BG_RECT) {
            __settile_rect(cmd->x, cmd->y, cmd->w, cmd->h, cmd->value);
        } else if (cmd->kind == VRAM_CMD_BG_BLOCK) {
            __settilemap_rect(cmd->dst, cmd->x, cmd->y, cmd->w, cmd->h, cmd->src);
        } else if (cmd->kind == VRAM_CMD_MEMCPY) {
            __vram_copy(cmd->dst, cmd->src, cmd->len);
        } else if (cmd->kind == VRAM_CMD_MEMSET) {
            __vram_fill(cmd->dst, cmd->value, cmd->len);
        }
        i++;
    }
    kq_vram_queue_used = 0;
}
vram_get_overflowed

큐 넘침 플래그를 지우지 않고 읽습니다. 이전 등록 실패가 남아 있을 수 있습니다.

사용 형식

c
u8 vram_get_overflowed();

반환값

기록된 오버플로가 없으면 0입니다. 등록이 거부되면 1이 되고 명시적으로 초기화할 때까지 유지됩니다. 큐 실행만으로는 지워지지 않습니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
overflow_seen=vram_get_overflowed();
if (overflow_seen!=1) failures++;
// Reading the latch again does not clear it.
if (vram_get_overflowed()!=1) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_get_overflowed: DMG
DMG
vram_get_overflowed: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:73

선언 주석 원문
Read the overflow latch without clearing it.

kitaqgb/lib/vram.c:175

c
u8 vram_get_overflowed()
{
    return kq_vram_queue_overflowed;
}
vram_get_queue_capacity

이 API의 로컬 버전 차이는 2026-10-03 변경 사항과 검증을 참조하세요.

현재 사용량과 관계없이 명령 버퍼의 전체 용량을 반환합니다.

사용 형식

c
u8 vram_get_queue_capacity();

반환값

여기에 설명한 기종별 단위의 부호 없는 8비트 값입니다. 조회만으로 큐를 변경하거나 실행하지 않습니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
capacity=vram_get_queue_capacity();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_get_queue_capacity: DMG
DMG
vram_get_queue_capacity: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:69

선언 주석 원문
Return the total number of command slots, independent of queue usage.
This is command-buffer capacity, not free space in hardware VRAM.

kitaqgb/lib/vram.c:162

c
u8 vram_get_queue_capacity()
{
    return VRAM_QUEUE_MAX;
}
vram_get_queue_free

명령 버퍼의 전체 용량에서 현재 사용량을 뺀 여유 용량을 반환합니다. 다음 레코드나 작업 묶음 전체가 들어가는지 등록 전에 확인하세요. 이 조회 함수는 공간을 예약하지 않습니다.

사용 형식

c
u8 vram_get_queue_free();

반환값

여기에 설명한 기종별 단위의 부호 없는 8비트 값입니다. 조회만으로 큐를 변경하거나 실행하지 않습니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
available=vram_get_queue_free();
if (used+available!=capacity) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_get_queue_free: DMG
DMG
vram_get_queue_free: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:71

선언 주석 원문
Return the remaining command-slot capacity.

kitaqgb/lib/vram.c:169

c
u8 vram_get_queue_free()
{
    return (u8)(VRAM_QUEUE_MAX - kq_vram_queue_used);
}
vram_get_queue_used

대기 중인 명령이 현재 차지하는 명령 버퍼 사용량을 반환합니다. 비디오 메모리에 쓸 데이터의 바이트 수가 아닙니다.

사용 형식

c
u8 vram_get_queue_used();

반환값

여기에 설명한 기종별 단위의 부호 없는 8비트 값입니다. 조회만으로 큐를 변경하거나 실행하지 않습니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
used=vram_get_queue_used();

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_get_queue_used: DMG
DMG
vram_get_queue_used: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:66

선언 주석 원문
Return the number of queued commands, not the number of transfer bytes.

kitaqgb/lib/vram.c:155

c
u8 vram_get_queue_used()
{
    return kq_vram_queue_used;
}
vram_init

나중에 실행할 VRAM 쓰기 명령 큐를 비우고 오버플로 기록을 지웁니다. 화면을 지우거나 타일 그래픽을 전송하거나 하드웨어 VRAM을 할당하지는 않습니다.

사용 형식

c
void vram_init();

반환값

없음(void).

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
vram_init();
if (vram_get_queue_used()!=0 || vram_get_overflowed()!=0) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_init: DMG
DMG
vram_init: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:39

선언 주석 원문
Start with an empty command queue and a clear overflow flag.

kitaqgb/lib/vram.c:34

c
void vram_init()
{
    kq_vram_queue_used = 0;
    kq_vram_queue_overflowed = 0;
}
vram_queue_bg_block

src의 w × h개 타일 번호를 base의 맵에 사각형으로 쓰도록 등록합니다. 원본은 한 행에 w바이트씩 빈틈없이 저장하며 대상 행 간격은 32바이트입니다. 원본 포인터를 보관하므로 실행 전에 데이터를 바꾸면 표시되는 블록에도 반영됩니다.

사용 형식

c
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);

매개변수

base

타일과 사각형 명령은 실행 시 LCDC 비트 3으로 배경 맵을 선택합니다. CGB의 타일 번호는 VRAM 뱅크 0을 사용하세요. 블록 전송은 명시한 시작 주소를 사용하며, 보통 0x9800 또는 0x9C00입니다. 행 간격은 32바이트이고 좌표를 잘라 주지 않습니다.

x, y

8×8타일 단위의 왼쪽 위 좌표이며 픽셀 단위가 아닙니다. 클리핑하지 않습니다. 대상 사각형을 x + w <= 32, GB는 y + h <= 32, FC 네임테이블 타일 영역은 y + h <= 30 안에 두세요. 타일 하나는 너비와 높이 1로 계산합니다.

w, h

타일 단위의 너비와 높이를 부호 없는 8비트 값으로 지정합니다. 블록 원본은 행 순서로 w * h바이트입니다. 크기가 0이면 화면에 쓰지 않지만 큐 사용량은 기종별 레코드 규칙을 따릅니다.

src

실행 때까지 보관하는 읽기 가능한 바이트의 근거리 포인터입니다. 실행이 끝날 때까지 데이터의 수명과 메모리·ROM 뱅크 매핑을 유지하세요. 뱅크 번호나 데이터 사본을 저장하지 않습니다. 비어 있지 않은 전송에는 유효한 원본이 필요하며 수명이 끝난 지역 배열을 사용하면 안 됩니다.

반환값

이번 명령을 등록하면 1, 빈 슬롯이 없으면 0입니다. 실패하면 오버플로를 기록하고 기존 명령은 유지합니다. 이전 오버플로가 있더라도 이번 등록에 성공하면 1을 반환합니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

타일과 사각형 명령은 실행 시 LCDC 비트 3으로 배경 맵을 선택합니다. CGB의 타일 번호는 VRAM 뱅크 0을 사용하세요. 블록 전송은 명시한 시작 주소를 사용하며, 보통 0x9800 또는 0x9C00입니다. 행 간격은 32바이트이고 좌표를 잘라 주지 않습니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
check_result=vram_queue_bg_block(MAP_BASE,10,4,3,2,block);
block[0]=1; // The queued pointer sees this change when the queue executes.
if (check_result!=1) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_queue_bg_block: DMG
DMG
vram_queue_bg_block: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:50

선언 주석 원문
Queue a tile-map rectangle while retaining src rather than copying its bytes.
Keep the source data and its ROM bank accessible until the queue is flushed.

kitaqgb/lib/vram.c:79

c
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src)
{
    VramCommand* cmd = vram_push(VRAM_CMD_BG_BLOCK);
    if (cmd == 0) return 0;
    cmd->dst = base;
    cmd->x = x;
    cmd->y = y;
    cmd->w = w;
    cmd->h = h;
    cmd->src = src;
    return 1;
}
vram_queue_bg_rect

배경 맵의 사각형을 같은 타일 번호로 채우는 작업을 등록합니다. 왼쪽 위 타일 좌표는 (x, y), 크기는 w × h타일입니다. 단색 타일은 채워진 사각형을 만들고, 무늬 타일은 각 칸에 같은 무늬를 반복합니다.

사용 형식

c
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);

매개변수

x, y

8×8타일 단위의 왼쪽 위 좌표이며 픽셀 단위가 아닙니다. 클리핑하지 않습니다. 대상 사각형을 x + w <= 32, GB는 y + h <= 32, FC 네임테이블 타일 영역은 y + h <= 30 안에 두세요. 타일 하나는 너비와 높이 1로 계산합니다.

w, h

타일 단위의 너비와 높이를 부호 없는 8비트 값으로 지정합니다. 블록 원본은 행 순서로 w * h바이트입니다. 크기가 0이면 화면에 쓰지 않지만 큐 사용량은 기종별 레코드 규칙을 따릅니다.

tile

0~255의 타일 맵 바이트 값입니다. 해당 그래픽을 따로 로드하고 원하는 패턴 테이블·주소 모드를 선택하세요. 타일 번호는 포인터나 색상 값이 아닙니다.

반환값

이번 명령을 등록하면 1, 빈 슬롯이 없으면 0입니다. 실패하면 오버플로를 기록하고 기존 명령은 유지합니다. 이전 오버플로가 있더라도 이번 등록에 성공하면 1을 반환합니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

타일과 사각형 명령은 실행 시 LCDC 비트 3으로 배경 맵을 선택합니다. CGB의 타일 번호는 VRAM 뱅크 0을 사용하세요. 블록 전송은 명시한 시작 주소를 사용하며, 보통 0x9800 또는 0x9C00입니다. 행 간격은 32바이트이고 좌표를 잘라 주지 않습니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
check_result=vram_queue_bg_rect(2,4,4,3,1); // A filled 32x24 rectangle at (16,32).
if (check_result!=1) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_queue_bg_rect: DMG
DMG
vram_queue_bg_rect: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:47

선언 주석 원문
Queue a rectangle filled with one tile value; coordinates and dimensions are in tiles.

kitaqgb/lib/vram.c:65

c
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile)
{
    VramCommand* cmd = vram_push(VRAM_CMD_BG_RECT);
    if (cmd == 0) return 0;
    cmd->x = x;
    cmd->y = y;
    cmd->w = w;
    cmd->h = h;
    cmd->value = tile;
    return 1;
}
vram_queue_bg_tile

배경의 (x, y)에 타일 번호 하나를 쓰는 명령을 등록합니다. 화면의 타일은 큐 실행 시 바뀝니다. 맵 항목을 쓰며, 타일 픽셀 데이터를 전송하거나 팔레트 속성을 바꾸지는 않습니다.

사용 형식

c
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);

매개변수

x, y

8×8타일 단위의 왼쪽 위 좌표이며 픽셀 단위가 아닙니다. 클리핑하지 않습니다. 대상 사각형을 x + w <= 32, GB는 y + h <= 32, FC 네임테이블 타일 영역은 y + h <= 30 안에 두세요. 타일 하나는 너비와 높이 1로 계산합니다.

tile

0~255의 타일 맵 바이트 값입니다. 해당 그래픽을 따로 로드하고 원하는 패턴 테이블·주소 모드를 선택하세요. 타일 번호는 포인터나 색상 값이 아닙니다.

반환값

이번 명령을 등록하면 1, 빈 슬롯이 없으면 0입니다. 실패하면 오버플로를 기록하고 기존 명령은 유지합니다. 이전 오버플로가 있더라도 이번 등록에 성공하면 1을 반환합니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

타일과 사각형 명령은 실행 시 LCDC 비트 3으로 배경 맵을 선택합니다. CGB의 타일 번호는 VRAM 뱅크 0을 사용하세요. 블록 전송은 명시한 시작 주소를 사용하며, 보통 0x9800 또는 0x9C00입니다. 행 간격은 32바이트이고 좌표를 잘라 주지 않습니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
check_result=vram_queue_bg_tile(2,2,1); // A solid 8x8 tile at pixel (16,16).
if (check_result!=1) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_queue_bg_tile: DMG
DMG
vram_queue_bg_tile: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:43

선언 주석 원문
Queue a single background tile write; return zero if no command slot is available.

kitaqgb/lib/vram.c:48

c
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile)
{
    VramCommand* cmd = vram_push(VRAM_CMD_BG_TILE);
    if (cmd == 0) return 0;
    cmd->x = x;
    cmd->y = y;
    cmd->value = tile;
    return 1;
}
vram_queue_memcpy

src에서 dst로 연속된 len바이트를 복사하도록 등록합니다. 원본과 대상은 한 바이트씩 진행하며 타일 행 간격을 적용하지 않습니다. 맵 바이트나 쓰기 가능한 타일 패턴 바이트를 전송할 수 있지만 형식을 변환하거나 타일당 바이트 수를 계산하지는 않습니다.

사용 형식

c
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);

매개변수

dst

VRAM의 대상 바이트 주소(0x8000–0x9FFF)입니다. 뱅크는 실행 시 선택된 값을 따릅니다. 연속 주소로 전송하며 타일맵 행 끝에서 줄을 바꾸지 않습니다. 대상 범위 전체가 유효해야 합니다. LCD가 켜진 상태의 안전한 쓰기 경로는 인터럽트를 활성화할 수 있어 호출 전의 인터럽트 금지 상태를 보존하지 않습니다.

src

실행 때까지 보관하는 읽기 가능한 바이트의 근거리 포인터입니다. 실행이 끝날 때까지 데이터의 수명과 메모리·ROM 뱅크 매핑을 유지하세요. 뱅크 번호나 데이터 사본을 저장하지 않습니다. 비어 있지 않은 전송에는 유효한 원본이 필요하며 수명이 끝난 지역 배열을 사용하면 안 됩니다.

len

연속된 바이트 수로 0~65535를 지정합니다. 타일 수가 아닙니다. 전체 범위가 유효한 원본과 쓰기 가능한 대상에 들어가도록 하세요. 범위 검사나 16비트 주소 순환 방지는 하지 않습니다.

반환값

이번 명령을 등록하면 1, 빈 슬롯이 없으면 0입니다. 실패하면 오버플로를 기록하고 기존 명령은 유지합니다. 이전 오버플로가 있더라도 이번 등록에 성공하면 1을 반환합니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
check_result=vram_queue_memcpy(MAP_BASE+8*32+2,strip,3);
if (check_result!=1) failures++; // Copy three map bytes, not three tile patterns.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_queue_memcpy: DMG
DMG
vram_queue_memcpy: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:53

선언 주석 원문
Queue a byte transfer and retain the source pointer. The source must remain
valid and visible until flush; len is measured in bytes, not tiles.

kitaqgb/lib/vram.c:94

c
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len)
{
    VramCommand* cmd = vram_push(VRAM_CMD_MEMCPY);
    if (cmd == 0) return 0;
    cmd->dst = dst;
    cmd->src = (const u8*)src;
    cmd->len = len;
    return 1;
}
vram_queue_memset

dst부터 연속된 len바이트를 한 바이트 값 value로 채우도록 등록합니다. 여러 바이트로 된 타일 패턴이 아닌 한 바이트를 반복하며, 맵의 32바이트 행 간격을 자동으로 적용하지 않습니다.

사용 형식

c
u8 vram_queue_memset(u16 dst, u8 value, u16 len);

매개변수

dst

VRAM의 대상 바이트 주소(0x8000–0x9FFF)입니다. 뱅크는 실행 시 선택된 값을 따릅니다. 연속 주소로 전송하며 타일맵 행 끝에서 줄을 바꾸지 않습니다. 대상 범위 전체가 유효해야 합니다. LCD가 켜진 상태의 안전한 쓰기 경로는 인터럽트를 활성화할 수 있어 호출 전의 인터럽트 금지 상태를 보존하지 않습니다.

value

0~255의 한 바이트를 반복해서 씁니다. 화면에서의 의미는 대상이 타일 번호인지, 픽셀 비트플레인인지, 다른 바이트 구조인지에 따라 달라집니다.

len

연속된 바이트 수로 0~65535를 지정합니다. 타일 수가 아닙니다. 전체 범위가 유효한 원본과 쓰기 가능한 대상에 들어가도록 하세요. 범위 검사나 16비트 주소 순환 방지는 하지 않습니다.

반환값

이번 명령을 등록하면 1, 빈 슬롯이 없으면 0입니다. 실패하면 오버플로를 기록하고 기존 명령은 유지합니다. 이전 오버플로가 있더라도 이번 등록에 성공하면 1을 반환합니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
check_result=vram_queue_memset(MAP_BASE+8*32+10,1,5);
if (check_result!=1) failures++; // Five solid tiles form a 40x8 horizontal bar.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_queue_memset: DMG
DMG
vram_queue_memset: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:57

선언 주석 원문
Queue a byte fill and return zero if the command queue is full.

kitaqgb/lib/vram.c:111

c
u8 vram_queue_memset(u16 dst, u8 value, u16 len)
{
    VramCommand* cmd = vram_push(VRAM_CMD_MEMSET);
    if (cmd == 0) return 0;
    cmd->dst = dst;
    cmd->value = value;
    cmd->len = len;
    return 1;
}
vram_queue_tile

vram_queue_tile은 같은 인수로 vram_queue_bg_tile을 직접 호출하고 같은 값을 반환합니다. 배경 맵 항목 하나를 쓰는 짧은 이름이며, 스프라이트 조작이나 타일 그래픽 전송이 아닙니다.

사용 형식

c
u8 vram_queue_tile(u8 x, u8 y, u8 tile);

매개변수

x, y

8×8타일 단위의 왼쪽 위 좌표이며 픽셀 단위가 아닙니다. 클리핑하지 않습니다. 대상 사각형을 x + w <= 32, GB는 y + h <= 32, FC 네임테이블 타일 영역은 y + h <= 30 안에 두세요. 타일 하나는 너비와 높이 1로 계산합니다.

tile

0~255의 타일 맵 바이트 값입니다. 해당 그래픽을 따로 로드하고 원하는 패턴 테이블·주소 모드를 선택하세요. 타일 번호는 포인터나 색상 값이 아닙니다.

반환값

이번 명령을 등록하면 1, 빈 슬롯이 없으면 0입니다. 실패하면 오버플로를 기록하고 기존 명령은 유지합니다. 이전 오버플로가 있더라도 이번 등록에 성공하면 1을 반환합니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

타일과 사각형 명령은 실행 시 LCDC 비트 3으로 배경 맵을 선택합니다. CGB의 타일 번호는 VRAM 뱅크 0을 사용하세요. 블록 전송은 명시한 시작 주소를 사용하며, 보통 0x9800 또는 0x9C00입니다. 행 간격은 32바이트이고 좌표를 잘라 주지 않습니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
check_result=vram_queue_tile(4,2,1); // The short alias draws at pixel (32,16).
if (check_result!=1) failures++;

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_queue_tile: DMG
DMG
vram_queue_tile: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:45

선언 주석 원문
Provide the short alias for a queued background tile write.

kitaqgb/lib/vram.c:59

c
u8 vram_queue_tile(u8 x, u8 y, u8 tile)
{
    return vram_queue_bg_tile(x, y, tile);
}
vram_queue_tiles

vram_queue_tiles는 vram_queue_memcpy를 직접 호출합니다. len은 타일 수가 아닌 바이트 수입니다. 보관하는 원본 포인터, 큐 레코드, 반환값과 실행 시점도 같습니다.

사용 형식

c
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);

매개변수

dst

VRAM의 대상 바이트 주소(0x8000–0x9FFF)입니다. 뱅크는 실행 시 선택된 값을 따릅니다. 연속 주소로 전송하며 타일맵 행 끝에서 줄을 바꾸지 않습니다. 대상 범위 전체가 유효해야 합니다. LCD가 켜진 상태의 안전한 쓰기 경로는 인터럽트를 활성화할 수 있어 호출 전의 인터럽트 금지 상태를 보존하지 않습니다.

src

실행 때까지 보관하는 읽기 가능한 바이트의 근거리 포인터입니다. 실행이 끝날 때까지 데이터의 수명과 메모리·ROM 뱅크 매핑을 유지하세요. 뱅크 번호나 데이터 사본을 저장하지 않습니다. 비어 있지 않은 전송에는 유효한 원본이 필요하며 수명이 끝난 지역 배열을 사용하면 안 됩니다.

len

연속된 바이트 수로 0~65535를 지정합니다. 타일 수가 아닙니다. 전체 범위가 유효한 원본과 쓰기 가능한 대상에 들어가도록 하세요. 범위 검사나 16비트 주소 순환 방지는 하지 않습니다.

반환값

이번 명령을 등록하면 1, 빈 슬롯이 없으면 0입니다. 실패하면 오버플로를 기록하고 기존 명령은 유지합니다. 이전 오버플로가 있더라도 이번 등록에 성공하면 1을 반환합니다.

사용 조건과 제한

GB의 단위는 명령 슬롯이며 기본 용량은 32입니다. 큰 전송이나 길이 0도 각 등록 함수가 슬롯 하나를 사용합니다. VRAM_QUEUE_MAX는 1~255 범위에서 모든 컴파일 단위에 동일하게 설정하세요. 빈 큐는 used=0, free=capacity입니다.

큐 등록과 실행이 겹치지 않도록 조율하세요. 인터럽트가 실행 중일 때 추가하거나 관리 변수를 직접 바꾸거나 보관된 원본 데이터를 의도치 않게 덮어쓰지 마세요. 이 API는 잠금이나 이중 버퍼링을 제공하지 않습니다. 용량은 명령 버퍼의 용량이며 하드웨어 VRAM의 빈 바이트 수가 아닙니다.

사용 예

c
check_result=vram_queue_tiles(MAP_BASE+8*32+6,strip+1,2);
if (check_result!=1) failures++; // This alias also measures length in bytes.

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

완성 프로그램으로 지연 쓰기, 큐 용량 관리, 오버플로 복구를 익힙니다. 그리기 등록 7회가 GB에서는 전체 32슬롯 중 7슬롯, FC에서는 전체 128바이트 중 52바이트를 사용합니다. CAPACITY/USED/FREE는 각각 032/007/025, 128/052/076입니다. AFTER FLUSH와 FAILED CHECKS는 000, OVERFLOW SEEN은 001이어야 합니다. 가득 찬 큐에 의도적으로 추가해 알림을 검사합니다. 읽거나 실행해도 알림은 남고 큐를 지우면 사라집니다. FC에서는 커밋하지 않은 직접 실행이 큐를 그대로 두는지도 확인합니다.

이미지 좌표는 왼쪽 위를 원점으로 하는 픽셀 단위입니다. (16,16)과 (32,16)에 채워진 8 × 8 정사각형, (16,32)에 채워진 32 × 24 사각형, (80,64)에 40 × 8 가로 막대가 나타나야 합니다. 마지막 VBlank 쓰기로 (144,80)에 8 × 8 정사각형을 추가합니다. 취소한 쓰기 위치 (144,24)는 비어 있어야 합니다. DMG는 흰 바탕에 검은 도형, CGB는 흰 바탕에 빨강·파랑·초록 도형, FC는 검은 바탕에 빨강·파랑·초록 도형입니다. 에뮬레이터 이미지이며 실제 기기 검증은 아닙니다.

복사 처리를 구별하기 위해 자체 제작한 8 × 8 패턴 세 가지를 사용합니다. 타일 1은 전체 채움, 2는 왼쪽 네 열만 채움, 3은 위쪽 한 픽셀에서 아래쪽 여덟 픽셀로 넓어지는 왼쪽 정렬 삼각형입니다. (80,32)의 3 × 2타일 블록은 [1,2,3] / [3,0,2]여야 하며 0은 빈칸입니다. 등록 후 원본 첫 바이트를 바꾸므로 왼쪽 위가 채워지면 원본 포인터를 보관한다는 뜻입니다. (16,64)의 복사는 [1,2,3], (48,64)의 tiles 별칭은 [2,3]을 표시합니다. 크기는 각각 24 × 16, 24 × 8, 16 × 8픽셀입니다.

CGB에서는 위쪽 정사각형 두 개, 세 패턴 복사, 마지막 VBlank 정사각형을 빨간색으로 표시합니다. 32 × 24 사각형과 두 패턴 복사는 파란색, 3 × 2타일 블록과 40 × 8 막대는 초록색입니다. 글자는 흰 바탕에 검은색입니다. 모양뿐 아니라 그려진 각 픽셀의 색도 검사합니다.

vram_queue_tiles: DMG
DMG
vram_queue_tiles: CGB
CGB

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaqgb\lib\vram.c .\kitaq-docs\samples\api-examples\gb\vram_queue_shapes.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\vram_queue_shapes.gb --profile=dev --rst-disable --stack-bank=fixed --cgb=cgb --no-cache --no-disasm
구현과 소스

kitaqgb/lib/vram.h:55

선언 주석 원문
Alias the queued byte-copy operation; this does not convert a tile count to bytes.

kitaqgb/lib/vram.c:105

c
u8 vram_queue_tiles(u16 dst, const void* src, u16 len)
{
    return vram_queue_memcpy(dst, src, len);
}

wire3d.h — DMG용 와이어프레임

흑백 3D 선 그리기입니다. 모델 정점·모서리·면과 오브젝트 위치·회전·배율을 제공하세요. 초기화, 프레임 시작, 그리기, 업로드 순서로 사용합니다. 물리는 별도입니다. 각도는 한 바퀴당 16단계이고 모델 배율 256이 1배입니다.

Vec3는 x/y/z, Edge는 정점 인덱스 a/b, Face는 삼각형 인덱스 a/b/c를 담습니다. Model의 vertices, edges, faces는 이 배열을 가리키고 각 count는 길이를 나타냅니다. edge_faces에는 인접 면 인덱스 f0/f1이 들어가며, 없는 면은 FACE_NONE입니다. flags의 MODEL_HIDDEN_LINES는 면 기반 모서리 선택을 요청합니다. 투영된 부호 있는 면적으로 면 방향을 결정하므로 정점 순서가 중요합니다.

Object는 모델 참조, 위치 x/y/z, 각도 rx/ry/rz, scale_q8, visible을 저장합니다. 여러 오브젝트가 모델을 공유할 수 있지만 그리기는 테이블을 복사하거나 ROM 뱅크를 자동 전환하지 않습니다. 그리는 동안 참조 데이터를 계속 읽을 수 있어야 합니다. CGB Object에는 색상 인덱스도 있습니다.

높이 96의 Model에는 edge_masks와 edge_mask_count도 있습니다. 오브젝트 요에 따라 선택되는 16비트 모서리 마스크의 RAM 테이블을 제공하거나, 사용하지 않으면 두 필드를 모두 0으로 설정하세요.

Wire3D_BeginFrame

프레임 그리기를 시작하고 가림 검사를 끕니다.

사용 형식

c
void Wire3D_BeginFrame();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 스테이징 픽셀과 가림 마스크를 지우고 가림 필터를 끕니다. 표시 중인 VRAM 프레임과 대기 중인 BG 타일 큐는 바꾸지 않습니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_BeginFrame: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_BeginFrame: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:34

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Clear staged pixels and occlusion mask and disable occlusion filtering.
This leaves the displayed VRAM frame and pending BG tile queue unchanged.

kitaqgb/lib/wire3d_dmg.c:2641

c
void Wire3DDMG_BeginFrame()
{

    w3ddmg_clear_stage_asm();
    w3ddmg_clear_occlusion_mask();




    w3ddmg_occlusion_active = 0;
}
Wire3D_DrawLine2D

양 끝점을 포함하는 4방향 연결 화면 좌표 선을 스테이징 영역에 그립니다.

사용 형식

c
void Wire3D_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 양 끝점을 포함한 연결 선을 128×96 스테이징 영역에 그립니다. DrawScene 중에는 5점 샘플 기반의 대략적인 가림 제외를 사용하고, 그 외에는 바로 그립니다. 뷰포트 좌표를 지정하세요. VRAM은 EndFrame에서만 갱신됩니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_DrawLine2D: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_DrawLine2D: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:35

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Draw a connected line into the 128x96 stage, including endpoints. During
DrawScene, use the coarse five-sample occlusion rejection; otherwise draw directly.
Supply viewport coordinates. VRAM is updated only by EndFrame.

kitaqgb/lib/wire3d_dmg.c:2685

c
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by)
{




    if (w3ddmg_occlusion_active)
    {
        w3ddmg_line_stage_masked_c(ax, ay, bx, by);
        return;
    }

    w3ddmg_line_x0 = ax;
    w3ddmg_line_y0 = ay;
    w3ddmg_line_x1 = bx;
    w3ddmg_line_y1 = by;
    if (ax < 128 && bx < 128 && ay < WIRE3D_DMG_SCREEN_H && by < WIRE3D_DMG_SCREEN_H)
        w3ddmg_line_inside_asm();
    else
        w3ddmg_line_stage_asm();
}
Wire3D_DrawLine3D

두 월드 좌표 끝점을 투영하고 그 사이에 선을 그립니다.

사용 형식

c
void Wire3D_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);

매개변수

ax

월드 좌표계에서 시작점의 X 성분입니다.

ay

월드 좌표계에서 시작점의 Y 성분입니다.

az

월드 좌표계에서 시작점의 Z 성분입니다.

bx

월드 좌표계에서 끝점의 X 성분입니다.

by

월드 좌표계에서 끝점의 Y 성분입니다.

bz

월드 좌표계에서 끝점의 Z 성분입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 두 월드 끝점을 투영하고 둘 다 깊이 범위를 통과할 때만 그립니다. 경계를 가로지르는 선분과 근·원평면의 교점을 구하지 않습니다. 투영된 끝점은 각각 화면 가장자리로 제한합니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_DrawLine3D: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_DrawLine3D: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:36

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Project both world endpoints and draw only when both pass the depth range.
Do not intersect a crossing segment with near/far planes; projected endpoints
are independently clamped to the screen edges.

kitaqgb/lib/wire3d_dmg.c:2808

c
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz)
{
    w3ddmg_u8 sx0;
    w3ddmg_u8 sy0;
    w3ddmg_u8 sx1;
    w3ddmg_u8 sy1;

    if (w3ddmg_project_world(ax, ay, az, &sx0, &sy0) == 0) return;
    if (w3ddmg_project_world(bx, by, bz, &sx1, &sy1) == 0) return;
    Wire3DDMG_DrawLine2D(sx0, sy0, sx1, sy1);
}
Wire3D_DrawModel

정점과 모서리로 된 모델을 지정한 위치와 회전으로 원래 크기에 그립니다.

사용 형식

c
void Wire3D_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 배율 256으로 DrawModelScaled를 호출하여 크기를 바꾸지 않고 모델을 그립니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3D_Model cube;
Wire3D_Object objects[2];
u16 masks[2];
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
    cube.edge_masks=0; cube.edge_mask_count=0;
    Wire3D_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3D_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3D_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
    result[1]=Wire3D_SelectEdgeMask(&cube,0,0,0);
    result[2]=Wire3D_SelectEdgeMask(&cube,0,8,0);
    Wire3D_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

Wire3D_DrawModel: DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
Wire3D_DrawModel: CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_models.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:37

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Draw an unscaled model by delegating to DrawModelScaled with scale 256.

kitaqgb/lib/wire3d_dmg.c:2825

c
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz)



{
    Wire3DDMG_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}
Wire3D_DrawModelScaled

모델 크기를 조절하고 Y/X/Z 순서로 회전한 뒤 정점을 이동·투영하여 모서리를 그립니다.

사용 형식

c
void Wire3D_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 최대 24개 정점을 크기 조절하고 Y/X/Z 순서로 회전한 뒤 이동·투영합니다. 이어서 요 마스크와 선택적 앞면 필터를 적용해 최대 16개 모서리를 그립니다. 0 이하의 배율은 1배(256)로 바뀝니다. 모델·정점·모서리 포인터가 null이면 무시하며, 참조 테이블은 읽을 수 있어야 합니다. 배율 곱과 이동 결과는 부호 있는 16비트 범위에 유지하세요. 깊이 경계를 가로지르는 모서리는 클리핑하지 않고 제외합니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3D_Model cube;
Wire3D_Object objects[2];
u16 masks[2];
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
    cube.edge_masks=0; cube.edge_mask_count=0;
    Wire3D_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3D_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3D_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
    result[1]=Wire3D_SelectEdgeMask(&cube,0,0,0);
    result[2]=Wire3D_SelectEdgeMask(&cube,0,8,0);
    Wire3D_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

Wire3D_DrawModelScaled: DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
Wire3D_DrawModelScaled: CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_models.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:38

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Scale, rotate in Y/X/Z order, translate and project at most 24 vertices;
then draw up to 16 edges filtered by yaw masks and optional front-facing faces.
Nonpositive scale becomes unity (256). Null model/vertex/edge pointers are
ignored; referenced tables must remain readable. Keep scale products and
translations in signed 16-bit range. Depth-crossing edges are dropped, not clipped.

kitaqgb/lib/wire3d_dmg.c:2965

c
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8)








{
    w3ddmg_u8 i;
    w3ddmg_u8 count;
    w3ddmg_u8 edge_count;
    w3ddmg_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->edges == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &model->vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
        vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
        vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);


        w3ddmg_rotate_y(&vx, &vz, (w3ddmg_i8)ry);
        w3ddmg_rotate_x(&vy, &vz, (w3ddmg_i8)rx);
        w3ddmg_rotate_z(&vx, &vy, (w3ddmg_i8)rz);






        vx = (w3ddmg_i16)(vx + x);
        vy = (w3ddmg_i16)(vy + y);
        vz = (w3ddmg_i16)(vz + z);

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }
        i = (w3ddmg_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
    if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
    {
        w3ddmg_build_face_visibility(model, count, face_count);
    }

    edge_count = model->edge_count;

    if (edge_count > WIRE3D_DMG_MODEL_EDGE_LIMIT) edge_count = WIRE3D_DMG_MODEL_EDGE_LIMIT;
    w3ddmg_build_edge_flags(model, edge_count, face_count, rx, ry, rz);

    i = 0;
    while (i < edge_count)
    {
        const Wire3DDMG_Edge* e;
        e = &model->edges[(__safe_index w3ddmg_u8)i];
        if ((e->a < count) && (e->b < count))
        {
            if (w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->a] &&
                w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->b] &&

                w3ddmg_edge_flags[(__safe_index w3ddmg_u8)i])



            {
                Wire3DDMG_DrawLine2D(
                    w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->a],
                    w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->a],
                    w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->b],
                    w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->b]);
            }
        }
        i = (w3ddmg_u8)(i + 1);
    }
}
Wire3D_DrawScene

가까운 면으로 나중의 모서리를 가리면서 최대 8개 오브젝트를 가까운 순서로 그립니다.

사용 형식

c
void Wire3D_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);

매개변수

objects

위치, 회전, 배율, 표시 여부 플래그를 담은 오브젝트 배열입니다.

count

제공한 배열 항목 수입니다. 실제 처리 상한은 해당 연산의 설명을 참조하세요.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 처음 최대 8개 오브젝트를 변환한 원점 깊이에 따라 가까운 순서로 정렬해 처리합니다. 보이는 유효 모델을 그린 뒤 앞면의 경계 직사각형을 마스크에 등록하여, 이후 선의 샘플 지점이 모두 가려지면 제외합니다. 깊이 버퍼가 아니라 오브젝트 간 가림의 근사입니다. 자체 마스크는 지우지만 기존 스테이징 픽셀은 유지합니다. null 배열은 무시하며 오브젝트와 그 데이터는 읽을 수 있어야 합니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3D_Model cube;
Wire3D_Object objects[2];
u16 masks[2];
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
    cube.edge_masks=0; cube.edge_mask_count=0;
    Wire3D_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3D_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3D_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
    result[1]=Wire3D_SelectEdgeMask(&cube,0,0,0);
    result[2]=Wire3D_SelectEdgeMask(&cube,0,8,0);
    Wire3D_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

Wire3D_DrawScene: DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
Wire3D_DrawScene: CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_models.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:39

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Process at most the first eight objects, sorted near to far by transformed
origin depth. Draw visible valid models, then mark their front-face bounding
rectangles to reject fully sampled later lines. This approximates inter-object
occlusion, not a depth buffer. It clears its mask but retains existing staged
pixels. Null arrays are ignored; objects and their data must remain readable.

kitaqgb/lib/wire3d_dmg.c:2723

c
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count)
{
    w3ddmg_u8 scene_count;
    w3ddmg_u8 i;

    if (objects == 0) return;

    scene_count = count;
    if (scene_count > WIRE3D_DMG_SCENE_OBJECT_LIMIT) scene_count = WIRE3D_DMG_SCENE_OBJECT_LIMIT;




    i = 0;
    while (i < scene_count)
    {
        w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = i;
        w3ddmg_scene_depth[(__safe_index w3ddmg_u8)i] = w3ddmg_scene_object_depth(&objects[(__safe_index w3ddmg_u8)i]);
        i = (w3ddmg_u8)(i + 1);
    }

    i = 0;
    while (i < scene_count)
    {
        w3ddmg_u8 j;
        j = (w3ddmg_u8)(i + 1);
        while (j < scene_count)
        {
            w3ddmg_u8 oi;
            w3ddmg_u8 oj;
            oi = w3ddmg_scene_order[(__safe_index w3ddmg_u8)i];
            oj = w3ddmg_scene_order[(__safe_index w3ddmg_u8)j];


            // Put the nearer origin first so its face bounds can suppress later lines.
            // The array itself stays in caller order; only the scratch index list is sorted.

            if (w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oj] < w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oi])
            {
                w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = oj;
                w3ddmg_scene_order[(__safe_index w3ddmg_u8)j] = oi;
            }
            j = (w3ddmg_u8)(j + 1);
        }
        i = (w3ddmg_u8)(i + 1);
    }

    w3ddmg_clear_occlusion_mask();

    w3ddmg_occlusion_active = 1;




    i = 0;
    while (i < scene_count)
    {
        Wire3DDMG_Object* obj;
        obj = &objects[(__safe_index w3ddmg_u8)w3ddmg_scene_order[(__safe_index w3ddmg_u8)i]];
        if ((obj->visible != 0) && (obj->model != 0))
        {

            Wire3DDMG_DrawModelScaled(obj->model, obj->x, obj->y, obj->z, (w3ddmg_i8)obj->rx, (w3ddmg_i8)obj->ry, (w3ddmg_i8)obj->rz, obj->scale_q8);
            w3ddmg_mark_model_occluder(obj->model);








        }
        i = (w3ddmg_u8)(i + 1);
    }

    w3ddmg_occlusion_active = 0;
}
Wire3D_EndFrame

대기 중인 배경 쓰기와 스테이징된 그림을 VRAM에 제출합니다.

사용 형식

c
void Wire3D_EndFrame();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 다음 VBlank를 기다리고 대기 중인 BG 맵 쓰기를 처리한 뒤, 접근 가능 구간을 폴링하며 스테이징 영역을 VRAM에 복사합니다. 복사하면서 스테이징 픽셀을 소비합니다. 전송이 VBlank 밖까지 이어질 수 있으며 원자적인 프레임 교체가 아닙니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_EndFrame: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_EndFrame: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:42

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Wait for the next VBlank, flush pending BG map writes, then copy the stage
to VRAM while polling access windows. Copying consumes the staged pixels.
The transfer may extend beyond VBlank; this is not an atomic frame swap.

kitaqgb/lib/wire3d_dmg.c:3081

c
void Wire3DDMG_EndFrame()
{
    w3ddmg_wait_vblank_start();
    w3ddmg_flush_bg_queue();

    w3ddmg_transfer_stage_asm();














}
Wire3D_EraseModelFaces

모델의 앞면 삼각형을 투영하고 그 안의 스테이징 픽셀을 지웁니다.

사용 형식

c
void Wire3D_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 은선 플래그와 면 데이터를 가진 모델의 정점을 최대 24개 투영하고 앞면 삼각형 내부를 스테이징 영역에서 지웁니다. 0 이하의 배율은 256(1배)입니다. 최대 16개 면을 확인하며 깊이 경계를 가로지르는 면은 건너뜁니다. 공유 투영 캐시도 교체하지만 VRAM은 갱신하지 않습니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom Wire3D_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom Wire3D_Face faces[2]={{0,2,1},{0,3,2}};
Wire3D_Model plane;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
    plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;plane.edge_masks=0;plane.edge_mask_count=0;
    Wire3D_BeginFrame();
    // Separate panels show a direct screen triangle and a projected square face.
    for(i=8;i<=32;i++) Wire3D_DrawLine2D(8,i,32,i);
    for(i=24;i<=72;i++) Wire3D_DrawLine2D(40,i,88,i);
    Wire3D_EraseTriangle2D(12,12,28,12,12,28);
    Wire3D_EraseModelFaces(&plane,0,0,64,0,0,0,256);

    Wire3D_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

Wire3D_EraseModelFaces: DMG — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
DMG — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
Wire3D_EraseModelFaces: CGB — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
CGB — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_faces.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:43

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Project up to 24 vertices and erase front-facing triangle interiors from
the stage for a model with hidden-line flags and face data. Nonpositive scale
means 256 (unity). Up to 16 faces are considered; depth-crossing faces are
skipped. This also replaces shared projection caches, but does not update VRAM.

kitaqgb/lib/wire3d_dmg.c:2841

c
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8)



{
    w3ddmg_u8 i;
    w3ddmg_u8 count;
    w3ddmg_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->faces == 0) return;
    if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &model->vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
        vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
        vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);


        w3ddmg_rotate_y(&vx, &vz, (w3ddmg_i8)ry);
        w3ddmg_rotate_x(&vy, &vz, (w3ddmg_i8)rx);
        w3ddmg_rotate_z(&vx, &vy, (w3ddmg_i8)rz);






        vx = (w3ddmg_i16)(vx + x);
        vy = (w3ddmg_i16)(vy + y);
        vz = (w3ddmg_i16)(vz + z);

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }
        i = (w3ddmg_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
    w3ddmg_build_face_visibility(model, count, face_count);

    i = 0;
    while (i < face_count)
    {
        const Wire3DDMG_Face* f;
        f = &model->faces[(__safe_index w3ddmg_u8)i];
        if (w3ddmg_face_visible[(__safe_index w3ddmg_u8)i] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->a] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->b] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->c])
        {
            w3ddmg_clear_triangle(
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->a],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->a],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->b],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->b],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->c],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->c]);
        }
        i = (w3ddmg_u8)(i + 1);
    }
}
Wire3D_EraseSpan2D

스테이징 영역 한 행에서 양 끝점을 포함하는 수평 스팬을 지웁니다.

사용 형식

c
void Wire3D_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);

매개변수

y

지울 행의 픽셀 Y 좌표입니다.

x0

뷰포트 픽셀 단위의 작은 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

x1

뷰포트 픽셀 단위의 큰 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. X 끝점 순서를 맞추고 양 끝점을 포함하는 스테이징 스팬을 지웁니다. 두 끝점은 모두 0~127이어야 합니다. 유효하지 않은 Y는 무시합니다. X를 자동으로 잘라 주지 않습니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_EraseSpan2D: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_EraseSpan2D: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:44

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Order the X endpoints and erase the inclusive staged span. Both endpoints
must be in 0..127; invalid Y is ignored. The routine does not clip X for you.

kitaqgb/lib/wire3d_dmg.c:2943

c
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1)
{
    w3ddmg_u8 tx;

    if (x0 > x1)
    {
        tx = x0;
        x0 = x1;
        x1 = tx;
    }
    w3ddmg_stage_clear_span(y, x0, x1);
}
Wire3D_EraseTriangle2D

수평 주사선 스팬을 사용해 화면 좌표 삼각형을 스테이징 영역에서 지웁니다.

사용 형식

c
void Wire3D_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

cx

뷰포트 픽셀 단위의 정점 C X 좌표입니다.

cy

뷰포트 픽셀 단위의 정점 C Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 정수 주사선 교점으로 스테이징 픽셀에서 삼각형을 지웁니다. 뷰포트 좌표를 지정하세요. 퇴화 삼각형은 무시하며 가림 마스크와 VRAM은 바꾸지 않습니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom Wire3D_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom Wire3D_Face faces[2]={{0,2,1},{0,3,2}};
Wire3D_Model plane;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
    plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;plane.edge_masks=0;plane.edge_mask_count=0;
    Wire3D_BeginFrame();
    // Separate panels show a direct screen triangle and a projected square face.
    for(i=8;i<=32;i++) Wire3D_DrawLine2D(8,i,32,i);
    for(i=24;i<=72;i++) Wire3D_DrawLine2D(40,i,88,i);
    Wire3D_EraseTriangle2D(12,12,28,12,12,28);
    Wire3D_EraseModelFaces(&plane,0,0,64,0,0,0,256);

    Wire3D_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

Wire3D_EraseTriangle2D: DMG — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
DMG — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
Wire3D_EraseTriangle2D: CGB — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.
CGB — 투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_faces.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:45

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Erase a triangle from staged pixels using integer scanline intersections.
Supply viewport coordinates. Degenerate triangles are ignored; the occlusion
mask and VRAM are unchanged.

kitaqgb/lib/wire3d_dmg.c:2933

c
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy)
{
    w3ddmg_clear_triangle(ax, ay, bx, by, cx, cy);
}
Wire3D_Init

흑백 와이어프레임 뷰포트용으로 LCD, 타일, 배경 맵을 초기화합니다.

사용 형식

c
void Wire3D_Init();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. LCD 상태를 제어합니다. VBlank를 기다려 LCD를 끄고 타일 6144바이트와 BG 맵을 지운 뒤, HUD 타일과 부호 있는 타일 번호의 128×96 뷰포트를 설치하고 스크롤 0, BGP=0xB4로 BG 표시를 켭니다. 카메라, BG 큐, 스테이징 영역을 재설정합니다. 스테이징용 0xD000..0xDFFF를 예약하고 WRAM 뱅크 매핑을 유지하세요. 그리기 전에 BeginFrame을 호출해 가림 상태도 초기화하세요.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_Init: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_Init: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:47

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Take over the LCD: wait for VBlank, switch it off, clear 6144 tile bytes and
the BG map, install HUD tiles and the 128x96 signed-tile viewport, then enable
BG display with scroll zero and BGP=0xB4. Reset camera, BG queue and stage.
Reserve 0xD000..0xDFFF for staging and retain its WRAM bank mapping.
Call BeginFrame before drawing to initialize the occlusion state as well.

kitaqgb/lib/wire3d_dmg.c:2572

c
void Wire3DDMG_Init()
{
    w3ddmg_u8 row;
    w3ddmg_u8 col;
    w3ddmg_u8 tid;
    w3ddmg_u16 off;

    w3ddmg_wait_vblank_start();
    w3ddmg_reg_lcdc = 0;

    w3ddmg_clear_vram_asm();

    w3ddmg_load_hud_tiles();

    w3ddmg_fill_bg_map_asm();

    row = 0;
    tid = 0x90;
    while (row < WIRE3D_DMG_TILE_H)
    {

        off = (w3ddmg_u16)((w3ddmg_u16)row << 5);



        col = 0;
        while (col < WIRE3D_DMG_TILE_W)
        {
            w3ddmg_bg_map_9800[(w3ddmg_u16)(off + (w3ddmg_u16)col)] = tid;
            tid = (w3ddmg_u8)(tid + WIRE3D_DMG_TILE_H);
            col = (w3ddmg_u8)(col + 1);
        }
        row = (w3ddmg_u8)(row + 1);
        tid = (w3ddmg_u8)(0x90 + row);
    }


    w3ddmg_reg_scx = 0;



    w3ddmg_reg_scy = 0;
    w3ddmg_reg_bgp = 0xB4;
    w3ddmg_reg_lcdc = 0x81;
    w3ddmg_bgq_count = 0;





    Wire3DDMG_SetCamera(0, 0, 0, 0, 0, 0);
    w3ddmg_clear_stage_asm();




}
Wire3D_ProjectPoint

월드 좌표의 점을 카메라를 통해 뷰포트 좌표로 투영합니다.

사용 형식

c
w3ddmg_u8 Wire3D_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);

매개변수

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

sx

투영된 X 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

sy

투영된 Y 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

반환값

투영에 성공하면 1, 깊이 검사에서 제외되면 0을 반환합니다.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 현재 카메라로 월드 점을 투영합니다. 깊이 검사에서 제외되면 출력은 유지하고 0을 반환하며, 성공하면 128×96 범위로 제한한 좌표를 씁니다. 출력 포인터는 유효해야 합니다. 화면 좌표 제한은 기하학적 클리핑이 아닙니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_ProjectPoint: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_ProjectPoint: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:50

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Project a world point with the current camera. Return zero for rejected
depth, leaving outputs unchanged; success writes clamped 128x96 coordinates.
Output pointers must be valid. Screen clamping is not geometric clipping.

kitaqgb/lib/wire3d_dmg.c:549

c
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy)
{
    return w3ddmg_project_world(x, y, z, sx, sy);
}
Wire3D_PutBgTile

배경 맵 셀 하나의 타일 번호 쓰기를 큐에 넣습니다.

사용 형식

c
void Wire3D_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);

매개변수

x

32×32 배경 맵의 X 타일 좌표입니다.

y

32×32 배경 맵의 Y 타일 좌표입니다.

tile

배경 셀의 8비트 타일 번호입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 0x9800의 32×32 맵에 쓸 타일을 EndFrame용 큐에 넣습니다. 잘못된 맵 좌표와 대기 중인 쓰기 48개를 초과하는 요청은 조용히 무시합니다. 이 큐는 일반 vram 라이브러리 큐와 별개입니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_PutBgTile: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_PutBgTile: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:51

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Queue a tile write to the 32x32 map at 0x9800 for EndFrame. Invalid map
coordinates and submissions beyond 48 pending writes are silently ignored.
This queue is separate from the general vram library queue.

kitaqgb/lib/wire3d_dmg.c:582

c
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile)
{
    if (x >= 32) return;
    if (y >= 32) return;
    if (w3ddmg_bgq_count >= WIRE3D_DMG_BG_QUEUE_LIMIT) return;
    w3ddmg_bgq_x[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = x;
    w3ddmg_bgq_y[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = y;
    w3ddmg_bgq_tile[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = tile;
    w3ddmg_bgq_count = (w3ddmg_u8)(w3ddmg_bgq_count + 1);
}
Wire3D_SelectEdgeMask

오브젝트의 요에 맞는 미리 계산된 모서리 가시성 마스크를 선택합니다.

사용 형식

c
w3ddmg_u16 Wire3D_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

16비트 모서리 가시성 마스크입니다. 테이블이 없으면 0xFFFF입니다.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 오브젝트 요의 하위 4비트로 미리 계산한 마스크를 선택합니다. 피치·롤·카메라 방향은 무시합니다. 구간 수는 16, 8, 4, 2를 사용하세요. 다른 양수 개수는 항목 0을 선택하며, 16 이상이면 처음 16개를 사용합니다. 데이터가 없으면 0xFFFF를 반환합니다. 현재 데이터 포인터 매핑을 통해 마스크 테이블을 읽을 수 있어야 합니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3D_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3D_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3D_Model cube;
Wire3D_Object objects[2];
u16 masks[2];
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
    cube.edge_masks=0; cube.edge_mask_count=0;
    Wire3D_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3D_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3D_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3D_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
    result[1]=Wire3D_SelectEdgeMask(&cube,0,0,0);
    result[2]=Wire3D_SelectEdgeMask(&cube,0,8,0);
    Wire3D_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

Wire3D_SelectEdgeMask: DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
DMG — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
Wire3D_SelectEdgeMask: CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.
CGB — 원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_models.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:52

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Select a precomputed mask from the low four bits of object yaw; pitch,
roll and camera orientation are ignored. Use 16, 8, 4 or 2 bins; other positive
counts select entry zero (counts >=16 use the first 16). Missing data returns
0xFFFF. Keep the mask table readable through the current data-pointer mapping.

kitaqgb/lib/wire3d_dmg.c:1109

c
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz)
{
    w3ddmg_u8 count;
    w3ddmg_u8 bin;

    if (model == 0) return 0xFFFF;
    if (model->edge_masks == 0) return 0xFFFF;
    count = model->edge_mask_count;
    if (count == 0) return 0xFFFF;

    (void)rx;
    (void)rz;

    bin = (w3ddmg_u8)(((w3ddmg_u8)ry) & 15);
    if (count >= 16) return model->edge_masks[(__safe_index w3ddmg_u8)bin];
    if (count == 8) bin = (w3ddmg_u8)(bin >> 1);
    else if (count == 4) bin = (w3ddmg_u8)(bin >> 2);
    else if (count == 2) bin = (w3ddmg_u8)(bin >> 3);
    else bin = 0;

    if (bin >= count) bin = (w3ddmg_u8)(count - 1);
    return model->edge_masks[(__safe_index w3ddmg_u8)bin];
}
Wire3D_SetCamera

이후 투영에 사용할 카메라 위치와 방향을 저장합니다.

사용 형식

c
void Wire3D_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll);

매개변수

x

월드 좌표계에서 카메라의 X 성분입니다.

y

월드 좌표계에서 카메라의 Y 성분입니다.

z

월드 좌표계에서 카메라의 Z 성분입니다.

pitch

X축 회전입니다. 16단계가 한 바퀴입니다.

yaw

Y축 회전입니다. 16단계가 한 바퀴입니다.

roll

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. 이후 그리기를 위해 카메라 위치와 각도를 저장합니다. 한 바퀴는 16각도 단계입니다. 기존 그림을 다시 투영하거나 입력 범위를 검사하지 않습니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_SetCamera: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_SetCamera: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:53

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Store camera position and angles for later draws; a full turn is 16 angle
steps. No existing drawing is reprojected and no input range validation occurs.

kitaqgb/lib/wire3d_dmg.c:2659

c
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll)



{
    w3ddmg_cam_x = x;
    w3ddmg_cam_y = y;
    w3ddmg_cam_z = z;
    w3ddmg_cam_pitch = pitch;
    w3ddmg_cam_yaw = yaw;
    w3ddmg_cam_roll = roll;
}
Wire3D_SetPalette

흑백 배경 팔레트 레지스터 BGP의 네 명암 매핑을 씁니다.

사용 형식

c
void Wire3D_SetPalette(w3ddmg_u8 bgp);

매개변수

bgp

2비트 명암 할당 네 개를 담은 BGP 레지스터 값입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96. DMG BGP 팔레트의 원시 인코딩 값을 즉시 씁니다. 프레임 동기화는 하지 않습니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3D_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3D_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3D_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3D_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3D_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3D_SetCamera(0,0,0,0,0,0);
    Wire3D_BeginFrame();
    Wire3D_DrawLine2D(8,8,56,8);
    Wire3D_DrawLine2D(56,8,56,40);
    Wire3D_DrawLine2D(56,40,8,40);
    Wire3D_DrawLine2D(8,40,8,8);
    Wire3D_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3D_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3D_PutBgTile(18,1,157);
    Wire3D_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

Wire3D_SetPalette: DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
DMG — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
Wire3D_SetPalette: CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.
CGB — 한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_wire3d_raster.c .\kitaqgb\lib\wire3d.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_wire3d_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d.h:54

선언 주석 원문
WIRE3D_DMG_HEIGHT = 96.
Write the raw DMG BGP palette encoding immediately; no frame synchronization occurs.

kitaqgb/lib/wire3d_dmg.c:597

c
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp)
{
    w3ddmg_reg_bgp = bgp;
}

wire3d_cgb.h — CGB용 컬러 와이어프레임

고속 렌더링 경로 사용법

일반 128×96 렌더러는 그리기 주소를 순차 갱신합니다. 가림 없는 선에서는 색상 플레인을 선마다 한 번 선택하고 픽셀 수와 오차를 CPU 레지스터에 보관합니다. 가림 있는 선도 색상 플레인을 선마다 한 번 선택하며 그리기 주소와 마스크 주소를 모두 순차 갱신합니다. 각 픽셀은 마스크 비트를 검사하고 가려지지 않았을 때만 기록됩니다. 160×144 렌더러와 FastMap에는 각각 전용 경로가 있습니다. 0, 90, 180, 270도 회전은 입력을 제한한 뒤 좌표 교환과 부호 변경으로 처리합니다. 게임 전체 성능은 정점 수, 모서리 길이, 가림과 VRAM 전송에도 좌우됩니다. 개별 연산 시간과 화면 한 장을 완성하는 시간은 따로 측정하세요.

CGB용 컬러 와이어프레임입니다. 128×96 픽셀 렌더러, 160×144 타일 할당기, 외곽선 타일 FastMap은 초기화와 전송 순서가 각각 다릅니다. 모델의 정점·모서리·삼각형 면은 호출자가 소유합니다. 이 모듈은 물리를 시뮬레이션하지 않습니다.

Vec3는 x/y/z, Edge는 정점 인덱스 a/b, Face는 삼각형 인덱스 a/b/c를 담습니다. Model의 vertices, edges, faces는 이 배열을 가리키고 각 count는 길이를 나타냅니다. edge_faces에는 인접 면 인덱스 f0/f1이 들어가며, 없는 면은 FACE_NONE입니다. flags의 MODEL_HIDDEN_LINES는 면 기반 모서리 선택을 요청합니다. 투영된 부호 있는 면적으로 면 방향을 결정하므로 정점 순서가 중요합니다.

Object는 모델 참조, 위치 x/y/z, 각도 rx/ry/rz, scale_q8, visible을 저장합니다. 여러 오브젝트가 모델을 공유할 수 있지만 그리기는 테이블을 복사하거나 ROM 뱅크를 자동 전환하지 않습니다. 그리는 동안 참조 데이터를 계속 읽을 수 있어야 합니다. CGB Object에는 색상 인덱스도 있습니다.

FastCube의 x/y는 화면 중심 기준 오프셋이며 z는 크기나 그리기 순서를 선택합니다. FastCubes는 각도를 무시하지만 FastCubeFrame은 rx/ry/rz로 스탬프 네 종류를 선택합니다. 이 간소화된 표시는 카메라로 투영하는 DrawModel과 용도가 다릅니다.

Wire3DCGB_BeginFrame

선택한 렌더링 모드에서 새 빈 프레임을 시작합니다.

사용 형식

c
void Wire3DCGB_BeginFrame();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

일반 모드에서는 스테이징 영역 전체 전송을 선택하고, 모든 스테이징 픽셀과 비트맵 마스크를 지우며, 마스크 경계를 재설정하고 가림 처리를 끕니다. 전체 화면 모드에서는 대신 해당 모드의 할당기와 스팬을 재설정합니다. 대기 중인 BG 쓰기는 큐에 남습니다. 전체 런타임 빌드가 필요합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:122

kitaqgb/lib/wire3d_cgb.c:8154

c
void Wire3DCGB_BeginFrame()
{
    if (w3dcgb_full_mode != 0)
    {
        w3dcgb_full_begin_asm();
        return;
    }
    w3dcgb_full_frame_transfer = 1;
    w3dcgb_clear_stage_asm();
    w3dcgb_clear_occlusion_mask_asm();
    w3dcgb_occ_min_x = (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1);
    w3dcgb_occ_min_y = (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1);
    w3dcgb_occ_max_x = 0;
    w3dcgb_occ_max_y = 0;
    w3dcgb_occlusion_active = 0;
}
Wire3DCGB_BeginFrameFast

지운 프레임을 시작하고 이전 부분 전송 범위를 무효화해 뷰포트 전체를 포함하도록 합니다.

사용 형식

c
void Wire3DCGB_BeginFrameFast();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

BeginFrame과 같은 일반/전체 화면 프레임 재설정을 수행하되, 먼저 두 이전 부분 전송 이력 범위를 각각 뷰포트 전체 192타일로 표시합니다. 이후 부분 업로드가 오래된 뱅크 상태를 유효하다고 간주하지 않도록 합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:123

kitaqgb/lib/wire3d_cgb.c:8175

c
void Wire3DCGB_BeginFrameFast()
{
    w3dcgb_older_dirty_min_tile = 0;
    w3dcgb_older_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
    w3dcgb_prev_dirty_min_tile = 0;
    w3dcgb_prev_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
    if (w3dcgb_full_mode != 0)
    {
        w3dcgb_full_begin_asm();
        return;
    }
    w3dcgb_full_frame_transfer = 1;
    w3dcgb_clear_stage_asm();
    w3dcgb_clear_occlusion_mask_asm();
    w3dcgb_occ_min_x = (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1);
    w3dcgb_occ_min_y = (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1);
    w3dcgb_occ_max_x = 0;
    w3dcgb_occ_max_y = 0;
    w3dcgb_occlusion_active = 0;
}
Wire3DCGB_BeginFrameSparse

부분 범위 전송을 위한 프레임을 시작합니다.

사용 형식

c
void Wire3DCGB_BeginFrameSparse();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

부분 전송을 선택하고 128×96 스테이징 영역 전체를 지워 변경 범위가 커질 때 이전 픽셀이 남지 않게 합니다. 마스크 경계를 재설정하고 가림 처리를 끕니다. PAINTER_ONLY 빌드에서는 사용하지 않는 비트맵 마스크를 지우지 않습니다. 전체 화면 모드에서는 해당 모드의 할당기 재설정에 처리를 넘깁니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:124

kitaqgb/lib/wire3d_cgb.c:8200

c
void Wire3DCGB_BeginFrameSparse()
{
    if (w3dcgb_full_mode != 0)
    {
        w3dcgb_full_begin_asm();
        return;
    }
    w3dcgb_full_frame_transfer = 0;
    w3dcgb_dirty_count = 0;
    /* One ASM pass is faster than repeated range-growth clears and guarantees
       that newly exposed dirty tiles can never copy stale stage pixels. */
    w3dcgb_clear_stage_asm();
#ifndef WIRE3DCGB_PAINTER_ONLY
    /* A Z-sorted painter erases silhouettes directly in the stage and never
       reads the separate front-to-back coverage mask. */
    w3dcgb_clear_occlusion_mask_asm();
#endif
    w3dcgb_occ_min_x = (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1);
    w3dcgb_occ_min_y = (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1);
    w3dcgb_occ_max_x = 0;
    w3dcgb_occ_max_y = 0;
    w3dcgb_occlusion_active = 0;
}
Wire3DCGB_ClearFrameTiles

표시 중인 128×96 프레임 타일과 스테이징 영역을 지웁니다.

사용 형식

c
void Wire3DCGB_ClearFrameTiles();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

128×96 렌더러에서 VBlank를 기다리고 LCD를 끈 뒤, 스테이징 영역과 양쪽 뱅크의 프레임 타일 범위를 지우고 맵 속성을 재설정한 다음 LCDC 0x81을 켭니다. 변경 플래그와 개수는 지우지만 부분 전송의 min/max 이력은 지우지 않습니다. full_mode를 재설정하지 않으며 전체 화면 모드를 다시 초기화하는 함수도 아닙니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:121

kitaqgb/lib/wire3d_cgb.c:8240

c
void Wire3DCGB_ClearFrameTiles()
{
    w3dcgb_u8 i;

    w3dcgb_wait_vblank_start();
    w3dcgb_reg_lcdc = 0;
    w3dcgb_clear_stage_asm();
    w3dcgb_clear_frame_tiles_vram_asm();
    w3dcgb_fill_attr_map_asm();
    w3dcgb_reg_lcdc = 0x81;

    i = 0;
    while (i < W3DCGB_DIRTY_TILE_LIMIT)
    {
        w3dcgb_dirty_flags[(__safe_index w3dcgb_u8)i] = 0;
        w3dcgb_prev_dirty_flags[(__safe_index w3dcgb_u8)i] = 0;
        i = (w3dcgb_u8)(i + 1);
    }
    w3dcgb_dirty_count = 0;
    w3dcgb_prev_dirty_count = 0;
}
Wire3DCGB_ClearOcclusionMask

가림 비트맵 또는 전체 화면 스팬 이력을 지웁니다.

사용 형식

c
void Wire3DCGB_ClearOcclusionMask();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

full_mode가 설정되었으면 전체 화면 스팬 이력을 지우고, 그렇지 않으면 128×96 비트맵 마스크와 경계를 지웁니다. 표시 중이거나 스테이징된 픽셀은 지우지 않고, 가림 검사 활성 상태도 바꾸지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Red/blue scanlines stop inside masks; green outlines identify the triangle.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
    u8 y;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    // Clearing this first test mask must leave the upper-left scanline intact.
    Wire3DCGB_MarkTriangle2D(8,8,16,8,8,16);
    Wire3DCGB_ClearOcclusionMask();
    Wire3DCGB_MarkTriangle2D(32,16,64,16,32,48);
    Wire3DCGB_MarkPackedSilhouette2D(silhouette,5,-2,104,32);
    Wire3DCGB_SetOcclusionActive(1);
    for(y=8;y<=56;y=y+4) Wire3DCGB_DrawLine2DColor(8,y,88,y,1);
    for(y=28;y<=36;y++) Wire3DCGB_DrawLine2DColor(92,y,120,y,2);
    Wire3DCGB_SetOcclusionActive(0);
    Wire3DCGB_DrawLine2DColor(32,16,64,16,3);
    Wire3DCGB_DrawLine2DColor(64,16,32,48,3);
    Wire3DCGB_DrawLine2DColor(32,48,32,16,3);
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

삼각형이 빨간 주사선의 가운데를 가리고, 패킹된 실루엣이 파란 선을 가립니다. 초록 외곽선으로 가림 영역의 위치를 표시합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_mask.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_mask.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:148

kitaqgb/lib/wire3d_cgb.c:1962

c
void Wire3DCGB_ClearOcclusionMask()
{
    if (w3dcgb_full_mode != 0) w3dcgb_full_clear_spans_asm();
    else w3dcgb_clear_occlusion_mask();
}
Wire3DCGB_ClearSparseStageFast

스테이징 영역 전체를 지우고 128×96 뷰포트 전체를 업로드 대상으로 표시합니다.

사용 형식

c
void Wire3DCGB_ClearSparseStageFast();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

뱅크 2의 스테이징 영역 전체를 지우고 128×96 뷰포트 전체를 변경된 것으로 표시합니다. 이름과 달리 부분 지우기가 아니며 스테이징 픽셀을 보존하지 않습니다. 가림 상태를 지우거나 전송 모드를 선택하지도 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:125

kitaqgb/lib/wire3d_cgb.c:8227

c
void Wire3DCGB_ClearSparseStageFast()
{
    w3dcgb_clear_stage_asm();
    w3dcgb_mark_dirty_rect(0, 0,
                           (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1),
                           (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1));
}
Wire3DCGB_DrawEdgeList2D

미리 투영된 부호 있는 바이트 정점 오프셋에서 모서리를 최대 64개 그립니다.

사용 형식

c
void Wire3DCGB_DrawEdgeList2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count, const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y, w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color);

매개변수

edges

각 모서리의 정점 인덱스입니다. 선언된 구조체 또는 바이트 쌍 형식을 사용합니다.

edge_count

모서리 수입니다.

vertex_x

미리 투영된 정점 X 오프셋 배열입니다.

vertex_y

미리 투영된 정점 Y 오프셋 배열입니다.

x

뷰포트 픽셀 단위의 중심 X 좌표입니다.

y

뷰포트 픽셀 단위의 중심 Y 좌표입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

(cx,cy) 기준의 부호 있는 바이트 오프셋에서 인덱스 모서리를 최대 64개 그립니다. null 배열은 무시하고, 인덱스는 읽을 수 있는 정점을 가리켜야 합니다. 이동한 끝점은 래핑되는 바이트 변환 전에 뷰포트 안에 있어야 합니다. 모드에 따라 분기하고 이전 색을 유지합니다. 정점 수 검사는 하지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
    shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
    Wire3DCGB_SetLineColor(2);
    Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
    Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
    Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
    Wire3DCGB_DrawTinyModel2D(104,24,16,3);
    result[0]=Wire3DCGB_ProjectAxis48(48,96);
    result[1]=Wire3DCGB_ProjectAxis48(-48,96);
    Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
    result[2]=Wire3DCGB_GetLineColor();
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 수평 모서리 두 개, 파란 정사각형, 잘린 초록 테두리, 초록 6픽셀 마커, 빨간 발사체로 목록 형식을 비교합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:183

kitaqgb/lib/wire3d_cgb.c:8524

c
void Wire3DCGB_DrawEdgeList2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count,
                             const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y,
                             w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color)
{
    w3dcgb_u8 i;
    w3dcgb_u8 a;
    w3dcgb_u8 b;
    w3dcgb_u8 old_color;

    if (edges == 0) return;
    if (vertex_x == 0) return;
    if (vertex_y == 0) return;
    if (edge_count > WIRE3DCGB_MODEL_EDGE_LIMIT) edge_count = WIRE3DCGB_MODEL_EDGE_LIMIT;

    old_color = w3dcgb_line_color;
    w3dcgb_line_color = (w3dcgb_u8)(color & 3);
    if (w3dcgb_full_mode == 0)
    {
        w3dcgb_edge_list_ptr = edges;
        w3dcgb_edge_x_ptr = vertex_x;
        w3dcgb_edge_y_ptr = vertex_y;
        w3dcgb_edge_remaining = edge_count;
        w3dcgb_edge_center_x = x;
        w3dcgb_edge_center_y = y;
        w3dcgb_edge_list_asm();
        w3dcgb_line_color = old_color;
        return;
    }
    i = 0;
    while (i < edge_count)
    {
        a = edges[(__safe_index w3dcgb_u8)i].a;
        b = edges[(__safe_index w3dcgb_u8)i].b;
        w3dcgb_line_x0 = (w3dcgb_u8)((w3dcgb_i16)x + (w3dcgb_i16)vertex_x[(__safe_index w3dcgb_u8)a]);
        w3dcgb_line_y0 = (w3dcgb_u8)((w3dcgb_i16)y + (w3dcgb_i16)vertex_y[(__safe_index w3dcgb_u8)a]);
        w3dcgb_line_x1 = (w3dcgb_u8)((w3dcgb_i16)x + (w3dcgb_i16)vertex_x[(__safe_index w3dcgb_u8)b]);
        w3dcgb_line_y1 = (w3dcgb_u8)((w3dcgb_i16)y + (w3dcgb_i16)vertex_y[(__safe_index w3dcgb_u8)b]);
        if (w3dcgb_full_mode != 0) w3dcgb_full_line_fast_asm();
        else w3dcgb_line_stage_asm();
        i = (w3dcgb_u8)(i + 1);
    }
    w3dcgb_line_color = old_color;
}
Wire3DCGB_DrawEdgeListClipped2D

부호 있는 투영 정점과 모서리를 검사한 뒤 모서리 목록을 잘라 그립니다.

사용 형식

c
void Wire3DCGB_DrawEdgeListClipped2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count, const w3dcgb_i16* vx, const w3dcgb_i16* vy, w3dcgb_u8 vertex_count, w3dcgb_i16 cx, w3dcgb_i16 cy, w3dcgb_u8 color);

매개변수

edges

각 모서리의 정점 인덱스입니다. 선언된 구조체 또는 바이트 쌍 형식을 사용합니다.

edge_count

모서리 수입니다.

vx

클리핑 전 부호 있는 16비트 X 오프셋 배열입니다.

vy

클리핑 전 부호 있는 16비트 Y 오프셋 배열입니다.

vertex_count

정점 배열의 항목 수입니다.

cx

뷰포트 픽셀 단위의 중심 X 좌표입니다.

cy

뷰포트 픽셀 단위의 중심 Y 좌표입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

그리기 전에 포인터, 정점 수 1~24, 모서리 수 최대 64, 모든 인덱스, 입력 좌표와 중심의 ±2047 범위를 검사합니다. 완전히 보이는 도형은 부호 있는 바이트 임시 버퍼와 빠른 인덱스 경로를 사용하고, 다른 모서리는 부호 있는 선 클리퍼를 사용합니다. 각 입력이 검사를 통과했더라도 이동 후 끝점이 ±2047을 넘으면 클리퍼에서 제외될 수 있습니다. 공유 화면 임시 버퍼를 덮어쓰며, 호출하는 선 API를 통해 이전 색을 유지합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
    shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
    Wire3DCGB_SetLineColor(2);
    Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
    Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
    Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
    Wire3DCGB_DrawTinyModel2D(104,24,16,3);
    result[0]=Wire3DCGB_ProjectAxis48(48,96);
    result[1]=Wire3DCGB_ProjectAxis48(-48,96);
    Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
    result[2]=Wire3DCGB_GetLineColor();
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 수평 모서리 두 개, 파란 정사각형, 잘린 초록 테두리, 초록 6픽셀 마커, 빨간 발사체로 목록 형식을 비교합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:138

kitaqgb/lib/wire3d_cgb.c:9806

c
void Wire3DCGB_DrawEdgeListClipped2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count,
    const w3dcgb_i16* vx, const w3dcgb_i16* vy, w3dcgb_u8 vertex_count,
    w3dcgb_i16 cx, w3dcgb_i16 cy, w3dcgb_u8 color)
{
    w3dcgb_u8 i;
    w3dcgb_u8 a;
    w3dcgb_u8 b;
    w3dcgb_u8 inside;
    w3dcgb_i16 x;
    w3dcgb_i16 y;
    w3dcgb_i16 min_x;
    w3dcgb_i16 min_y;
    w3dcgb_i16 max_x;
    w3dcgb_i16 max_y;
    if ((edges == 0) || (vx == 0) || (vy == 0)) return;
    if ((cx < -2047) || (cx > 2047) || (cy < -2047) || (cy > 2047)) return;
    if ((vertex_count == 0) || (vertex_count > WIRE3DCGB_MODEL_VERTEX_LIMIT) ||
        (edge_count > WIRE3DCGB_MODEL_EDGE_LIMIT)) return;
    i = 0;
    while (i < edge_count)
    {
        if ((edges[(__safe_index w3dcgb_u8)i].a >= vertex_count) ||
            (edges[(__safe_index w3dcgb_u8)i].b >= vertex_count)) return;
        i = (w3dcgb_u8)(i + 1);
    }
    min_x = 32767;
    min_y = 32767;
    max_x = -32767;
    max_y = -32767;
    inside = 1;
    i = 0;
    while (i < vertex_count)
    {
        if ((vx[(__safe_index w3dcgb_u8)i] < -2047) ||
            (vx[(__safe_index w3dcgb_u8)i] > 2047) ||
            (vy[(__safe_index w3dcgb_u8)i] < -2047) ||
            (vy[(__safe_index w3dcgb_u8)i] > 2047)) return;
        x = (w3dcgb_i16)(cx + vx[(__safe_index w3dcgb_u8)i]);
        y = (w3dcgb_i16)(cy + vy[(__safe_index w3dcgb_u8)i]);
        if (x < min_x) min_x = x;
        if (x > max_x) max_x = x;
        if (y < min_y) min_y = y;
        if (y > max_y) max_y = y;
        /* Reuse projected-vertex scratch; drawing is non-reentrant. */
        w3dcgb_screen_x[(__safe_index w3dcgb_u8)i] = (w3dcgb_u8)(x - 64);
        w3dcgb_screen_y[(__safe_index w3dcgb_u8)i] = (w3dcgb_u8)(y - 48);
        i = (w3dcgb_u8)(i + 1);
    }
    if ((w3dcgb_clip_outcode(min_x, min_y) | w3dcgb_clip_outcode(max_x, max_y)) != 0) inside = 0;
    if (inside != 0)
    {
        if (w3dcgb_full_mode == 0) w3dcgb_mark_dirty_rect((w3dcgb_u8)min_x,
            (w3dcgb_u8)min_y, (w3dcgb_u8)max_x, (w3dcgb_u8)max_y);
        Wire3DCGB_DrawEdgeList2D(edges, edge_count, (const w3dcgb_i8*)w3dcgb_screen_x,
            (const w3dcgb_i8*)w3dcgb_screen_y, 64, 48, color);
        return;
    }
    i = 0;
    while (i < edge_count)
    {
        a = edges[(__safe_index w3dcgb_u8)i].a;
        b = edges[(__safe_index w3dcgb_u8)i].b;
        Wire3DCGB_DrawLineClipped2D((w3dcgb_i16)(cx + vx[(__safe_index w3dcgb_u8)a]),
            (w3dcgb_i16)(cy + vy[(__safe_index w3dcgb_u8)a]),
            (w3dcgb_i16)(cx + vx[(__safe_index w3dcgb_u8)b]),
            (w3dcgb_i16)(cy + vy[(__safe_index w3dcgb_u8)b]), color);
        i = (w3dcgb_u8)(i + 1);
    }
}
Wire3DCGB_DrawFastCubeFrame

이전 큐브 스탬프 프레임을 교체하고 최대 3개 스탬프와 상태 표시기를 업로드합니다.

사용 형식

c
void Wire3DCGB_DrawFastCubeFrame(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);

매개변수

cubes

고속 큐브 그리기에 사용하는 위치·각도·색상 배열입니다.

count

제공한 배열 항목 수입니다. 실제 처리 상한은 해당 연산의 설명을 참조하세요.

hidden_enabled

0이면 숨은 모서리도 그리며, 0이 아니면 간소화된 숨은 모서리 제거를 선택합니다.

selected

선택한 오브젝트의 원본 배열 인덱스입니다. 스탬프 API는 상태 표시기에 이 값을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

맵을 준비하고 이전 범위와 상태 셀을 지운 뒤, 원래 Z 값을 기준으로 큐브 스탬프를 최대 3개 먼 순서로 정렬해 그리고 VBlank에서 타일 번호와 속성을 업로드합니다. 호출자의 배열 순서는 바꾸지 않습니다. 배열이 null이 아니고 count가 0이면 이전 스탬프를 지우지만, null 배열이면 아무것도 하지 않습니다. selected & 3은 상태 셀만 고르며 큐브를 강조하지 않습니다. 큐브 스탬프가 로드되어 있고 전체 런타임과 일관된 FastMap WRAM 매핑이 필요합니다. 이 함수가 그것들을 초기화하지는 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// A complete cube-stamp frame removes the preceding stamp's old map cells.
#include "wire_cgb_example.h"
Wire3DCGB_FastCube cube[1];
void main() {
    u8 bank;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors();
    cube[0].x=-24;cube[0].y=0;cube[0].z=96;
    cube[0].rx=0;cube[0].ry=0;cube[0].rz=0;cube[0].color=1;
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_DrawFastCubeFrame(cube,1,1,0);
    cube[0].x=24;
    Wire3DCGB_DrawFastCubeFrame(cube,1,1,0);
    sample_svbk=bank;result[0]=cube[0].x;result[7]=0xA55A;
    while(1) {}
}

예상 결과

이전 큐브 스탬프가 사라집니다. 빨간 32×32 큐브가 (72,32)에서 시작하고 위쪽에 초록 상태 표시기가 나타납니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_stamp.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_stamp.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:158

kitaqgb/lib/wire3d_cgb.c:10800

c
void Wire3DCGB_DrawFastCubeFrame(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected)
{
    w3dcgb_u8 i;
    w3dcgb_u8 scene_count;
    w3dcgb_u8 a;
    w3dcgb_u8 b;
    w3dcgb_u8 c;
    w3dcgb_u8 x;

    if (cubes == 0) return;
    scene_count = count;
    if (scene_count > 3) scene_count = 3;

    w3dcgb_fast_map_prepare();

    i = 0;
    while (i < w3dcgb_fast_prev_count)
    {
        w3dcgb_fast_map_clear_rect(
            w3dcgb_fast_prev_x[(__safe_index w3dcgb_u8)i],
            w3dcgb_fast_prev_y[(__safe_index w3dcgb_u8)i],
            w3dcgb_fast_prev_w[(__safe_index w3dcgb_u8)i],
            w3dcgb_fast_prev_h[(__safe_index w3dcgb_u8)i]);
        i = (w3dcgb_u8)(i + 1);
    }
    w3dcgb_fast_map_clear_rect(0, 0, 4, 1);
    w3dcgb_fast_map_clear_rect(14, 0, 2, 1);

    if (scene_count == 0)
    {
        w3dcgb_fast_prev_count = 0;
        w3dcgb_wait_vblank_start();
        w3dcgb_fast_map_flush_gdma_asm();
        return;
    }

    a = 0;
    b = 1;
    c = 2;
    if (scene_count == 1)
    {
        w3dcgb_fast_map_draw_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0), 0);
        w3dcgb_fast_prev_count = 1;
    }
    else if (scene_count == 2)
    {
        if (cubes[0].z < cubes[1].z)
        {
            w3dcgb_fast_map_draw_cube_one(&cubes[1], hidden_enabled, (w3dcgb_u8)(selected == 1), 1);
            w3dcgb_fast_map_draw_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0), 0);
        }
        else
        {
            w3dcgb_fast_map_draw_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0), 0);
            w3dcgb_fast_map_draw_cube_one(&cubes[1], hidden_enabled, (w3dcgb_u8)(selected == 1), 1);
        }
        w3dcgb_fast_prev_count = 2;
    }
    else
    {
        if (cubes[a].z < cubes[b].z)
        {
            w3dcgb_u8 t;
            t = a;
            a = b;
            b = t;
        }
        if (cubes[b].z < cubes[c].z)
        {
            w3dcgb_u8 t;
            t = b;
            b = c;
            c = t;
        }
        if (cubes[a].z < cubes[b].z)
        {
            w3dcgb_u8 t;
            t = a;
            a = b;
            b = t;
        }
        w3dcgb_fast_map_draw_cube_one(&cubes[a], hidden_enabled, (w3dcgb_u8)(selected == a), a);
        w3dcgb_fast_map_draw_cube_one(&cubes[b], hidden_enabled, (w3dcgb_u8)(selected == b), b);
        w3dcgb_fast_map_draw_cube_one(&cubes[c], hidden_enabled, (w3dcgb_u8)(selected == c), c);
        w3dcgb_fast_prev_count = 3;
    }

    x = (w3dcgb_u8)(selected & 3);
    w3dcgb_fast_map_or_cell((w3dcgb_i16)x, (w3dcgb_i16)0, WIRE3DCGB_COLOR_HIGH, 15);
    if (hidden_enabled != 0) w3dcgb_fast_map_or_cell((w3dcgb_i16)15, (w3dcgb_i16)0, WIRE3DCGB_COLOR_HIGH, 15);
    else w3dcgb_fast_map_or_cell((w3dcgb_i16)14, (w3dcgb_i16)0, WIRE3DCGB_COLOR_LOW, 15);

    w3dcgb_wait_vblank_start();
    w3dcgb_fast_map_flush_gdma_asm();
}
Wire3DCGB_DrawFastCubes

깊이에 따라 크기가 달라지는 2D 외곽선으로 큐브를 최대 3개 그립니다.

사용 형식

c
void Wire3DCGB_DrawFastCubes(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);

매개변수

cubes

고속 큐브 그리기에 사용하는 위치·각도·색상 배열입니다.

count

제공한 배열 항목 수입니다. 실제 처리 상한은 해당 연산의 설명을 참조하세요.

hidden_enabled

0이면 숨은 모서리도 그리며, 0이 아니면 간소화된 숨은 모서리 제거를 선택합니다.

selected

선택한 오브젝트의 원본 배열 인덱스입니다. 스탬프 API는 상태 표시기에 이 값을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

호출자의 배열 순서를 바꾸지 않고 원래 Z 값을 기준으로 먼 순서로 정렬하여 2D 근사 큐브를 최대 3개 그립니다. null이나 빈 입력은 무시합니다. selected는 원본 배열의 인덱스입니다. 카메라와 회전은 사용하지 않으며 색도 복원하지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Fast cube approximations use screen offsets and depth size bands, not a camera.
#include "wire_cgb_example.h"
Wire3DCGB_FastCube cubes[2];
void main() {
    u8 i;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    for(i=0;i<2;i++){cubes[i].rx=0;cubes[i].ry=0;cubes[i].rz=0;}
    cubes[0].x=-32;cubes[0].y=-8;cubes[0].z=90;cubes[0].color=1;
    cubes[1].x=32;cubes[1].y=8;cubes[1].z=160;cubes[1].color=2;
    Wire3DCGB_SetCamera(100,0,0,4,4,4); // FastCubes intentionally ignores this.
    Wire3DCGB_DrawFastCubes(cubes,2,1,0);
    Wire3DCGB_DrawFastStatus(1,0);
    result[0]=Wire3DCGB_GetLineColor();
    result[1]=cubes[0].z;result[2]=cubes[1].z;
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

왼쪽의 가까운 빨간 큐브가 오른쪽의 먼 파란 큐브보다 큽니다. 초록 십자 표시가 선택한 빨간 큐브를 가리킵니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_cubes.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_cubes.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:156

kitaqgb/lib/wire3d_cgb.c:8765

c
void Wire3DCGB_DrawFastCubes(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected)
{
    w3dcgb_u8 scene_count;
    w3dcgb_u8 a;
    w3dcgb_u8 b;
    w3dcgb_u8 c;
    w3dcgb_u8 x;

    if (cubes == 0) return;
    scene_count = count;
    if (scene_count == 0) return;
    if (scene_count > 3) scene_count = 3;

    a = 0;
    b = 1;
    c = 2;
    if (scene_count == 1)
    {
        w3dcgb_draw_fast_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0));
        return;
    }

    if (scene_count == 2)
    {
        if (cubes[0].z < cubes[1].z)
        {
            w3dcgb_draw_fast_cube_one(&cubes[1], hidden_enabled, (w3dcgb_u8)(selected == 1));
            w3dcgb_draw_fast_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0));
        }
        else
        {
            w3dcgb_draw_fast_cube_one(&cubes[0], hidden_enabled, (w3dcgb_u8)(selected == 0));
            w3dcgb_draw_fast_cube_one(&cubes[1], hidden_enabled, (w3dcgb_u8)(selected == 1));
        }
        return;
    }

    if (cubes[a].z < cubes[b].z)
    {
        w3dcgb_u8 t;
        t = a;
        a = b;
        b = t;
    }
    if (cubes[b].z < cubes[c].z)
    {
        w3dcgb_u8 t;
        t = b;
        b = c;
        c = t;
    }
    if (cubes[a].z < cubes[b].z)
    {
        w3dcgb_u8 t;
        t = a;
        a = b;
        b = t;
    }

    w3dcgb_draw_fast_cube_one(&cubes[a], hidden_enabled, (w3dcgb_u8)(selected == a));
    w3dcgb_draw_fast_cube_one(&cubes[b], hidden_enabled, (w3dcgb_u8)(selected == b));
    w3dcgb_draw_fast_cube_one(&cubes[c], hidden_enabled, (w3dcgb_u8)(selected == c));
}
Wire3DCGB_DrawFastProjectile

이미 투영된 중심에 깊이와 위상으로 크기와 방향을 정한 6모서리 발사체를 그립니다.

사용 형식

c
void Wire3DCGB_DrawFastProjectile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_i16 z, w3dcgb_u8 phase, w3dcgb_u8 color);

매개변수

x

뷰포트 픽셀 단위의 중심 X 좌표입니다.

y

뷰포트 픽셀 단위의 중심 Y 좌표입니다.

z

크기를 선택하거나 투영을 계산하는 데 사용하는 깊이입니다.

phase

회전 위상입니다. 8카운트마다 다음 방향으로 넘어갑니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

이미 투영된 중심에 깊이별 크기 4단계와 위상별 방향 4종을 사용해 모서리 6개의 발사체를 그립니다. 중심이 X=10~117 또는 Y=10~85 밖이면 제외하고, 범위를 변경된 것으로 표시하며 요청한 색을 선택한 상태로 둡니다. 일반 래스터라이저를 사용하고 카메라는 적용하지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
    shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
    Wire3DCGB_SetLineColor(2);
    Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
    Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
    Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
    Wire3DCGB_DrawTinyModel2D(104,24,16,3);
    result[0]=Wire3DCGB_ProjectAxis48(48,96);
    result[1]=Wire3DCGB_ProjectAxis48(-48,96);
    Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
    result[2]=Wire3DCGB_GetLineColor();
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 수평 모서리 두 개, 파란 정사각형, 잘린 초록 테두리, 초록 6픽셀 마커, 빨간 발사체로 목록 형식을 비교합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:159

kitaqgb/lib/wire3d_cgb.c:8833

c
void Wire3DCGB_DrawFastProjectile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_i16 z,
                                  w3dcgb_u8 phase, w3dcgb_u8 color)
{
    w3dcgb_u8 radius;
    w3dcgb_u8 half;
    w3dcgb_u8 depth;
    w3dcgb_u8 ax;
    w3dcgb_u8 ay;
    w3dcgb_u8 bx;
    w3dcgb_u8 by;
    w3dcgb_u8 cx;
    w3dcgb_u8 cy;
    w3dcgb_u8 dx;
    w3dcgb_u8 dy;
    w3dcgb_u8 spin;

    if ((x < 10) || (x > 117) || (y < 10) || (y > 85)) return;
    radius = 3;
    depth = 1;
    if (z <= 160) { radius = 4; depth = 2; }
    if (z <= 112) { radius = 5; depth = 3; }
    if (z <= 64) { radius = 7; depth = 4; }
    half = (w3dcgb_u8)(radius >> 1);

    ax = x;
    ay = (w3dcgb_u8)(y - radius);
    bx = (w3dcgb_u8)(x - radius);
    by = (w3dcgb_u8)(y + half);
    cx = (w3dcgb_u8)(x + radius);
    cy = by;
    spin = (w3dcgb_u8)((phase >> 3) & 3);
    dx = (w3dcgb_u8)(x + depth);
    dy = (w3dcgb_u8)(y - depth);
    if (spin == 1) dy = (w3dcgb_u8)(y + depth);
    else if (spin == 2)
    {
        dx = (w3dcgb_u8)(x - depth);
        dy = (w3dcgb_u8)(y + depth);
    }
    else if (spin == 3) dx = (w3dcgb_u8)(x - depth);

    w3dcgb_mark_dirty_rect((w3dcgb_u8)(x - radius), (w3dcgb_u8)(y - radius),
                           (w3dcgb_u8)(x + radius), (w3dcgb_u8)(y + radius));
    w3dcgb_line_color = color;
    w3dcgb_draw_line_raw(ax, ay, bx, by);
    w3dcgb_draw_line_raw(bx, by, cx, cy);
    w3dcgb_draw_line_raw(cx, cy, ax, ay);
    w3dcgb_draw_line_raw(ax, ay, dx, dy);
    w3dcgb_draw_line_raw(bx, by, dx, dy);
    w3dcgb_draw_line_raw(cx, cy, dx, dy);
}
Wire3DCGB_DrawFastStatus

오브젝트 선택과 은선 모드를 나타내는 작은 선 표시기를 그립니다.

사용 형식

c
void Wire3DCGB_DrawFastStatus(w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);

매개변수

hidden_enabled

0이면 숨은 모서리도 그리며, 0이 아니면 간소화된 숨은 모서리 제거를 선택합니다.

selected

선택한 오브젝트의 원본 배열 인덱스입니다. 스탬프 API는 상태 표시기에 이 값을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

색상 3으로 작은 선택/은선 모드 표시기를 그리고 일반 모드의 해당 범위를 변경된 것으로 표시합니다. selected는 0~2로 가정하며 검사하지 않습니다. 글꼴 타일 대신 선을 사용하고 이전 색을 복원하지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Fast cube approximations use screen offsets and depth size bands, not a camera.
#include "wire_cgb_example.h"
Wire3DCGB_FastCube cubes[2];
void main() {
    u8 i;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    for(i=0;i<2;i++){cubes[i].rx=0;cubes[i].ry=0;cubes[i].rz=0;}
    cubes[0].x=-32;cubes[0].y=-8;cubes[0].z=90;cubes[0].color=1;
    cubes[1].x=32;cubes[1].y=8;cubes[1].z=160;cubes[1].color=2;
    Wire3DCGB_SetCamera(100,0,0,4,4,4); // FastCubes intentionally ignores this.
    Wire3DCGB_DrawFastCubes(cubes,2,1,0);
    Wire3DCGB_DrawFastStatus(1,0);
    result[0]=Wire3DCGB_GetLineColor();
    result[1]=cubes[0].z;result[2]=cubes[1].z;
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

왼쪽의 가까운 빨간 큐브가 오른쪽의 먼 파란 큐브보다 큽니다. 초록 십자 표시가 선택한 빨간 큐브를 가리킵니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_cubes.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_cubes.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:157

kitaqgb/lib/wire3d_cgb.c:8888

c
void Wire3DCGB_DrawFastStatus(w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected)
{
    w3dcgb_u8 x;

    w3dcgb_mark_dirty_rect(0, 0, 31, 7);
    w3dcgb_mark_dirty_rect(116, 0, 127, 7);

    x = (w3dcgb_u8)(4 + (selected * 8));
    w3dcgb_line_color = WIRE3DCGB_COLOR_HIGH;
    w3dcgb_draw_line_raw(x, 3, (w3dcgb_u8)(x + 5), 3);
    w3dcgb_draw_line_raw(x, 6, (w3dcgb_u8)(x + 5), 6);
    if (hidden_enabled != 0)
    {
        w3dcgb_draw_line_raw(118, 3, 124, 3);
        w3dcgb_draw_line_raw(118, 6, 124, 6);
    }
    else
    {
        w3dcgb_draw_line_raw(118, 3, 124, 6);
        w3dcgb_draw_line_raw(118, 6, 124, 3);
    }
}
Wire3DCGB_DrawLine2D

활성 렌더러로 양 끝점을 포함하는 화면 좌표 선을 그립니다.

사용 형식

c
void Wire3DCGB_DrawLine2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

바이트 끝점을 저장하고 일반 또는 전체 화면 선 래스터라이저를 호출합니다. 좌표는 선택한 뷰포트 안에 있어야 합니다. 부호 있는 좌표나 화면 밖 도형에는 DrawLineClipped2D를 사용하세요. 일반 선은 색상 평면을 OR 연산하고 부분 전송 경계를 표시하지 않으므로, 부분 업로드 전에는 클리핑 API나 InvalidateFrameHistory를 사용하세요. 전체 화면 선은 색을 교체하고 타일을 할당합니다. 사용 중인 두 선 경로 모두 색상 0을 지우기가 아닌 3으로 처리합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:177

kitaqgb/lib/wire3d_cgb.c:8363

c
void Wire3DCGB_DrawLine2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by)
{
    w3dcgb_line_x0 = ax;
    w3dcgb_line_y0 = ay;
    w3dcgb_line_x1 = bx;
    w3dcgb_line_y1 = by;
    if (w3dcgb_full_mode != 0) w3dcgb_full_line_fast_asm();
    else w3dcgb_line_stage_asm();
}
Wire3DCGB_DrawLine2DColor

선택한 색을 유지하면서 화면 좌표 선을 일시적인 색으로 그립니다.

사용 형식

c
void Wire3DCGB_DrawLine2DColor(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 color);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

DrawLine2D 호출 동안 color & 3을 설정하고 이전 색을 복원합니다. 해당 함수의 좌표, 색상 합성, 부분 전송 범위 조건을 따르세요. 두 활성 렌더러 모두 0으로 선을 지울 수 없습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:178

kitaqgb/lib/wire3d_cgb.c:8376

c
void Wire3DCGB_DrawLine2DColor(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 color)
{
    w3dcgb_u8 old_color;
    old_color = w3dcgb_line_color;
    Wire3DCGB_SetLineColor(color);
    Wire3DCGB_DrawLine2D(ax, ay, bx, by);
    w3dcgb_line_color = old_color;
}
Wire3DCGB_DrawLine3D

월드 좌표의 끝점을 카메라로 투영하고 현재 색으로 선을 그립니다.

사용 형식

c
void Wire3DCGB_DrawLine3D(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz);

매개변수

ax

월드 좌표계에서 시작점의 X 성분입니다.

ay

월드 좌표계에서 시작점의 Y 성분입니다.

az

월드 좌표계에서 시작점의 Z 성분입니다.

bx

월드 좌표계에서 끝점의 X 성분입니다.

by

월드 좌표계에서 끝점의 Y 성분입니다.

bz

월드 좌표계에서 끝점의 Z 성분입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

두 끝점을 카메라를 통해 128×96 뷰포트로 투영합니다. 어느 한 끝점이라도 깊이 검사를 통과하지 못하면 선 전체를 제외하며, 근평면을 가로지르는 선을 잘라 주지 않습니다. DrawLine2D는 모드에 따라 분기하지만 투영은 계속 128×96입니다. 일반 선은 색상 평면을 합성하고 부분 전송 경계는 표시하지 않으므로, 전체 업로드를 사용하거나 부분 업로드 전에 프레임 이력을 명시적으로 무효화하세요.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:172

kitaqgb/lib/wire3d_cgb.c:8992

c
void Wire3DCGB_DrawLine3D(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz)
{
    w3dcgb_u8 sx0;
    w3dcgb_u8 sy0;
    w3dcgb_u8 sx1;
    w3dcgb_u8 sy1;

    if (w3dcgb_project_world(ax, ay, az, &sx0, &sy0) == 0) return;
    if (w3dcgb_project_world(bx, by, bz, &sx1, &sy1) == 0) return;
    Wire3DCGB_DrawLine2D(sx0, sy0, sx1, sy1);
}
Wire3DCGB_DrawLine3DColor

3D 선을 일시적인 색으로 그립니다.

사용 형식

c
void Wire3DCGB_DrawLine3DColor(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz, w3dcgb_u8 color);

매개변수

ax

월드 좌표계에서 시작점의 X 성분입니다.

ay

월드 좌표계에서 시작점의 Y 성분입니다.

az

월드 좌표계에서 시작점의 Z 성분입니다.

bx

월드 좌표계에서 끝점의 X 성분입니다.

by

월드 좌표계에서 끝점의 Y 성분입니다.

bz

월드 좌표계에서 끝점의 Z 성분입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

DrawLine3D 호출 동안 color & 3을 선택한 뒤 이전 색을 복원합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:173

kitaqgb/lib/wire3d_cgb.c:9005

c
void Wire3DCGB_DrawLine3DColor(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz, w3dcgb_u8 color)
{
    w3dcgb_u8 old_color;
    old_color = w3dcgb_line_color;
    Wire3DCGB_SetLineColor(color);
    Wire3DCGB_DrawLine3D(ax, ay, az, bx, by, bz);
    w3dcgb_line_color = old_color;
}
Wire3DCGB_DrawLineClipped2D

부호 있는 화면 좌표를 뷰포트에 맞춰 자르고 요청한 색으로 선을 그립니다.

사용 형식

c
void Wire3DCGB_DrawLineClipped2D(w3dcgb_i16 x0, w3dcgb_i16 y0, w3dcgb_i16 x1, w3dcgb_i16 y1, w3dcgb_u8 color);

매개변수

x0

뷰포트 픽셀 단위의 작은 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

y0

뷰포트 픽셀 단위의 작은 쪽 Y 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

x1

뷰포트 픽셀 단위의 큰 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

y1

뷰포트 픽셀 단위의 큰 쪽 Y 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

끝점은 부호 있는 값이며 래스터라이저의 u8 ABI로 변환하기 전에 잘립니다. 부호 있는 2D 선을 선택한 뷰포트에 맞춰 자른 뒤 일시적인 색으로 그립니다. ±2047 밖의 입력은 거부합니다. 128×96 안에 완전히 들어오는 선은 빠른 경로를 사용하고, 나머지는 영역 코드와 범위를 제한한 정수 교점 계산을 최대 8회 반복합니다. 승인된 일반 모드 선은 변경 경계를 표시합니다. 이는 화면 클리핑만 수행하며 3D 투영이나 깊이 클리핑은 하지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:136

선언 주석 원문
Signed endpoints, clipped before conversion to the rasterizer's u8 ABI.

kitaqgb/lib/wire3d_cgb.c:9745

c
void Wire3DCGB_DrawLineClipped2D(w3dcgb_i16 x0, w3dcgb_i16 y0,
                               w3dcgb_i16 x1, w3dcgb_i16 y1, w3dcgb_u8 color)
{
    w3dcgb_u8 c0;
    w3dcgb_u8 c1;
    w3dcgb_u8 outside;
    w3dcgb_u8 guard;
    w3dcgb_i16 x;
    w3dcgb_i16 y;
    c0 = 0;
    c1 = 0;
    if ((((x0 | y0 | x1 | y1) & 0xFF80) != 0) || (y0 >= WIRE3DCGB_SCREEN_H) || (y1 >= WIRE3DCGB_SCREEN_H))
    {
        if ((x0 < -2047) || (x0 > 2047) || (y0 < -2047) || (y0 > 2047) ||
            (x1 < -2047) || (x1 > 2047) || (y1 < -2047) || (y1 > 2047)) return;
        c0 = w3dcgb_clip_outcode(x0, y0);
        c1 = w3dcgb_clip_outcode(x1, y1);
    }
    guard = 0;
    while (guard < 8)
    {
        if ((c0 | c1) == 0)
        {
            /* The existing ASM rasterizer handles the hot, in-window path. */
            if (w3dcgb_full_mode == 0) w3dcgb_mark_dirty_line((w3dcgb_u8)x0, (w3dcgb_u8)y0,
                                  (w3dcgb_u8)x1, (w3dcgb_u8)y1);
            Wire3DCGB_DrawLine2DColor((w3dcgb_u8)x0, (w3dcgb_u8)y0,
                                    (w3dcgb_u8)x1, (w3dcgb_u8)y1, color);
            return;
        }
        if ((c0 & c1) != 0) return;
        outside = c0;
        if (outside == 0) outside = c1;
        if ((outside & 12) != 0)
        {
            y = 0;
            if ((outside & 8) != 0) y = WIRE3DCGB_SCREEN_H - 1;
            if (((outside & 8) != 0) && (w3dcgb_full_mode != 0)) y = WIRE3DCGB_FULL_SCREEN_H - 1;
            x = (w3dcgb_i16)(x0 + w3dcgb_clip_muldiv((w3dcgb_i16)(x1 - x0),
                (w3dcgb_i16)(y - y0), (w3dcgb_i16)(y1 - y0)));
        }
        else
        {
            x = 0;
            if ((outside & 2) != 0) x = WIRE3DCGB_SCREEN_W - 1;
            if (((outside & 2) != 0) && (w3dcgb_full_mode != 0)) x = WIRE3DCGB_FULL_SCREEN_W - 1;
            y = (w3dcgb_i16)(y0 + w3dcgb_clip_muldiv((w3dcgb_i16)(y1 - y0),
                (w3dcgb_i16)(x - x0), (w3dcgb_i16)(x1 - x0)));
        }
        if (outside == c0) { x0 = x; y0 = y; c0 = w3dcgb_clip_outcode(x0, y0); }
        else { x1 = x; y1 = y; c1 = w3dcgb_clip_outcode(x1, y1); }
        guard = (w3dcgb_u8)(guard + 1);
    }
}
Wire3DCGB_DrawLineList2DColor

지정한 색으로 4바이트 화면 좌표 선 레코드 목록을 그립니다.

사용 형식

c
void Wire3DCGB_DrawLineList2DColor(const w3dcgb_u8* line_xy, w3dcgb_u8 line_count, w3dcgb_u8 color);

매개변수

line_xy

(x0,y0,x1,y1) 레코드로 구성된 바이트 배열입니다.

line_count

선 레코드 수입니다. 최대 64개를 처리합니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

4바이트(x0,y0,x1,y1) 레코드를 최대 64개 그리며, null 목록은 무시합니다. 끝점은 선택한 뷰포트 안에 있어야 합니다. 이전 색을 유지하며 각 선을 일반 또는 전체 화면 래스터라이저에 전달합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:186

kitaqgb/lib/wire3d_cgb.c:8571

c
void Wire3DCGB_DrawLineList2DColor(const w3dcgb_u8* line_xy,
                                  w3dcgb_u8 line_count, w3dcgb_u8 color)
{
    w3dcgb_u8 i;
    w3dcgb_u8 offset;
    w3dcgb_u8 old_color;
    if (line_xy == 0) return;
    if (line_count > WIRE3DCGB_MODEL_EDGE_LIMIT) line_count = WIRE3DCGB_MODEL_EDGE_LIMIT;

    old_color = w3dcgb_line_color;
    w3dcgb_line_color = (w3dcgb_u8)(color & 3);
    i = 0;
    offset = 0;
    while (i < line_count)
    {
        w3dcgb_line_x0 = line_xy[(__safe_index w3dcgb_u8)offset];
        offset = (w3dcgb_u8)(offset + 1);
        w3dcgb_line_y0 = line_xy[(__safe_index w3dcgb_u8)offset];
        offset = (w3dcgb_u8)(offset + 1);
        w3dcgb_line_x1 = line_xy[(__safe_index w3dcgb_u8)offset];
        offset = (w3dcgb_u8)(offset + 1);
        w3dcgb_line_y1 = line_xy[(__safe_index w3dcgb_u8)offset];
        offset = (w3dcgb_u8)(offset + 1);
        if (w3dcgb_full_mode != 0) w3dcgb_full_line_fast_asm();
        else w3dcgb_line_stage_asm();
        i = (w3dcgb_u8)(i + 1);
    }
    w3dcgb_line_color = old_color;
}
Wire3DCGB_DrawMaskedModel2D

미리 투영된 정점과 모서리 비트마스크로 활성화된 모델 모서리를 그립니다.

사용 형식

c
void Wire3DCGB_DrawMaskedModel2D(const Wire3DCGB_Model* model, const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y, const w3dcgb_u8* edge_mask, w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

vertex_x

미리 투영된 정점 X 오프셋 배열입니다.

vertex_y

미리 투영된 정점 Y 오프셋 배열입니다.

edge_mask

모서리마다 가시성 비트 하나를 갖는 바이트 배열입니다. 최하위 비트부터 사용합니다.

x

뷰포트 픽셀 단위의 중심 X 좌표입니다.

y

뷰포트 픽셀 단위의 중심 Y 좌표입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

(x,y) 기준으로 미리 투영된 부호 있는 바이트 오프셋을 사용해 활성화된 모델 모서리를 그립니다. 마스크는 바이트당 모서리 8개이며 최하위 비트부터입니다. 모든 포인터와 정점 인덱스는 유효해야 하며, 모서리가 0개여도 edge_mask[0]을 읽습니다. 개수에 상한을 적용하지 않습니다. 이동한 끝점은 바이트 변환 전에 뷰포트 안에 있어야 합니다. 음수는 래핑됩니다. 이전 선 색을 유지하고 활성 모드에 따라 분기합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
    shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
    Wire3DCGB_SetLineColor(2);
    Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
    Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
    Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
    Wire3DCGB_DrawTinyModel2D(104,24,16,3);
    result[0]=Wire3DCGB_ProjectAxis48(48,96);
    result[1]=Wire3DCGB_ProjectAxis48(-48,96);
    Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
    result[2]=Wire3DCGB_GetLineColor();
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 수평 모서리 두 개, 파란 정사각형, 잘린 초록 테두리, 초록 6픽셀 마커, 빨간 발사체로 목록 형식을 비교합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:179

kitaqgb/lib/wire3d_cgb.c:8392

c
void Wire3DCGB_DrawMaskedModel2D(const Wire3DCGB_Model* model,
                                 const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y,
                                 const w3dcgb_u8* edge_mask,
                                 w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color)
{
    w3dcgb_u8 i;
    w3dcgb_u8 bit;
    w3dcgb_u8 mask_index;
    w3dcgb_u8 mask;
    w3dcgb_u8 a;
    w3dcgb_u8 b;
    w3dcgb_u8 old_color;

    old_color = w3dcgb_line_color;
    w3dcgb_line_color = (w3dcgb_u8)(color & 3);
    i = 0;
    bit = 1;
    mask_index = 0;
    mask = edge_mask[0];
    while (i < model->edge_count)
    {
        if ((mask & bit) != 0)
        {
            a = model->edges[(__safe_index w3dcgb_u8)i].a;
            b = model->edges[(__safe_index w3dcgb_u8)i].b;
            w3dcgb_line_x0 = (w3dcgb_u8)((w3dcgb_i16)x + (w3dcgb_i16)vertex_x[(__safe_index w3dcgb_u8)a]);
            w3dcgb_line_y0 = (w3dcgb_u8)((w3dcgb_i16)y + (w3dcgb_i16)vertex_y[(__safe_index w3dcgb_u8)a]);
            w3dcgb_line_x1 = (w3dcgb_u8)((w3dcgb_i16)x + (w3dcgb_i16)vertex_x[(__safe_index w3dcgb_u8)b]);
            w3dcgb_line_y1 = (w3dcgb_u8)((w3dcgb_i16)y + (w3dcgb_i16)vertex_y[(__safe_index w3dcgb_u8)b]);
            if (w3dcgb_full_mode != 0) w3dcgb_full_line_fast_asm();
            else w3dcgb_line_stage_asm();
        }
        i = (w3dcgb_u8)(i + 1);
        bit = (w3dcgb_u8)(bit << 1);
        if ((bit == 0) && (i < model->edge_count))
        {
            bit = 1;
            mask_index = (w3dcgb_u8)(mask_index + 1);
            mask = edge_mask[(__safe_index w3dcgb_u8)mask_index];
        }
    }
    w3dcgb_line_color = old_color;
}
Wire3DCGB_DrawModel

지정한 위치와 회전으로 3D 모델을 원래 크기로 그립니다.

사용 형식

c
void Wire3DCGB_DrawModel(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

DrawModelScaled의 조건에 따라 Q8 배율 1(256)로 모델을 그립니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:128

kitaqgb/lib/wire3d_cgb.c:9015

c
void Wire3DCGB_DrawModel(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz)
{
    Wire3DCGB_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}
Wire3DCGB_DrawModelColor

원래 크기의 모델을 일시적인 색으로 그립니다.

사용 형식

c
void Wire3DCGB_DrawModelColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_u8 color);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

일시적인 색을 사용해 Q8 배율 1로 모델을 그린 뒤 원래 색으로 되돌립니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:130

kitaqgb/lib/wire3d_cgb.c:9021

c
void Wire3DCGB_DrawModelColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_u8 color)
{
    Wire3DCGB_DrawModelScaledColor(model, x, y, z, rx, ry, rz, 256, color);
}
Wire3DCGB_DrawModelScaled

모델의 크기를 조절하고 회전·투영한 뒤, 선택된 모서리를 현재 색으로 그립니다.

사용 형식

c
void Wire3DCGB_DrawModelScaled(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

양수 Q8 배율로 최대 24개 정점을 투영합니다. 0 이하의 배율은 1배로 처리합니다. 1배 곱셈과 0각도 회전은 생략합니다. 중간값은 s16 범위에 들어가야 합니다. 인접 관계 필터를 사용할 수 있으면 최대 16개 앞면 플래그를 만든 뒤, 깊이와 정점 인덱스가 유효한 모서리를 그립니다. 모델의 모서리 수에는 64개 제한이 없습니다. 근평면 클리핑은 하지 않습니다. 공유 투영 캐시를 교체하고 일반 128×96 스테이징 영역에 선 색을 OR 연산으로 기록합니다. 이 경로는 부분 전송 경계를 표시하지 않으므로, 전체 업로드를 수행하거나 부분 업로드 전에 프레임 이력을 명시적으로 무효화하세요.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:129

kitaqgb/lib/wire3d_cgb.c:9396

c
void Wire3DCGB_DrawModelScaled(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8)
{
    w3dcgb_u8 i;
    w3dcgb_u8 count;
    w3dcgb_u8 edge_count;
    w3dcgb_u8 face_count;
    w3dcgb_u8 camera_unrotated;
    w3dcgb_u8 unit_scale;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->edges == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3DCGB_MODEL_VERTEX_LIMIT) count = WIRE3DCGB_MODEL_VERTEX_LIMIT;
    unit_scale = 0;
    if (scale_q8 == 256) unit_scale = 1;
    camera_unrotated = 0;
    if ((w3dcgb_cam_yaw == 0) && (w3dcgb_cam_pitch == 0) && (w3dcgb_cam_roll == 0))
    {
        camera_unrotated = 1;
    }

    i = 0;
    while (i < count)
    {
        const Wire3DCGB_Vec3* v;
        w3dcgb_i16 vx;
        w3dcgb_i16 vy;
        w3dcgb_i16 vz;
        w3dcgb_u8 sx;
        w3dcgb_u8 sy;
        w3dcgb_u8 projected;

        v = &model->vertices[(__safe_index w3dcgb_u8)i];
        if (unit_scale != 0)
        {
            vx = v->x;
            vy = v->y;
            vz = v->z;
        }
        else
        {
            vx = (w3dcgb_i16)((v->x * scale_q8) >> 8);
            vy = (w3dcgb_i16)((v->y * scale_q8) >> 8);
            vz = (w3dcgb_i16)((v->z * scale_q8) >> 8);
        }

        if (ry != 0) w3dcgb_rotate_y(&vx, &vz, (w3dcgb_i8)ry);
        if (rx != 0) w3dcgb_rotate_x(&vy, &vz, (w3dcgb_i8)rx);
        if (rz != 0) w3dcgb_rotate_z(&vx, &vy, (w3dcgb_i8)rz);

        vx = (w3dcgb_i16)(vx + x);
        vy = (w3dcgb_i16)(vy + y);
        vz = (w3dcgb_i16)(vz + z);

        if (camera_unrotated != 0)
        {
            vx = (w3dcgb_i16)(vx - w3dcgb_cam_x);
            vy = (w3dcgb_i16)(vy - w3dcgb_cam_y);
            vz = (w3dcgb_i16)(vz - w3dcgb_cam_z);
            projected = w3dcgb_project_camera_space(vx, vy, vz, &sx, &sy);
        }
        else
        {
            projected = w3dcgb_project_world(vx, vy, vz, &sx, &sy);
        }

        if (projected != 0)
        {
            w3dcgb_screen_x[(__safe_index w3dcgb_u8)i] = sx;
            w3dcgb_screen_y[(__safe_index w3dcgb_u8)i] = sy;
            w3dcgb_screen_visible[(__safe_index w3dcgb_u8)i] = 1;
        }
        else
        {
            w3dcgb_screen_visible[(__safe_index w3dcgb_u8)i] = 0;
        }
        i = (w3dcgb_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3DCGB_MODEL_FACE_LIMIT) face_count = WIRE3DCGB_MODEL_FACE_LIMIT;
    if ((model->flags & WIRE3DCGB_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
    {
        w3dcgb_build_face_visibility(model, count, face_count);
    }

    edge_count = model->edge_count;
    i = 0;
    while (i < edge_count)
    {
        const Wire3DCGB_Edge* e;
        e = &model->edges[(__safe_index w3dcgb_u8)i];
        if ((e->a < count) && (e->b < count))
        {
            if (w3dcgb_screen_visible[(__safe_index w3dcgb_u8)e->a] &&
                w3dcgb_screen_visible[(__safe_index w3dcgb_u8)e->b] &&
                w3dcgb_is_edge_visible(model, i, face_count))
            {
                w3dcgb_draw_model_line(
                    w3dcgb_screen_x[(__safe_index w3dcgb_u8)e->a],
                    w3dcgb_screen_y[(__safe_index w3dcgb_u8)e->a],
                    w3dcgb_screen_x[(__safe_index w3dcgb_u8)e->b],
                    w3dcgb_screen_y[(__safe_index w3dcgb_u8)e->b]);
            }
        }
        i = (w3dcgb_u8)(i + 1);
    }
}
Wire3DCGB_DrawModelScaledColor

지정한 배율과 일시적인 선 색상으로 모델을 그립니다.

사용 형식

c
void Wire3DCGB_DrawModelScaledColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8, w3dcgb_u8 color);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

DrawModelScaled 호출 동안 color & 3을 선택하고, 완료 후 호출 전 색을 복원합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:131

kitaqgb/lib/wire3d_cgb.c:9510

c
void Wire3DCGB_DrawModelScaledColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8, w3dcgb_u8 color)
{
    w3dcgb_u8 old_color;
    old_color = w3dcgb_line_color;
    Wire3DCGB_SetLineColor(color);
    Wire3DCGB_DrawModelScaled(model, x, y, z, rx, ry, rz, scale_q8);
    w3dcgb_line_color = old_color;
}
Wire3DCGB_DrawPoint2D

현재 색으로 픽셀 하나를 씁니다.

사용 형식

c
void Wire3DCGB_DrawPoint2D(w3dcgb_u8 x, w3dcgb_u8 y);

매개변수

x

뷰포트 픽셀 단위의 중심 X 좌표입니다.

y

뷰포트 픽셀 단위의 중심 Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

일반 모드에서는 128×96 밖의 좌표를 거부하고 부분 전송 경계를 표시한 뒤, 0을 포함한 현재 색으로 스테이징 픽셀을 교체합니다. 전체 화면 모드에서는 대신 두 끝점이 같은 고속 선을 그리므로 0은 색상 3을 뜻하고, 유효하지 않은 좌표는 해당 프레임의 오버플로 플래그를 설정합니다. 화면 전송은 나중에 수행됩니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:174

kitaqgb/lib/wire3d_cgb.c:8283

c
void Wire3DCGB_DrawPoint2D(w3dcgb_u8 x, w3dcgb_u8 y)
{
    w3dcgb_u8 tile;
    if (w3dcgb_full_mode != 0)
    {
        w3dcgb_line_x0 = x;
        w3dcgb_line_y0 = y;
        w3dcgb_line_x1 = x;
        w3dcgb_line_y1 = y;
        w3dcgb_full_line_fast_asm();
        return;
    }
    if (x >= WIRE3DCGB_SCREEN_W) return;
    if (y >= WIRE3DCGB_SCREEN_H) return;
    if (w3dcgb_full_frame_transfer == 0)
    {
        tile = (w3dcgb_u8)(((x >> 3) * W3DCGB_TILE_H) + (y >> 3));
        if (tile < w3dcgb_dirty_min_tile) w3dcgb_dirty_min_tile = tile;
        if (tile > w3dcgb_dirty_max_tile) w3dcgb_dirty_max_tile = tile;
    }
    w3dcgb_plot_x = x;
    w3dcgb_plot_y = y;
    w3dcgb_plot_stage_asm();
}
Wire3DCGB_DrawScene

최대 8개 오브젝트를 가까운 순서로 그리며, 앞서 그린 모델의 면으로 뒤의 선을 가립니다.

사용 형식

c
void Wire3DCGB_DrawScene(Wire3DCGB_Object* objects, w3dcgb_u8 count);

매개변수

objects

위치, 회전, 배율, 표시 여부 플래그를 담은 오브젝트 배열입니다.

count

제공한 배열 항목 수입니다. 실제 처리 상한은 해당 연산의 설명을 참조하세요.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

호출자의 배열을 바꾸지 않고 카메라 좌표계의 원점 깊이를 기준으로 최대 8개 오브젝트를 가까운 순서로 정렬합니다. 마스크를 지우고, 먼저 등록된 영역에 따른 가림 검사를 적용해 보이는 모델을 그린 뒤 해당 면을 가림 영역에 추가합니다. 모델 배열과 면 인덱스는 유효해야 합니다. 색상 0은 현재 색을 이어받으며, 앞선 오브젝트의 색일 수도 있습니다. 마지막에 호출 전 색을 복원하고 가림 검사를 끕니다. 이 모델 경로는 일반 128×96 스테이징 영역용입니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// A near square hides the middle of a farther blue line, regardless of array order.
#include "wire_cgb_example.h"
#include "wire_cgb_plane.h"
__prg_rom Wire3DCGB_Vec3 back_vertices[2]={{-96,0,0},{96,0,0}};
__prg_rom Wire3DCGB_Edge back_edges[1]={{0,1}};
Wire3DCGB_Model back;
Wire3DCGB_Object objects[2];
void main() {
    u8 i;
    wire_results_clear();wire_plane_setup();
    back.vertices=back_vertices;back.edges=back_edges;back.faces=0;back.edge_faces=0;
    back.vertex_count=2;back.edge_count=1;back.face_count=0;back.flags=0;
    for(i=0;i<2;i++) {
        objects[i].x=0;objects[i].y=0;objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256;objects[i].visible=1;
    }
    objects[0].model=&back;objects[0].z=128;objects[0].color=2;
    objects[1].model=&plane;objects[1].z=64;objects[1].color=1;
    Wire3DCGB_Init();wire_colors();Wire3DCGB_BeginFrame();Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawScene(objects,2);
    result[0]=objects[0].z;result[1]=objects[1].z;result[2]=Wire3DCGB_GetLineColor();
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

(46,30)..(82,66)의 가까운 빨간 정사각형이 더 먼 파란 수평선의 가운데를 가려 왼쪽과 오른쪽 구간만 보입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_scene.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_scene.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:155

kitaqgb/lib/wire3d_cgb.c:8918

c
void Wire3DCGB_DrawScene(Wire3DCGB_Object* objects, w3dcgb_u8 count)
{
    w3dcgb_u8 scene_count;
    w3dcgb_u8 i;
    w3dcgb_u8 old_color;

    if (objects == 0) return;

    scene_count = count;
    if (scene_count > WIRE3DCGB_SCENE_OBJECT_LIMIT) scene_count = WIRE3DCGB_SCENE_OBJECT_LIMIT;

    i = 0;
    while (i < scene_count)
    {
        w3dcgb_scene_order[(__safe_index w3dcgb_u8)i] = i;
        w3dcgb_scene_depth[(__safe_index w3dcgb_u8)i] = w3dcgb_scene_object_depth(&objects[(__safe_index w3dcgb_u8)i]);
        i = (w3dcgb_u8)(i + 1);
    }

    i = 0;
    while (i < scene_count)
    {
        w3dcgb_u8 j;
        j = (w3dcgb_u8)(i + 1);
        while (j < scene_count)
        {
            w3dcgb_u8 oi;
            w3dcgb_u8 oj;
            oi = w3dcgb_scene_order[(__safe_index w3dcgb_u8)i];
            oj = w3dcgb_scene_order[(__safe_index w3dcgb_u8)j];

            if (w3dcgb_scene_depth[(__safe_index w3dcgb_u8)oj] < w3dcgb_scene_depth[(__safe_index w3dcgb_u8)oi])
            {
                w3dcgb_scene_order[(__safe_index w3dcgb_u8)i] = oj;
                w3dcgb_scene_order[(__safe_index w3dcgb_u8)j] = oi;
            }
            j = (w3dcgb_u8)(j + 1);
        }
        i = (w3dcgb_u8)(i + 1);
    }

    old_color = w3dcgb_line_color;
    w3dcgb_clear_occlusion_mask();
    w3dcgb_occlusion_active = 0;

    i = 0;
    while (i < scene_count)
    {
        Wire3DCGB_Object* obj;
        obj = &objects[(__safe_index w3dcgb_u8)w3dcgb_scene_order[(__safe_index w3dcgb_u8)i]];
        if ((obj->visible != 0) && (obj->model != 0))
        {
            if (i == 0) w3dcgb_occlusion_active = 0;
            else w3dcgb_occlusion_active = 1;
            if (obj->color != 0) Wire3DCGB_SetLineColor(obj->color);
            Wire3DCGB_DrawModelScaled(obj->model, obj->x, obj->y, obj->z, (w3dcgb_i8)obj->rx, (w3dcgb_i8)obj->ry, (w3dcgb_i8)obj->rz, obj->scale_q8);
            w3dcgb_occlusion_active = 0;
            w3dcgb_mark_model_occluder(obj->model);
        }
        i = (w3dcgb_u8)(i + 1);
    }

    w3dcgb_occlusion_active = 0;
    w3dcgb_line_color = old_color;
}
Wire3DCGB_DrawTinyModel2D

앞과 뒤가 방향을 나타내는 6픽셀 마커를 그립니다.

사용 형식

c
void Wire3DCGB_DrawTinyModel2D(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 turn, w3dcgb_u8 color);

매개변수

x

뷰포트 픽셀 단위의 중심 X 좌표입니다.

y

뷰포트 픽셀 단위의 중심 Y 좌표입니다.

turn

하위 5비트로 작은 마커의 방향을 선택하는 값입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

선 색을 유지하면서 128×96 점 그리기 루틴으로 6픽셀 마커를 그립니다. 중심이 X=3~124 또는 Y=3~92 밖이면 무시합니다. turn의 하위 5비트로 왼쪽/직진/오른쪽을 나타내는 앞·뒤 오프셋을 선택합니다. 일반 3D 변환이 아니며 전체 화면 렌더러로 분기하지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
    shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
    Wire3DCGB_SetLineColor(2);
    Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
    Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
    Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
    Wire3DCGB_DrawTinyModel2D(104,24,16,3);
    result[0]=Wire3DCGB_ProjectAxis48(48,96);
    result[1]=Wire3DCGB_ProjectAxis48(-48,96);
    Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
    result[2]=Wire3DCGB_GetLineColor();
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 수평 모서리 두 개, 파란 정사각형, 잘린 초록 테두리, 초록 6픽셀 마커, 빨간 발사체로 목록 형식을 비교합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:175

kitaqgb/lib/wire3d_cgb.c:8313

c
void Wire3DCGB_DrawTinyModel2D(w3dcgb_u8 x, w3dcgb_u8 y,
                               w3dcgb_u8 turn, w3dcgb_u8 color)
{
    w3dcgb_u8 nose_x;
    w3dcgb_u8 tail_x;
    w3dcgb_u8 old_color;
    if ((x < 3) || (x > 124) || (y < 3) || (y > (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 4))) return;

    nose_x = x;
    tail_x = x;
    turn = (w3dcgb_u8)(turn & 31);
    if (turn < 12)
    {
        nose_x = (w3dcgb_u8)(x + 1);
        tail_x = (w3dcgb_u8)(x - 1);
    }
    else if (turn >= 20)
    {
        nose_x = (w3dcgb_u8)(x - 1);
        tail_x = (w3dcgb_u8)(x + 1);
    }

    old_color = w3dcgb_line_color;
    w3dcgb_line_color = (w3dcgb_u8)(color & 3);
    w3dcgb_plot_x = nose_x;
    w3dcgb_plot_y = (w3dcgb_u8)(y - 2);
    w3dcgb_plot_stage_asm();
    w3dcgb_plot_x = x;
    w3dcgb_plot_y = (w3dcgb_u8)(y - 1);
    w3dcgb_plot_stage_asm();
    w3dcgb_plot_x = (w3dcgb_u8)(x - 2);
    w3dcgb_plot_y = (w3dcgb_u8)(y + 1);
    w3dcgb_plot_stage_asm();
    w3dcgb_plot_x = (w3dcgb_u8)(x + 2);
    w3dcgb_plot_stage_asm();
    w3dcgb_plot_x = x;
    w3dcgb_plot_y = y;
    w3dcgb_plot_stage_asm();
    w3dcgb_plot_x = tail_x;
    w3dcgb_plot_y = (w3dcgb_u8)(y + 2);
    w3dcgb_plot_stage_asm();
    w3dcgb_line_color = old_color;
}
Wire3DCGB_DrawWhiteBorderFast

128×96 스테이징 영역 둘레에 색상 인덱스 2의 1픽셀 테두리를 그립니다.

사용 형식

c
void Wire3DCGB_DrawWhiteBorderFast();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

내부 픽셀과 WRAM 뱅크 선택을 유지하면서 일반 스테이징 영역 둘레에 색상 2의 1픽셀 테두리를 씁니다. 실제 보이는 색은 팔레트에 따라 달라집니다. 변경 범위는 표시하지 않으므로 부분 전송 호출자는 업로드를 준비해야 합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// A cleared 24-pixel strip and a palette-index-2 border have distinct purposes.
#include "wire_cgb_example.h"
void main() {
    u8 y;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    for(y=0;y<96;y++) Wire3DCGB_DrawLine2D(0,y,31,y);
    Wire3DCGB_EraseLeftGuard24Fast();
    // With this example's palette, color index 2 is blue rather than white.
    Wire3DCGB_DrawWhiteBorderFast();
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

왼쪽 24열이 지워지고 빨간 띠가 남습니다. 색상 인덱스 2의 바깥 테두리는 파란색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_guard.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_guard.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:147

kitaqgb/lib/wire3d_cgb.c:9369

c
void Wire3DCGB_DrawWhiteBorderFast()
{
    w3dcgb_draw_white_border_asm();
}
Wire3DCGB_EnableAtomicMaps

128×96 화면 출력이 두 배경 맵을 번갈아 사용하도록 설정합니다.

사용 형식

c
void Wire3DCGB_EnableAtomicMaps();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

시작 시에만 사용합니다. 양쪽 BG 맵을 예약하며 큐에 넣은 HUD 타일은 두 맵에 똑같이 반영됩니다. 128×96 초기화 중 맵 교대를 한 번 켭니다. 전체 화면 모드이거나 이미 켜져 있으면 무시합니다. LCD가 켜져 있으면 VBlank를 기다려 LCD를 끄고, 9800의 두 뱅크를 9C00으로 복사한 다음 각 뷰포트 속성이 타일 뱅크 0/1을 사용하도록 설정합니다. 9C00 맵을 선택하고 VBK를 0으로 하여 LCDC를 복원합니다. 두 BG 맵은 모두 예약되며, 큐에 넣은 HUD 타일 번호는 양쪽에 복제됩니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:144

선언 주석 원문
Startup-only: reserves both BG maps; queued HUD tiles are mirrored.

kitaqgb/lib/wire3d_cgb.c:7912

c
void Wire3DCGB_EnableAtomicMaps()
{
    if ((w3dcgb_full_mode != 0) || (w3dcgb_atomic_maps != 0)) return;
    __asm {
w3dam_wait:
        LDH_A_MEM 68
        CP_IMM 144
        JR_C w3dam_wait
        LDH_A_MEM 64
        PUSH_AF
        XOR_A
        LDH_MEM_A 64
        LDH_MEM_A 79
        LD_HL_IMM 0x9800
        LD_DE_IMM 0x9C00
        LD_B_IMM 4
w3dam_copy_page:
        LD_C_IMM 0
w3dam_copy_byte:
        LD_A_HL
        INC_HL
        LD_DE_A
        INC_DE
        DEC_C
        JR_NZ w3dam_copy_byte
        DEC_B
        JR_NZ w3dam_copy_page
        LDH_A_MEM 79
        AND_IMM 1
        JR_NZ w3dam_attrs
        LD_A_IMM 1
        LDH_MEM_A 79
        LD_HL_IMM 0x9800
        LD_DE_IMM 0x9C00
        LD_B_IMM 4
        JR w3dam_copy_page
w3dam_attrs:
        LD_HL_IMM 0x9800
        LD_DE_IMM 0x9C00
        LD_B_IMM 12
w3dam_row:
        LD_C_IMM 16
w3dam_cell:
        XOR_A
        LDI_HL_A
        LD_A_IMM 8
        LD_DE_A
        INC_DE
        DEC_C
        JR_NZ w3dam_cell
        LD_A_L
        ADD_A_IMM 16
        LD_L_A
        JR_NC w3dam_hl_ready
        INC_H
w3dam_hl_ready:
        LD_A_E
        ADD_A_IMM 16
        LD_E_A
        JR_NC w3dam_de_ready
        INC_D
w3dam_de_ready:
        DEC_B
        JR_NZ w3dam_row
        LD_A_IMM 1
        LD_MEM_A w3dcgb_atomic_maps
        XOR_A
        LDH_MEM_A 79
        POP_AF
        OR_IMM 8
        LDH_MEM_A 64
        RET
    }
}
Wire3DCGB_EnableDoubleSpeed

CGB CPU를 배속 동작으로 전환합니다.

사용 형식

c
void Wire3DCGB_EnableDoubleSpeed();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

CGB에서 KEY1이 이미 배속 상태를 나타내면 바로 반환합니다. 그렇지 않으면 속도 전환을 요청하고 STOP 도우미를 호출합니다. CGB 하드웨어를 전제로 하는 API이며 흑백 기기용 대체 동작은 없습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:116

kitaqgb/lib/wire3d_cgb.c:1081

c
void Wire3DCGB_EnableDoubleSpeed()
{
    if ((w3dcgb_reg_key1 & 0x80) != 0) return;
    w3dcgb_reg_key1 = 1;
    w3dcgb_cgb_speed_switch_asm();
}
Wire3DCGB_EndFrame

완성된 프레임을 업로드하고 표시합니다.

사용 형식

c
void Wire3DCGB_EndFrame();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

일반 모드에서는 대기 중인 BG 쓰기를 반영하고 스테이징 영역 전체를 전송한 뒤 완성된 타일 뱅크를 표시합니다. 전체 화면 모드에서는 할당된 타일을 전송·표시하며 HUD 큐를 처리하지 않습니다. LCD가 켜져 있어야 하며 전송 도우미의 뱅크·인터럽트 조건을 지켜야 합니다. 여러 프레임이 걸릴 수 있습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:189

kitaqgb/lib/wire3d_cgb.c:9881

c
void Wire3DCGB_EndFrame()
{
    if (w3dcgb_full_mode != 0)
    {
        w3dcgb_full_transfer_asm();
        w3dcgb_full_present_asm();
        return;
    }
    if (w3dcgb_bgq_count != 0)
    {
        w3dcgb_wait_vblank_start();
        w3dcgb_flush_bg_queue();
    }
    w3dcgb_transfer_stage_asm();
    w3dcgb_present_stage_asm();
}
Wire3DCGB_EndFrameFast

대기 중인 배경 쓰기를 처리하지 않고 프레임 전체를 업로드·표시합니다.

사용 형식

c
void Wire3DCGB_EndFrameFast();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

BG 큐를 비우지 않고 선택한 모드의 프레임 전체를 전송·표시합니다. 대기 중인 HUD 쓰기는 소비하지 않습니다. EndFrame과 같은 LCD·뱅크·인터럽트 조건을 지켜야 하며 전체 런타임 빌드가 필요합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:190

kitaqgb/lib/wire3d_cgb.c:9902

c
void Wire3DCGB_EndFrameFast()
{
    if (w3dcgb_full_mode != 0)
    {
        w3dcgb_full_transfer_asm();
        w3dcgb_full_present_asm();
        return;
    }
    w3dcgb_transfer_stage_asm();
    w3dcgb_present_stage_asm();
}
Wire3DCGB_EndFrameSparse

새 VBlank를 기다린 뒤 필요한 부분 범위를 업로드하고 표시합니다.

사용 형식

c
void Wire3DCGB_EndFrameSparse();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

일반 모드에서는 새 VBlank를 기다리고 EndFrameSparseNow를 호출합니다. 전체 화면 모드에서는 해당 모드의 전체 전송·표시 경로를 사용합니다. 전체 런타임과 켜진 LCD가 필요하며, 한 프레임 안에 끝난다는 보장은 없습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:191

kitaqgb/lib/wire3d_cgb.c:9917

c
void Wire3DCGB_EndFrameSparse()
{
    if (w3dcgb_full_mode != 0)
    {
        w3dcgb_full_transfer_asm();
        w3dcgb_full_present_asm();
        return;
    }
    w3dcgb_wait_vblank_start();
    Wire3DCGB_EndFrameSparseNow();
}
Wire3DCGB_EndFrameSparseNow

시작 시 새 VBlank를 기다리지 않고 배경 쓰기와 현재/N−2의 부분 범위를 전송합니다.

사용 형식

c
void Wire3DCGB_EndFrameSparseNow();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

대기 중인 BG 쓰기를 반영하고 현재/N−2의 부분 타일 범위를 뒤쪽 뱅크에 업로드한 다음 표시합니다. 시작 시 새 VBlank를 기다리는 단계는 생략하지만, 일반 맵 모드에서 빈 HUD 타일을 복원할 때는 여전히 기다리며 DMA와 표시 전환도 대기할 수 있습니다. 전체 런타임의 전체 화면 모드는 자체 경로로 넘깁니다. LCD가 켜져 있어야 하고 DMA가 활성인 동안 SVBK/VBK를 유지해야 합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:192

kitaqgb/lib/wire3d_cgb.c:9935

c
void Wire3DCGB_EndFrameSparseNow()
{
#ifndef WIRE3DCGB_MINIMAL_RUNTIME
    if (w3dcgb_full_mode != 0)
    {
        w3dcgb_full_transfer_asm();
        w3dcgb_full_present_asm();
        return;
    }
#endif
    /* Atomic mode never writes a displayed tile and does not need a
       frame-long VBlank wait before starting an off-screen upload. */
    if (w3dcgb_atomic_maps == 0) w3dcgb_restore_hud_blank_tile_asm();
    if (w3dcgb_bgq_count != 0) w3dcgb_flush_bg_queue();
    w3dcgb_transfer_dirty_tiles();
    w3dcgb_present_stage_asm();
}
Wire3DCGB_EraseLeftGuard24Fast

일반 스테이징 영역의 맨 왼쪽 24열을 지웁니다.

사용 형식

c
void Wire3DCGB_EraseLeftGuard24Fast();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

뱅크 선택을 보존하는 ASM으로 스테이징 영역의 맨 왼쪽 24열을 지웁니다. 변경 범위는 표시하지 않으므로 부분 전송 호출자는 지워진 타일을 전송 범위에 포함해야 합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// A cleared 24-pixel strip and a palette-index-2 border have distinct purposes.
#include "wire_cgb_example.h"
void main() {
    u8 y;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    for(y=0;y<96;y++) Wire3DCGB_DrawLine2D(0,y,31,y);
    Wire3DCGB_EraseLeftGuard24Fast();
    // With this example's palette, color index 2 is blue rather than white.
    Wire3DCGB_DrawWhiteBorderFast();
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

왼쪽 24열이 지워지고 빨간 띠가 남습니다. 색상 인덱스 2의 바깥 테두리는 파란색입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_guard.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_guard.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:146

kitaqgb/lib/wire3d_cgb.c:9200

c
void Wire3DCGB_EraseLeftGuard24Fast()
{
    w3dcgb_erase_left_guard24_asm();
}
Wire3DCGB_EraseModelFaces

투영된 모델의 앞면 안쪽에 있는 스테이징 픽셀을 지웁니다.

사용 형식

c
void Wire3DCGB_EraseModelFaces(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

정점과 면을 가진 은선 제거용 모델에서 정점을 최대 24개 변환하고, 최대 16개 면 중 앞을 향하는 삼각형을 지웁니다. 0 이하의 배율은 1배를 뜻합니다. 이 경로는 1배에서도 곱셈을 수행하며 각도가 0이어도 세 회전 도우미를 모두 실행합니다. 유효하지 않거나 깊이 검사를 통과하지 못한 면은 제외합니다. 공유 투영 캐시를 교체하며 일반 C 스테이징 지우기 루틴을 사용하므로, 호출자나 할당 과정에서 올바른 WRAM 매핑을 제공해야 합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Projected model faces erase a square opening; redraw its outline in green.
#include "wire_cgb_example.h"
#include "wire_cgb_plane.h"
void main() {
    u8 y;u8 bank;
    wire_results_clear();wire_plane_setup();Wire3DCGB_Init();wire_colors();Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    for(y=8;y<=88;y++) Wire3DCGB_DrawLine2D(24,y,104,y);
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_EraseModelFaces(&plane,0,0,64,0,0,0,256);
    sample_svbk=bank;
    Wire3DCGB_DrawModelColor(&plane,0,0,64,0,0,0,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_faces.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:132

kitaqgb/lib/wire3d_cgb.c:9033

c
void Wire3DCGB_EraseModelFaces(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8)
{
    w3dcgb_u8 i;
    w3dcgb_u8 count;
    w3dcgb_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->faces == 0) return;
    if ((model->flags & WIRE3DCGB_MODEL_HIDDEN_LINES) == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3DCGB_MODEL_VERTEX_LIMIT) count = WIRE3DCGB_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DCGB_Vec3* v;
        w3dcgb_i16 vx;
        w3dcgb_i16 vy;
        w3dcgb_i16 vz;
        w3dcgb_u8 sx;
        w3dcgb_u8 sy;

        v = &model->vertices[(__safe_index w3dcgb_u8)i];
        vx = (w3dcgb_i16)((v->x * scale_q8) >> 8);
        vy = (w3dcgb_i16)((v->y * scale_q8) >> 8);
        vz = (w3dcgb_i16)((v->z * scale_q8) >> 8);

        w3dcgb_rotate_y(&vx, &vz, (w3dcgb_i8)ry);
        w3dcgb_rotate_x(&vy, &vz, (w3dcgb_i8)rx);
        w3dcgb_rotate_z(&vx, &vy, (w3dcgb_i8)rz);

        vx = (w3dcgb_i16)(vx + x);
        vy = (w3dcgb_i16)(vy + y);
        vz = (w3dcgb_i16)(vz + z);

        if (w3dcgb_project_world(vx, vy, vz, &sx, &sy))
        {
            w3dcgb_screen_x[(__safe_index w3dcgb_u8)i] = sx;
            w3dcgb_screen_y[(__safe_index w3dcgb_u8)i] = sy;
            w3dcgb_screen_visible[(__safe_index w3dcgb_u8)i] = 1;
        }
        else
        {
            w3dcgb_screen_visible[(__safe_index w3dcgb_u8)i] = 0;
        }
        i = (w3dcgb_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3DCGB_MODEL_FACE_LIMIT) face_count = WIRE3DCGB_MODEL_FACE_LIMIT;
    w3dcgb_build_face_visibility(model, count, face_count);

    i = 0;
    while (i < face_count)
    {
        const Wire3DCGB_Face* f;
        f = &model->faces[(__safe_index w3dcgb_u8)i];
        if (w3dcgb_face_visible[(__safe_index w3dcgb_u8)i] &&
            w3dcgb_screen_visible[(__safe_index w3dcgb_u8)f->a] &&
            w3dcgb_screen_visible[(__safe_index w3dcgb_u8)f->b] &&
            w3dcgb_screen_visible[(__safe_index w3dcgb_u8)f->c])
        {
            w3dcgb_clear_triangle(
                w3dcgb_screen_x[(__safe_index w3dcgb_u8)f->a],
                w3dcgb_screen_y[(__safe_index w3dcgb_u8)f->a],
                w3dcgb_screen_x[(__safe_index w3dcgb_u8)f->b],
                w3dcgb_screen_y[(__safe_index w3dcgb_u8)f->b],
                w3dcgb_screen_x[(__safe_index w3dcgb_u8)f->c],
                w3dcgb_screen_y[(__safe_index w3dcgb_u8)f->c]);
        }
        i = (w3dcgb_u8)(i + 1);
    }
}
Wire3DCGB_ErasePackedSilhouette2D

일반 스테이징 영역의 두 색상 평면에서 패킹된 실루엣을 지웁니다.

사용 형식

c
void Wire3DCGB_ErasePackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count, w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);

매개변수

profile

행마다 1바이트를 사용하는 실루엣 배열입니다. 0xFF는 해당 행을 건너뜁니다.

count

제공한 배열 항목 수입니다. 실제 처리 상한은 해당 연산의 설명을 참조하세요.

y0

중심 Y에서 실루엣 첫 행까지의 부호 있는 오프셋입니다.

x

뷰포트 픽셀 단위의 중심 X 좌표입니다.

y

뷰포트 픽셀 단위의 중심 Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

스테이징된 두 비트플레인에서 패킹된 실루엣을 최대 29행 지웁니다. 형식, 배치, 2픽셀 여유와 클리핑은 MarkPackedSilhouette2D와 같고 null은 무시합니다. ASM 스팬 쓰기 루틴은 WRAM 뱅크 2를 선택했다가 원래 선택을 복원하지만 변경 타일을 표시하지는 않습니다. 부분 전송 모드에서는 호출자가 지워진 타일을 업로드 범위에 포함해야 합니다. 이 API는 128×96 스테이징 영역용입니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Colored panels expose triangle, span, rectangle and packed-silhouette erasure.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
    u8 y;
    u8 bank;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(8,y,40,y,1);
    for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(48,y,80,y,2);
    for(y=64;y<=72;y++) Wire3DCGB_DrawLine2DColor(88,y,120,y,3);
    // The C triangle/rectangle clearers access the stage through the current
    // WRAM window. Select bank 2 around them and restore the caller's bank.
    bank=sample_svbk; sample_svbk=2;
    Wire3DCGB_EraseTriangle2D(12,12,36,12,12,36);
    Wire3DCGB_EraseSpan2D(36,40,24);
    Wire3DCGB_EraseRect2D(56,16,72,32);
    Wire3DCGB_ErasePackedSilhouette2D(silhouette,5,-2,104,68);
    sample_svbk=bank;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

삼각형, 수평 스팬, 직사각형, 패킹된 실루엣으로 빨강·파랑·초록 패널에 검은 구멍을 만듭니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_erase.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_erase.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:153

kitaqgb/lib/wire3d_cgb.c:2038

c
void Wire3DCGB_ErasePackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count,
                                      w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y)
{
    w3dcgb_u8 i;
    w3dcgb_u8 packed;
    w3dcgb_u8 half_width;
    w3dcgb_i16 center;
    w3dcgb_i16 left;
    w3dcgb_i16 right;
    w3dcgb_i16 row;

    if (profile == 0) return;
    if (count > 29) count = 29;
    i = 0;
    while (i < count)
    {
        packed = profile[(__safe_index w3dcgb_u8)i];
        if (packed != 0xFF)
        {
            row = (w3dcgb_i16)((w3dcgb_i16)y + (w3dcgb_i16)y0 + (w3dcgb_i16)i);
            if ((row >= 0) && (row < WIRE3DCGB_SCREEN_H))
            {
                center = (w3dcgb_i16)((w3dcgb_i16)x + (w3dcgb_i16)(packed >> 4) - 7);
                half_width = (w3dcgb_u8)(packed & 15);
                left = (w3dcgb_i16)(center - (w3dcgb_i16)half_width - 2);
                right = (w3dcgb_i16)(center + (w3dcgb_i16)half_width + 2);
                if ((right >= 0) && (left < WIRE3DCGB_SCREEN_W))
                {
                    if (left < 0) left = 0;
                    if (right >= WIRE3DCGB_SCREEN_W) right = WIRE3DCGB_SCREEN_W - 1;
                    w3dcgb_mask_span_y = (w3dcgb_u8)row;
                    w3dcgb_mask_span_min_x = (w3dcgb_u8)left;
                    w3dcgb_mask_span_max_x = (w3dcgb_u8)right;
                    w3dcgb_stage_clear_span_asm();
                }
            }
        }
        i = (w3dcgb_u8)(i + 1);
    }
}
Wire3DCGB_EraseRect2D

일반 스테이징 영역에서 직사각형을 지웁니다.

사용 형식

c
void Wire3DCGB_EraseRect2D(w3dcgb_u8 x0, w3dcgb_u8 y0, w3dcgb_u8 x1, w3dcgb_u8 y1);

매개변수

x0

뷰포트 픽셀 단위의 작은 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

y0

뷰포트 픽셀 단위의 작은 쪽 Y 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

x1

뷰포트 픽셀 단위의 큰 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

y1

뷰포트 픽셀 단위의 큰 쪽 Y 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

직사각형의 끝점 순서를 맞추고 128×96에 맞춰 자릅니다. 높이 전체에 걸친 왼쪽 16픽셀 또는 24픽셀 띠는 뱅크 선택을 보존하는 ASM 지우기와 변경 표시를 사용합니다. 그 밖의 직사각형은 C 행 지우기를 사용하므로 호출자가 스테이징 영역에 맞는 WRAM 매핑을 제공해야 합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Colored panels expose triangle, span, rectangle and packed-silhouette erasure.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
    u8 y;
    u8 bank;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(8,y,40,y,1);
    for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(48,y,80,y,2);
    for(y=64;y<=72;y++) Wire3DCGB_DrawLine2DColor(88,y,120,y,3);
    // The C triangle/rectangle clearers access the stage through the current
    // WRAM window. Select bank 2 around them and restore the caller's bank.
    bank=sample_svbk; sample_svbk=2;
    Wire3DCGB_EraseTriangle2D(12,12,36,12,12,36);
    Wire3DCGB_EraseSpan2D(36,40,24);
    Wire3DCGB_EraseRect2D(56,16,72,32);
    Wire3DCGB_ErasePackedSilhouette2D(silhouette,5,-2,104,68);
    sample_svbk=bank;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

삼각형, 수평 스팬, 직사각형, 패킹된 실루엣으로 빨강·파랑·초록 패널에 검은 구멍을 만듭니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_erase.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_erase.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:145

kitaqgb/lib/wire3d_cgb.c:9146

c
void Wire3DCGB_EraseRect2D(w3dcgb_u8 x0, w3dcgb_u8 y0, w3dcgb_u8 x1, w3dcgb_u8 y1)
{
    w3dcgb_u8 t;
    w3dcgb_u8 y;

    if (x0 > x1)
    {
        t = x0;
        x0 = x1;
        x1 = t;
    }
    if (y0 > y1)
    {
        t = y0;
        y0 = y1;
        y1 = t;
    }
    if (x0 >= WIRE3DCGB_SCREEN_W) return;
    if (y0 >= WIRE3DCGB_SCREEN_H) return;
    if (x1 >= WIRE3DCGB_SCREEN_W) x1 = (w3dcgb_u8)(WIRE3DCGB_SCREEN_W - 1);
    if (y1 >= WIRE3DCGB_SCREEN_H) y1 = (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1);

    if ((x0 == 0) &&
        (x1 == 15) &&
        (y0 == 0) &&
        (y1 == (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1)))
    {
        w3dcgb_erase_left_guard16_asm();
        w3dcgb_mark_dirty_rect(0, 0, 15, (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1));
        return;
    }
    if ((x0 == 0) &&
        (x1 == 23) &&
        (y0 == 0) &&
        (y1 == (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1)))
    {
        w3dcgb_erase_left_guard24_asm();
        w3dcgb_mark_dirty_rect(0, 0, 23, (w3dcgb_u8)(WIRE3DCGB_SCREEN_H - 1));
        return;
    }

    y = y0;
    while (y <= y1)
    {
        w3dcgb_stage_clear_span(y, x0, x1);
        if (y == y1) break;
        y = (w3dcgb_u8)(y + 1);
    }
}
Wire3DCGB_EraseSpan2D

WRAM 뱅크 선택을 저장·복원하면서 수평 스팬을 지웁니다.

사용 형식

c
void Wire3DCGB_EraseSpan2D(w3dcgb_u8 y, w3dcgb_u8 x0, w3dcgb_u8 x1);

매개변수

y

지울 행의 픽셀 Y 좌표입니다.

x0

뷰포트 픽셀 단위의 작은 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

x1

뷰포트 픽셀 단위의 큰 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

X 끝점의 순서를 맞추고, 행이나 왼쪽 끝이 화면 밖이면 제외하며, 오른쪽 끝을 127로 제한합니다. 범위를 변경된 것으로 표시하고 WRAM 뱅크 2를 선택했다가 복원하는 ASM 스팬 지우기 루틴을 사용합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Colored panels expose triangle, span, rectangle and packed-silhouette erasure.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
    u8 y;
    u8 bank;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(8,y,40,y,1);
    for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(48,y,80,y,2);
    for(y=64;y<=72;y++) Wire3DCGB_DrawLine2DColor(88,y,120,y,3);
    // The C triangle/rectangle clearers access the stage through the current
    // WRAM window. Select bank 2 around them and restore the caller's bank.
    bank=sample_svbk; sample_svbk=2;
    Wire3DCGB_EraseTriangle2D(12,12,36,12,12,36);
    Wire3DCGB_EraseSpan2D(36,40,24);
    Wire3DCGB_EraseRect2D(56,16,72,32);
    Wire3DCGB_ErasePackedSilhouette2D(silhouette,5,-2,104,68);
    sample_svbk=bank;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

삼각형, 수평 스팬, 직사각형, 패킹된 실루엣으로 빨강·파랑·초록 패널에 검은 구멍을 만듭니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_erase.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_erase.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:134

kitaqgb/lib/wire3d_cgb.c:9123

c
void Wire3DCGB_EraseSpan2D(w3dcgb_u8 y, w3dcgb_u8 x0, w3dcgb_u8 x1)
{
    w3dcgb_u8 tx;

    if (x0 > x1)
    {
        tx = x0;
        x0 = x1;
        x1 = tx;
    }
    if ((y >= WIRE3DCGB_SCREEN_H) || (x0 >= WIRE3DCGB_SCREEN_W)) return;
    if (x1 >= WIRE3DCGB_SCREEN_W) x1 = WIRE3DCGB_SCREEN_W - 1;
    w3dcgb_mark_dirty_rect(x0, y, x1, y);
    w3dcgb_mask_span_y = y;
    w3dcgb_mask_span_min_x = x0;
    w3dcgb_mask_span_max_x = x1;
    w3dcgb_stage_clear_span_asm();
}
Wire3DCGB_EraseTriangle2D

일반 스테이징 영역의 두 색상 비트플레인에서 삼각형을 지웁니다.

사용 형식

c
void Wire3DCGB_EraseTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

cx

뷰포트 픽셀 단위의 정점 C X 좌표입니다.

cy

뷰포트 픽셀 단위의 정점 C Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

일반 C 스테이징 지우기 루틴으로 삼각형을 지웁니다. 잘린 스팬이 닿은 타일을 변경된 것으로 표시합니다. 호출자나 할당 과정에서 스테이징 영역의 WRAM 매핑을 제공해야 합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Colored panels expose triangle, span, rectangle and packed-silhouette erasure.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
    u8 y;
    u8 bank;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(8,y,40,y,1);
    for(y=8;y<=40;y++) Wire3DCGB_DrawLine2DColor(48,y,80,y,2);
    for(y=64;y<=72;y++) Wire3DCGB_DrawLine2DColor(88,y,120,y,3);
    // The C triangle/rectangle clearers access the stage through the current
    // WRAM window. Select bank 2 around them and restore the caller's bank.
    bank=sample_svbk; sample_svbk=2;
    Wire3DCGB_EraseTriangle2D(12,12,36,12,12,36);
    Wire3DCGB_EraseSpan2D(36,40,24);
    Wire3DCGB_EraseRect2D(56,16,72,32);
    Wire3DCGB_ErasePackedSilhouette2D(silhouette,5,-2,104,68);
    sample_svbk=bank;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

삼각형, 수평 스팬, 직사각형, 패킹된 실루엣으로 빨강·파랑·초록 패널에 검은 구멍을 만듭니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_erase.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_erase.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:133

kitaqgb/lib/wire3d_cgb.c:9113

c
void Wire3DCGB_EraseTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy)
{
    w3dcgb_clear_triangle(ax, ay, bx, by, cx, cy);
}
Wire3DCGB_FastMapBegin

16×12 FastMap 뷰포트의 타일 번호와 속성을 지웁니다.

사용 형식

c
void Wire3DCGB_FastMapBegin();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

FastMap을 준비 완료로 표시하고 16×12 뷰포트의 타일 번호와 속성을 지웁니다. 플러시가 행마다 32열을 복사하더라도 섀도 버퍼의 16~31열은 유지합니다. 전체 런타임과 안정적인 FastMap WRAM 매핑이 필요합니다. 하드웨어를 초기화하거나 맵을 업로드하지는 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
    u8 bank;
    wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_FastMapBegin();
    Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
    Wire3DCGB_FastMapFlush();
    Wire3DCGB_FastMapBeginTilesOnly();
    Wire3DCGB_FastMapCell(13,1,1,1);
    Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
    Wire3DCGB_FastMapRect(4,2,9,7,2,15);
    Wire3DCGB_FastMapCell(2,9,3,15);
    Wire3DCGB_FastMapFlushTilesOnly();
    sample_svbk=bank;result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 모서리, 큰 파란 직사각형, 한 타일 크기의 초록 테두리가 외곽선 셀을 보여 줍니다. 처음에 왼쪽 위에 있던 빨간 셀은 사라지며, 타일만 갱신하는 경로는 속성을 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:160

kitaqgb/lib/wire3d_cgb.c:10137

c
void Wire3DCGB_FastMapBegin()
{
    w3dcgb_fast_map_ready = 1;
    w3dcgb_fast_map_clear_rect(0, 0, 16, 12);
}
Wire3DCGB_FastMapBeginTilesOnly

16×12 FastMap 뷰포트의 타일 번호만 지웁니다.

사용 형식

c
void Wire3DCGB_FastMapBeginTilesOnly();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

FastMap을 준비 완료로 표시하고 16×12 뷰포트의 타일 번호만 지웁니다. 속성과 16~31열은 유지합니다. 전체 런타임과 의도한 WRAM 매핑이 필요하며, 하드웨어 초기화와 업로드는 별도로 수행합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
    u8 bank;
    wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_FastMapBegin();
    Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
    Wire3DCGB_FastMapFlush();
    Wire3DCGB_FastMapBeginTilesOnly();
    Wire3DCGB_FastMapCell(13,1,1,1);
    Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
    Wire3DCGB_FastMapRect(4,2,9,7,2,15);
    Wire3DCGB_FastMapCell(2,9,3,15);
    Wire3DCGB_FastMapFlushTilesOnly();
    sample_svbk=bank;result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 모서리, 큰 파란 직사각형, 한 타일 크기의 초록 테두리가 외곽선 셀을 보여 줍니다. 처음에 왼쪽 위에 있던 빨간 셀은 사라지며, 타일만 갱신하는 경로는 속성을 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:161

kitaqgb/lib/wire3d_cgb.c:10146

c
void Wire3DCGB_FastMapBeginTilesOnly()
{
    w3dcgb_fast_map_ready = 1;
    w3dcgb_fm_x0 = 0;
    w3dcgb_fm_y0 = 0;
    w3dcgb_fm_count_x = 16;
    w3dcgb_fm_count_y = 12;
    w3dcgb_fast_map_clear_rect_asm();
}
Wire3DCGB_FastMapCell

맵 셀 하나에 선택한 위·아래·왼쪽·오른쪽 외곽선을 추가합니다.

사용 형식

c
void Wire3DCGB_FastMapCell(w3dcgb_u8 tx, w3dcgb_u8 ty, w3dcgb_u8 color, w3dcgb_u8 mask);

매개변수

tx

타일 좌표 단위의 X 위치입니다.

ty

타일 좌표 단위의 Y 위치입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

mask

셀의 변 마스크입니다. 1=위, 2=아래, 4=왼쪽, 8=오른쪽입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

셀에 외곽선 변을 추가합니다. 비트 1/2/4/8은 위/아래/왼쪽/오른쪽입니다. 같은 색의 마스크는 합쳐지고 다른 색은 이전 마스크를 교체합니다. 마스크 0은 무시하며 색상 0은 MAIN, 3을 넘는 색상은 3으로 제한합니다. 안정적인 WRAM 매핑으로 16×12 섀도 버퍼에 적용합니다. 전체 런타임이 필요합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
    u8 bank;
    wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_FastMapBegin();
    Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
    Wire3DCGB_FastMapFlush();
    Wire3DCGB_FastMapBeginTilesOnly();
    Wire3DCGB_FastMapCell(13,1,1,1);
    Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
    Wire3DCGB_FastMapRect(4,2,9,7,2,15);
    Wire3DCGB_FastMapCell(2,9,3,15);
    Wire3DCGB_FastMapFlushTilesOnly();
    sample_svbk=bank;result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 모서리, 큰 파란 직사각형, 한 타일 크기의 초록 테두리가 외곽선 셀을 보여 줍니다. 처음에 왼쪽 위에 있던 빨간 셀은 사라지며, 타일만 갱신하는 경로는 속성을 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:162

kitaqgb/lib/wire3d_cgb.c:10160

c
void Wire3DCGB_FastMapCell(w3dcgb_u8 tx, w3dcgb_u8 ty, w3dcgb_u8 color, w3dcgb_u8 mask)
{
    w3dcgb_fast_map_or_cell((w3dcgb_i16)tx, (w3dcgb_i16)ty, color, mask);
}
Wire3DCGB_FastMapFlush

섀도 버퍼의 처음 12행 전체 타일 번호와 속성을 VRAM에 업로드합니다.

사용 형식

c
void Wire3DCGB_FastMapFlush();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

LCD가 켜져 있으면 새 VBlank를 기다린 뒤 맵의 처음 12행 전체 타일 번호와 속성을 맵 9800에 업로드합니다. LCD가 꺼져 있으면 즉시 진행합니다. 전체 런타임, 안정적인 WRAM 매핑, 두 번의 즉시 GDMA 전송을 모두 마칠 충분한 안전 구간이 필요합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
    u8 bank;
    wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_FastMapBegin();
    Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
    Wire3DCGB_FastMapFlush();
    Wire3DCGB_FastMapBeginTilesOnly();
    Wire3DCGB_FastMapCell(13,1,1,1);
    Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
    Wire3DCGB_FastMapRect(4,2,9,7,2,15);
    Wire3DCGB_FastMapCell(2,9,3,15);
    Wire3DCGB_FastMapFlushTilesOnly();
    sample_svbk=bank;result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 모서리, 큰 파란 직사각형, 한 타일 크기의 초록 테두리가 외곽선 셀을 보여 줍니다. 처음에 왼쪽 위에 있던 빨간 셀은 사라지며, 타일만 갱신하는 경로는 속성을 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:164

kitaqgb/lib/wire3d_cgb.c:10208

c
void Wire3DCGB_FastMapFlush()
{
    w3dcgb_wait_vblank_start();
    w3dcgb_fast_map_flush_gdma_asm();
}
Wire3DCGB_FastMapFlushTilesOnly

섀도 맵 처음 12행 전체에서 타일 번호만 업로드합니다.

사용 형식

c
void Wire3DCGB_FastMapFlushTilesOnly();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

LCD가 켜져 있으면 새 VBlank를 기다리고 처음 12행 전체의 타일 번호만 맵 9800에 업로드합니다. 속성은 유지됩니다. 전체 런타임, 안정적인 WRAM 매핑, 안전한 GDMA 구간이 필요합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
    u8 bank;
    wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_FastMapBegin();
    Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
    Wire3DCGB_FastMapFlush();
    Wire3DCGB_FastMapBeginTilesOnly();
    Wire3DCGB_FastMapCell(13,1,1,1);
    Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
    Wire3DCGB_FastMapRect(4,2,9,7,2,15);
    Wire3DCGB_FastMapCell(2,9,3,15);
    Wire3DCGB_FastMapFlushTilesOnly();
    sample_svbk=bank;result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 모서리, 큰 파란 직사각형, 한 타일 크기의 초록 테두리가 외곽선 셀을 보여 줍니다. 처음에 왼쪽 위에 있던 빨간 셀은 사라지며, 타일만 갱신하는 경로는 속성을 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:165

kitaqgb/lib/wire3d_cgb.c:10217

c
void Wire3DCGB_FastMapFlushTilesOnly()
{
    w3dcgb_wait_vblank_start();
    w3dcgb_fast_map_flush_tiles_gdma_asm();
}
Wire3DCGB_FastMapRect

타일 좌표 직사각형 둘레에 선택한 외곽선 변을 배치합니다.

사용 형식

c
void Wire3DCGB_FastMapRect(w3dcgb_u8 tx0, w3dcgb_u8 ty0, w3dcgb_u8 tx1, w3dcgb_u8 ty1, w3dcgb_u8 color, w3dcgb_u8 sides);

매개변수

tx0

타일 좌표 단위의 X 위치입니다.

ty0

타일 좌표 단위의 Y 위치입니다.

tx1

타일 좌표 단위의 X 위치입니다.

ty1

타일 좌표 단위의 Y 위치입니다.

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

sides

직사각형 변 마스크입니다. 1=위, 2=아래, 4=왼쪽, 8=오른쪽입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

바이트 타일 좌표의 순서를 맞추고 16×12에 맞춰 자른 뒤 선택한 테두리 셀을 교체합니다. 변 비트 1/2/4/8은 위/아래/왼쪽/오른쪽입니다. 색상 0은 MAIN이며 3을 넘는 값은 3으로 제한합니다. 속성과 내부 셀은 유지합니다. 모서리를 구분하려면 행과 열을 각각 두 개 이상 사용하세요. 겹친 모서리는 순서대로 덮어씁니다. 전체 런타임과 안정적인 WRAM 매핑이 필요합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
    u8 bank;
    wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_FastMapBegin();
    Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
    Wire3DCGB_FastMapFlush();
    Wire3DCGB_FastMapBeginTilesOnly();
    Wire3DCGB_FastMapCell(13,1,1,1);
    Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
    Wire3DCGB_FastMapRect(4,2,9,7,2,15);
    Wire3DCGB_FastMapCell(2,9,3,15);
    Wire3DCGB_FastMapFlushTilesOnly();
    sample_svbk=bank;result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 모서리, 큰 파란 직사각형, 한 타일 크기의 초록 테두리가 외곽선 셀을 보여 줍니다. 처음에 왼쪽 위에 있던 빨간 셀은 사라지며, 타일만 갱신하는 경로는 속성을 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:163

kitaqgb/lib/wire3d_cgb.c:10170

c
void Wire3DCGB_FastMapRect(w3dcgb_u8 tx0, w3dcgb_u8 ty0, w3dcgb_u8 tx1, w3dcgb_u8 ty1, w3dcgb_u8 color, w3dcgb_u8 sides)
{
    w3dcgb_u8 t;

    if (tx0 > tx1)
    {
        t = tx0;
        tx0 = tx1;
        tx1 = t;
    }
    if (ty0 > ty1)
    {
        t = ty0;
        ty0 = ty1;
        ty1 = t;
    }
    if (tx0 >= 16) return;
    if (ty0 >= 12) return;
    if (tx1 >= 16) tx1 = 15;
    if (ty1 >= 12) ty1 = 11;
    if (color == 0) color = WIRE3DCGB_COLOR_MAIN;
    if (color > 3) color = 3;

    w3dcgb_fm_x0 = tx0;
    w3dcgb_fm_y0 = ty0;
    w3dcgb_fm_x1 = tx1;
    w3dcgb_fm_y1 = ty1;
    w3dcgb_fm_count_x = (w3dcgb_u8)(tx1 - tx0 + 1);
    w3dcgb_fm_count_y = (w3dcgb_u8)(ty1 - ty0 + 1);
    w3dcgb_fm_tile_base = (w3dcgb_u8)(W3DCGB_FAST_TILE_BASE + ((color - 1) << 4));
    w3dcgb_fm_sides = (w3dcgb_u8)(sides & 15);
    w3dcgb_fast_map_rect_asm();
}
Wire3DCGB_GetFullScreenOverflow

전체 화면 그리기에서 좌표 오류 또는 타일 할당 공간 소진을 보고합니다.

사용 형식

c
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow();

반환값

오류가 없으면 0, 할당 공간 소진이나 유효하지 않은 좌표가 발생한 뒤에는 1입니다.

사용 조건과 제한

전체 화면 프레임의 오류 플래그를 반환합니다. 고속 선 경로에서 타일 할당 공간이 소진되거나 좌표가 유효하지 않으면 설정됩니다. 한 번 설정되면 BeginFrame이 재설정할 때까지 이후 고속 경로의 픽셀 쓰기를 억제합니다. 일반적인 하드웨어 상태 플래그가 아니며, 조회 함수에는 전체 런타임이 필요합니다.

전체 화면에서는 가림이나 오버플로로 픽셀 쓰기를 억제하기 전에 타일을 할당합니다. 할당된 타일이 검게 남을 수 있으며, 오류 후에도 그리기를 계속하면 타일 수가 늘어날 수 있습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// One point per tile exposes the 127-tile limit without relying on text alone.
#include "wire_cgb_example.h"
void main() {
    u8 i;
    wire_results_clear();
    Wire3DCGB_InitFullScreen(); wire_colors();
    Wire3DCGB_BeginFrame(); Wire3DCGB_SetLineColor(3);
    for(i=0;i<128;i++) Wire3DCGB_DrawPoint2D((i%20)*8+4,(i/20)*8+4);
    result[0]=Wire3DCGB_GetFullScreenTileCount();
    result[1]=Wire3DCGB_GetFullScreenOverflow();
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 점 127개가 서로 다른 타일을 차지합니다. 128번째 할당을 시도하면 개수는 127로 유지되고 overflow가 1이 됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_capacity.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_capacity.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:194

kitaqgb/lib/wire3d_cgb.c:9965

c
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow()
{
    return w3dcgb_full_overflow;
}
Wire3DCGB_GetFullScreenTileCount

현재 프레임에서 할당된 전체 화면 타일 수를 반환합니다.

사용 형식

c
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount();

반환값

할당된 타일 수로, 범위는 0~127입니다.

사용 조건과 제한

현재 전체 화면 모드의 할당 개수를 반환합니다. 최대 127이며 바이트 수나 보이는 픽셀 또는 0이 아닌 픽셀의 수가 아닙니다. 전체 런타임 전용입니다.

전체 화면에서는 가림이나 오버플로로 픽셀 쓰기를 억제하기 전에 타일을 할당합니다. 할당된 타일이 검게 남을 수 있으며, 오류 후에도 그리기를 계속하면 타일 수가 늘어날 수 있습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// One point per tile exposes the 127-tile limit without relying on text alone.
#include "wire_cgb_example.h"
void main() {
    u8 i;
    wire_results_clear();
    Wire3DCGB_InitFullScreen(); wire_colors();
    Wire3DCGB_BeginFrame(); Wire3DCGB_SetLineColor(3);
    for(i=0;i<128;i++) Wire3DCGB_DrawPoint2D((i%20)*8+4,(i/20)*8+4);
    result[0]=Wire3DCGB_GetFullScreenTileCount();
    result[1]=Wire3DCGB_GetFullScreenOverflow();
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 점 127개가 서로 다른 타일을 차지합니다. 128번째 할당을 시도하면 개수는 127로 유지되고 overflow가 1이 됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_capacity.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_capacity.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:193

kitaqgb/lib/wire3d_cgb.c:9956

c
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount()
{
    return w3dcgb_full_tile_count;
}
Wire3DCGB_GetLineColor

현재 저장된 선 색상 인덱스를 읽습니다.

사용 형식

c
w3dcgb_u8 Wire3DCGB_GetLineColor();

반환값

현재 저장된 선 색상 값입니다.

사용 조건과 제한

그리기 상태를 바꾸지 않고 현재 저장된 2비트 선 색상을 반환합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:120

kitaqgb/lib/wire3d_cgb.c:1147

c
w3dcgb_u8 Wire3DCGB_GetLineColor()
{
    return w3dcgb_line_color;
}
Wire3DCGB_Init

CGB 128×96 픽셀 렌더러를 초기화합니다.

사용 형식

c
void Wire3DCGB_Init();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

CGB 전용 128×96 렌더러를 초기화합니다. 배속을 켜고 VBlank에서 LCD를 끈 뒤, 두 타일 뱅크를 지우고 HUD/생성 타일을 불러와 열 우선 순서의 16×12 뷰포트를 설정합니다. 초기 상태는 빈 타일 뱅크 1, 스크롤 0, 기본 BG 팔레트, 색상 2, 카메라 0입니다. 큐를 재설정하고 뱅크 2의 스테이징 영역을 지웁니다. 그리기 전에 BeginFrame을 호출해 가림 상태를 초기화하세요. 초기화는 LCD·타일·맵 상태를 전역적으로 바꿉니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:113

kitaqgb/lib/wire3d_cgb.c:7994

c
void Wire3DCGB_Init()
{
    w3dcgb_u8 row;
    w3dcgb_u8 col;
    w3dcgb_u8 tid;
    w3dcgb_u8 tile_index;
    w3dcgb_u16 off;

    w3dcgb_full_mode = 0;
    w3dcgb_atomic_maps = 0;
    Wire3DCGB_EnableDoubleSpeed();
    w3dcgb_wait_vblank_start();
    w3dcgb_reg_lcdc = 0;

    w3dcgb_clear_vram_asm();
    w3dcgb_load_hud_tiles();
#ifndef WIRE3DCGB_MINIMAL_RUNTIME
    w3dcgb_load_fast_map_tiles();
    w3dcgb_load_fast_stamp_tiles();
#endif
    w3dcgb_fill_bg_map_asm();
    w3dcgb_fill_attr_map_asm();

    row = 0;
    while (row < W3DCGB_TILE_H)
    {
        off = (w3dcgb_u16)((w3dcgb_u16)row << 5);
        tile_index = row;
        col = 0;
        while (col < W3DCGB_TILE_W)
        {
            if (tile_index < 112) tid = (w3dcgb_u8)(0x90 + tile_index);
            else tid = (w3dcgb_u8)(tile_index - 112);
            w3dcgb_bg_map_9800[(w3dcgb_u16)(off + (w3dcgb_u16)col)] = tid;
            tile_index = (w3dcgb_u8)(tile_index + W3DCGB_TILE_H);
            col = (w3dcgb_u8)(col + 1);
        }
        row = (w3dcgb_u8)(row + 1);
    }

    w3dcgb_select_blank_render_bank_asm();

    w3dcgb_reg_scx = 0;
    w3dcgb_reg_scy = 0;
    w3dcgb_reg_bgp = 0xB4;
    Wire3DCGB_SetPaletteRGB15(
        WIRE3DCGB_RGB15(0, 0, 2),
        WIRE3DCGB_RGB15(10, 20, 31),
        WIRE3DCGB_RGB15(31, 31, 31),
        WIRE3DCGB_RGB15(31, 14, 4));
    w3dcgb_line_color = WIRE3DCGB_COLOR_DEFAULT;
    w3dcgb_reg_lcdc = 0x81;
    w3dcgb_bgq_count = 0;
    w3dcgb_dirty_count = 0;
    w3dcgb_prev_dirty_count = 0;
    w3dcgb_dirty_min_tile = 0xFF;
    w3dcgb_dirty_max_tile = 0;
    // Both back banks may contain generated fast-map/stamp tiles. Refresh
    // the whole pixel viewport on their first sparse use, including empty rows.
    w3dcgb_prev_dirty_min_tile = 0;
    w3dcgb_prev_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
    w3dcgb_older_dirty_min_tile = 0;
    w3dcgb_older_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
    w3dcgb_display_tile_bank = 1;
    w3dcgb_pending_tile_bank = 1;

    Wire3DCGB_SetCamera((w3dcgb_i16)0, (w3dcgb_i16)0, (w3dcgb_i16)0, 0, 0, 0);
    w3dcgb_clear_stage_asm();
}
Wire3DCGB_InitFastMapLite

미리 계산된 외곽선 타일로 FastMap 렌더링을 초기화합니다.

사용 형식

c
void Wire3DCGB_InitFastMapLite();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

HUD와 미리 계산된 외곽선 타일 48개를 사용하는 CGB 타일 맵 렌더러를 초기화합니다. 타일 VRAM과 맵을 지우고 스크롤·팔레트·카메라를 재설정한 뒤 일반 모드를 선택합니다. 일반 픽셀 뷰포트의 맵 배치와 생성된 큐브 스탬프는 설정하지 않으므로 이 모드에서는 FastMap API를 사용하세요. 뱅크 2의 스테이징 영역을 지우고 FastMap 준비를 대기 상태로 표시합니다. 전체 런타임 빌드가 필요합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// FastMap uses precomputed outline tiles rather than a pixel stage upload.
#include "wire_cgb_example.h"
void main() {
    u8 bank;
    wire_results_clear(); Wire3DCGB_InitFastMapLite(); wire_colors();
    bank=sample_svbk;sample_svbk=2;
    Wire3DCGB_FastMapBegin();
    Wire3DCGB_FastMapCell(1,1,1,15); // This first red square must disappear.
    Wire3DCGB_FastMapFlush();
    Wire3DCGB_FastMapBeginTilesOnly();
    Wire3DCGB_FastMapCell(13,1,1,1);
    Wire3DCGB_FastMapCell(13,1,1,4); // Same-color top and left sides combine.
    Wire3DCGB_FastMapRect(4,2,9,7,2,15);
    Wire3DCGB_FastMapCell(2,9,3,15);
    Wire3DCGB_FastMapFlushTilesOnly();
    sample_svbk=bank;result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 모서리, 큰 파란 직사각형, 한 타일 크기의 초록 테두리가 외곽선 셀을 보여 줍니다. 처음에 왼쪽 위에 있던 빨간 셀은 사라지며, 타일만 갱신하는 경로는 속성을 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_fastmap.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_fastmap.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:115

kitaqgb/lib/wire3d_cgb.c:8108

c
void Wire3DCGB_InitFastMapLite()
{
    w3dcgb_atomic_maps = 0;
    w3dcgb_full_mode = 0;
    Wire3DCGB_EnableDoubleSpeed();
    w3dcgb_wait_vblank_start();
    w3dcgb_reg_lcdc = 0;

    w3dcgb_clear_vram_asm();
    w3dcgb_load_hud_tiles();
    w3dcgb_load_fast_map_tiles_lite_asm();
    w3dcgb_fill_bg_map_asm();
    w3dcgb_fill_attr_map_asm();

    w3dcgb_reg_scx = 0;
    w3dcgb_reg_scy = 0;
    w3dcgb_reg_bgp = 0xB4;
    Wire3DCGB_SetPaletteRGB15(
        WIRE3DCGB_RGB15(0, 0, 2),
        WIRE3DCGB_RGB15(10, 20, 31),
        WIRE3DCGB_RGB15(31, 31, 31),
        WIRE3DCGB_RGB15(31, 14, 4));
    w3dcgb_line_color = WIRE3DCGB_COLOR_DEFAULT;
    w3dcgb_reg_lcdc = 0x81;
    w3dcgb_bgq_count = 0;
    w3dcgb_dirty_count = 0;
    w3dcgb_prev_dirty_count = 0;
    w3dcgb_dirty_min_tile = 0xFF;
    w3dcgb_dirty_max_tile = 0;
    w3dcgb_prev_dirty_min_tile = 0xFF;
    w3dcgb_prev_dirty_max_tile = 0;
    w3dcgb_fast_map_ready = 0;
    w3dcgb_display_tile_bank = 0;
    w3dcgb_pending_tile_bank = 0;

    Wire3DCGB_SetCamera((w3dcgb_i16)0, (w3dcgb_i16)0, (w3dcgb_i16)0, 0, 0, 0);
    w3dcgb_clear_stage_asm();
}
Wire3DCGB_InitFullScreen

픽셀을 그릴 때 타일을 할당하는 160×144 렌더러를 초기화합니다.

사용 형식

c
void Wire3DCGB_InitFullScreen();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

CGB 전용 160×144 타일 할당기를 초기화합니다. 두 타일 뱅크와 맵 9800을 지우고 스크롤·팔레트·색상·카메라를 설정한 뒤, 타일 수와 조회/스팬 상태를 재설정하고 부호 없는 BG 타일 주소 지정을 켭니다. HUD 타일은 불러오지 않습니다. 고정 WRAM 조회 테이블, 데이터 영역, 주소 목록을 위한 공간을 확보하고 전체 화면 렌더링 동안 같은 WRAM 뱅크를 매핑해 두세요.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// A large frame demonstrates the 160x144 renderer and its allocated-tile count.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear();
    Wire3DCGB_InitFullScreen(); wire_colors();
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,151,8);
    Wire3DCGB_DrawLine2D(8,8,8,135);
    Wire3DCGB_DrawLine2DColor(8,135,151,135,2);
    Wire3DCGB_DrawLine2DColor(151,8,151,135,3);
    result[0]=Wire3DCGB_GetFullScreenTileCount();
    result[1]=Wire3DCGB_GetFullScreenOverflow();
    Wire3DCGB_EndFrameFast();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

큰 테두리가 (8,8)..(151,135)에 걸쳐 표시됩니다. 위쪽과 왼쪽은 빨간색, 아래쪽은 파란색, 오른쪽은 초록색입니다. 타일 64개를 사용하며 overflow는 0입니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_full.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_full.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:114

kitaqgb/lib/wire3d_cgb.c:8070

c
void Wire3DCGB_InitFullScreen()
{
    w3dcgb_atomic_maps = 0;
    Wire3DCGB_EnableDoubleSpeed();
    w3dcgb_wait_vblank_start();
    w3dcgb_reg_lcdc = 0;

    w3dcgb_clear_vram_asm();
    w3dcgb_full_clear_map_asm();
    w3dcgb_reg_scx = 0;
    w3dcgb_reg_scy = 0;
    w3dcgb_reg_bgp = 0xB4;
    Wire3DCGB_SetPaletteRGB15(
        WIRE3DCGB_RGB15(0, 0, 2),
        WIRE3DCGB_RGB15(10, 20, 31),
        WIRE3DCGB_RGB15(31, 31, 31),
        WIRE3DCGB_RGB15(31, 14, 4));
    w3dcgb_line_color = WIRE3DCGB_COLOR_DEFAULT;
    w3dcgb_bgq_count = 0;
    w3dcgb_dirty_count = 0;
    w3dcgb_prev_dirty_count = 0;
    w3dcgb_display_tile_bank = 0;
    w3dcgb_pending_tile_bank = 0;
    w3dcgb_full_tile_count = 0;
    w3dcgb_full_prev_tile_count = 0;
    w3dcgb_full_overflow = 0;
    w3dcgb_full_mode = 1;

    Wire3DCGB_SetCamera((w3dcgb_i16)0, (w3dcgb_i16)0, (w3dcgb_i16)0, 0, 0, 0);
    w3dcgb_full_begin_asm();
    w3dcgb_reg_lcdc = 0x91;
}
Wire3DCGB_InvalidateFrameHistory

현재 및 이전 두 전송 범위를 일반 모드의 전체 192타일로 넓힙니다.

사용 형식

c
void Wire3DCGB_InvalidateFrameHistory();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

현재 및 이전 두 부분 전송 범위를 일반 모드의 전체 192타일로 표시합니다. 픽셀 데이터는 지우지 않으며, 이후 업로드는 예전 범위에 의존할 수 없습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:142

kitaqgb/lib/wire3d_cgb.c:9712

c
void Wire3DCGB_InvalidateFrameHistory()
{
    w3dcgb_dirty_min_tile = 0;
    w3dcgb_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
    w3dcgb_prev_dirty_min_tile = 0;
    w3dcgb_prev_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
    w3dcgb_older_dirty_min_tile = 0;
    w3dcgb_older_dirty_max_tile = (w3dcgb_u8)(WIRE3DCGB_TILE_COUNT - 1);
}
Wire3DCGB_MarkDirtyRect2D

나중에 업로드해야 할 범위에 픽셀 직사각형을 추가합니다.

사용 형식

c
void Wire3DCGB_MarkDirtyRect2D(w3dcgb_u8 min_x, w3dcgb_u8 min_y, w3dcgb_u8 max_x, w3dcgb_u8 max_y);

매개변수

min_x

뷰포트 픽셀 단위의 작은 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

min_y

뷰포트 픽셀 단위의 작은 쪽 Y 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

max_x

뷰포트 픽셀 단위의 큰 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

max_y

뷰포트 픽셀 단위의 큰 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

끝점을 포함하는 픽셀 직사각형을 그리지 않고 나중에 전송할 영역으로 표시합니다. 끝점은 순서대로 지정하세요. 127/95를 넘는 값은 경계로 제한됩니다. 전체 화면 타일 할당기가 아닌 128×96 타일을 추적합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Reuse both VRAM banks and remove old geometry while presenting sparse frames.
#include "wire_cgb_example.h"
void main() {
    wire_results_clear(); Wire3DCGB_Init();
    Wire3DCGB_ClearFrameTiles();
    Wire3DCGB_EnableAtomicMaps(); wire_colors();
    // First frame: red on the left. Fast begin invalidates both bank histories.
    Wire3DCGB_BeginFrameFast(); wire_frame(8,8,32,32,1);
    Wire3DCGB_EndFrameFast();
    // Second frame: blue in the middle, with the old red frame removed.
    Wire3DCGB_BeginFrameSparse(); wire_frame(40,40,64,64,2);
    Wire3DCGB_EndFrameSparse();
    // Third frame: explicitly clearing a stage discards its first green point.
    Wire3DCGB_BeginFrameSparse();
    Wire3DCGB_SetLineColor(3); Wire3DCGB_DrawPoint2D(4,4);
    Wire3DCGB_ClearSparseStageFast();
    // The final image contains only this green frame on the right.
    wire_frame(80,8,112,32,3);
    Wire3DCGB_MarkDirtyRect2D(80,8,112,32);
    Wire3DCGB_InvalidateFrameHistory();
    Wire3DCGB_EndFrameSparseNow();
    result[0]=Wire3DCGB_GetLineColor();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

먼저 그린 빨간 테두리와 파란 테두리가 사라지고 (80,8)..(112,32)의 마지막 초록 테두리만 남습니다. 부분 업로드와 이력 관리의 동작을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_sparse.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_sparse.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:126

kitaqgb/lib/wire3d_cgb.c:1288

c
void Wire3DCGB_MarkDirtyRect2D(w3dcgb_u8 min_x, w3dcgb_u8 min_y, w3dcgb_u8 max_x, w3dcgb_u8 max_y)
{
    w3dcgb_mark_dirty_rect(min_x, min_y, max_x, max_y);
}
Wire3DCGB_MarkPackedSilhouette2D

행별로 패킹된 실루엣을 128×96 가림 비트맵에 등록합니다.

사용 형식

c
void Wire3DCGB_MarkPackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count, w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);

매개변수

profile

행마다 1바이트를 사용하는 실루엣 배열입니다. 0xFF는 해당 행을 건너뜁니다.

count

제공한 배열 항목 수입니다. 실제 처리 상한은 해당 연산의 설명을 참조하세요.

y0

중심 Y에서 실루엣 첫 행까지의 부호 있는 오프셋입니다.

x

뷰포트 픽셀 단위의 중심 X 좌표입니다.

y

뷰포트 픽셀 단위의 중심 Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

128×96 비트맵 마스크에 실루엣을 최대 29행 등록합니다. 패킹된 각 바이트의 상위 니블은 중심 오프셋(nibble−7), 하위 니블은 반폭이며, 0xFF는 해당 행을 건너뜁니다. 행을 y+y0+i에 놓고 스팬을 2픽셀 확장한 뒤 뷰포트에 맞춰 자릅니다. profile에는 읽기 가능한 바이트가 count개 있어야 하며 null은 무시합니다. 전체 화면 스팬을 갱신하거나 가림 검사를 켜지는 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Red/blue scanlines stop inside masks; green outlines identify the triangle.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
    u8 y;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    // Clearing this first test mask must leave the upper-left scanline intact.
    Wire3DCGB_MarkTriangle2D(8,8,16,8,8,16);
    Wire3DCGB_ClearOcclusionMask();
    Wire3DCGB_MarkTriangle2D(32,16,64,16,32,48);
    Wire3DCGB_MarkPackedSilhouette2D(silhouette,5,-2,104,32);
    Wire3DCGB_SetOcclusionActive(1);
    for(y=8;y<=56;y=y+4) Wire3DCGB_DrawLine2DColor(8,y,88,y,1);
    for(y=28;y<=36;y++) Wire3DCGB_DrawLine2DColor(92,y,120,y,2);
    Wire3DCGB_SetOcclusionActive(0);
    Wire3DCGB_DrawLine2DColor(32,16,64,16,3);
    Wire3DCGB_DrawLine2DColor(64,16,32,48,3);
    Wire3DCGB_DrawLine2DColor(32,48,32,16,3);
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

삼각형이 빨간 주사선의 가운데를 가리고, 패킹된 실루엣이 파란 선을 가립니다. 초록 외곽선으로 가림 영역의 위치를 표시합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_mask.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_mask.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:151

kitaqgb/lib/wire3d_cgb.c:1991

c
void Wire3DCGB_MarkPackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count,
                                     w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y)
{
    w3dcgb_u8 i;
    w3dcgb_u8 packed;
    w3dcgb_u8 half_width;
    w3dcgb_i16 center;
    w3dcgb_i16 left;
    w3dcgb_i16 right;
    w3dcgb_i16 row;

    if (profile == 0) return;
    if (count > 29) count = 29;
    i = 0;
    while (i < count)
    {
        packed = profile[(__safe_index w3dcgb_u8)i];
        if (packed != 0xFF)
        {
            row = (w3dcgb_i16)((w3dcgb_i16)y + (w3dcgb_i16)y0 + (w3dcgb_i16)i);
            if ((row >= 0) && (row < WIRE3DCGB_SCREEN_H))
            {
                center = (w3dcgb_i16)((w3dcgb_i16)x + (w3dcgb_i16)(packed >> 4) - 7);
                half_width = (w3dcgb_u8)(packed & 15);
                /* Two-pixel guard covers rasterized endpoints at 22.5-degree views. */
                left = (w3dcgb_i16)(center - (w3dcgb_i16)half_width - 2);
                right = (w3dcgb_i16)(center + (w3dcgb_i16)half_width + 2);
                if ((right >= 0) && (left < WIRE3DCGB_SCREEN_W))
                {
                    if (left < 0) left = 0;
                    if (right >= WIRE3DCGB_SCREEN_W) right = WIRE3DCGB_SCREEN_W - 1;
                    w3dcgb_mask_span_y = (w3dcgb_u8)row;
                    w3dcgb_mask_span_min_x = (w3dcgb_u8)left;
                    w3dcgb_mask_span_max_x = (w3dcgb_u8)right;
                    w3dcgb_mask_set_span_asm();
                }
            }
        }
        i = (w3dcgb_u8)(i + 1);
    }
}
Wire3DCGB_MarkTriangle2D

이후에 그리는 선을 가릴 수 있는 영역으로 삼각형을 등록합니다.

사용 형식

c
void Wire3DCGB_MarkTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

cx

뷰포트 픽셀 단위의 정점 C X 좌표입니다.

cy

뷰포트 픽셀 단위의 정점 C Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

픽셀을 그리거나 가림 검사를 켜지 않고 화면 좌표의 삼각형을 마스크에 등록합니다. 정점은 선택한 뷰포트 안에 있어야 합니다. 사용 중인 ASM은 X 방향으로 1픽셀 여유를 추가하며, 범위를 128×96 모드에서는 0~127, 160×144 모드에서는 0~159로 제한합니다. 임의의 화면 밖 삼각형을 잘라 주는 함수는 아닙니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Red/blue scanlines stop inside masks; green outlines identify the triangle.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
    u8 y;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    // Clearing this first test mask must leave the upper-left scanline intact.
    Wire3DCGB_MarkTriangle2D(8,8,16,8,8,16);
    Wire3DCGB_ClearOcclusionMask();
    Wire3DCGB_MarkTriangle2D(32,16,64,16,32,48);
    Wire3DCGB_MarkPackedSilhouette2D(silhouette,5,-2,104,32);
    Wire3DCGB_SetOcclusionActive(1);
    for(y=8;y<=56;y=y+4) Wire3DCGB_DrawLine2DColor(8,y,88,y,1);
    for(y=28;y<=36;y++) Wire3DCGB_DrawLine2DColor(92,y,120,y,2);
    Wire3DCGB_SetOcclusionActive(0);
    Wire3DCGB_DrawLine2DColor(32,16,64,16,3);
    Wire3DCGB_DrawLine2DColor(64,16,32,48,3);
    Wire3DCGB_DrawLine2DColor(32,48,32,16,3);
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

삼각형이 빨간 주사선의 가운데를 가리고, 패킹된 실루엣이 파란 선을 가립니다. 초록 외곽선으로 가림 영역의 위치를 표시합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_mask.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_mask.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:150

kitaqgb/lib/wire3d_cgb.c:1980

c
void Wire3DCGB_MarkTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy)
{
    w3dcgb_mark_triangle(ax, ay, bx, by, cx, cy);
}
Wire3DCGB_ProjectAxis48

초점 거리 48로 투영 오프셋 하나를 근사합니다.

사용 형식

c
w3dcgb_i16 Wire3DCGB_ProjectAxis48(w3dcgb_i16 value, w3dcgb_i16 z);

매개변수

value

투영할 부호 있는 16비트 성분입니다.

z

크기를 선택하거나 투영을 계산하는 데 사용하는 깊이입니다.

반환값

근사 계산한 부호 있는 16비트 투영 오프셋입니다.

사용 조건과 제한

카메라나 화면 중심 오프셋 없이 value*48/z를 근사합니다. 음수 또는 매우 작은 Z는 4로 처리합니다. Z가 255보다 크면 깊이가 한 바이트에 들어갈 때까지 깊이와 크기를 함께 오른쪽으로 시프트한 뒤 크기를 최대 160으로 제한합니다. 부호 있는 오프셋을 반환하며, 근거리나 원거리 깊이를 거부하지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Preprojected edge arrays, a clipped square, a tiny marker and a projectile.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom s8 vx8[4]={-8,8,8,-8};
__prg_rom s8 vy8[4]={-8,-8,8,8};
__prg_rom s16 vx16[4]={-12,12,12,-12};
__prg_rom s16 vy16[4]={-8,-8,8,8};
__prg_rom u8 mask[1]={5};
Wire3DCGB_Model shape;
void main() {
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    shape.vertices=0;shape.edges=edges;shape.faces=0;shape.edge_faces=0;
    shape.vertex_count=4;shape.edge_count=4;shape.face_count=0;shape.flags=0;
    Wire3DCGB_SetLineColor(2);
    Wire3DCGB_DrawMaskedModel2D(&shape,vx8,vy8,mask,24,24,1);
    Wire3DCGB_DrawEdgeList2D(edges,4,vx8,vy8,64,24,2);
    Wire3DCGB_DrawEdgeListClipped2D(edges,4,vx16,vy16,4,4,64,3);
    Wire3DCGB_DrawTinyModel2D(104,24,16,3);
    result[0]=Wire3DCGB_ProjectAxis48(48,96);
    result[1]=Wire3DCGB_ProjectAxis48(-48,96);
    Wire3DCGB_DrawFastProjectile(96,64,64,0,1);
    result[2]=Wire3DCGB_GetLineColor();
    Wire3DCGB_EndFrame();result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨간 수평 모서리 두 개, 파란 정사각형, 잘린 초록 테두리, 초록 6픽셀 마커, 빨간 발사체로 목록 형식을 비교합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_lists.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_lists.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:141

kitaqgb/lib/wire3d_cgb.c:9702

c
w3dcgb_i16 Wire3DCGB_ProjectAxis48(w3dcgb_i16 value, w3dcgb_i16 z)
{
    w3dcgb_projection_value = value;
    w3dcgb_projection_z = z;
    w3dcgb_project_axis48_asm();
    return w3dcgb_projection_result;
}
Wire3DCGB_ProjectPoint

월드 좌표의 점을 카메라를 통해 128×96 뷰포트로 투영합니다.

사용 형식

c
w3dcgb_u8 Wire3DCGB_ProjectPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);

매개변수

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

sx

투영된 X 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

sy

투영된 Y 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

반환값

투영에 성공하면 1, 깊이 검사에서 제외되면 0을 반환합니다.

사용 조건과 제한

월드 좌표의 점을 현재 카메라를 통해 128×96 뷰포트로 투영합니다. 깊이 검사에서 제외되면 0을 반환하고 출력을 유지합니다. 성공하면 뷰포트 범위로 제한한 바이트 좌표를 기록합니다. 쓰기 가능한 유효 포인터가 필요합니다. 160×144 전체 화면용 투영기가 아닙니다. MINIMAL_RUNTIME 빌드에는 없습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:169

kitaqgb/lib/wire3d_cgb.c:589

c
w3dcgb_u8 Wire3DCGB_ProjectPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy)
{
    return w3dcgb_project_world(x, y, z, sx, sy);
}
Wire3DCGB_ProjectPointNoRotation

카메라 위치를 뺀 뒤 카메라 회전 없이 점을 투영합니다.

사용 형식

c
w3dcgb_u8 Wire3DCGB_ProjectPointNoRotation(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);

매개변수

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

sx

투영된 X 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

sy

투영된 Y 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

반환값

투영에 성공하면 1, 깊이 검사에서 제외되면 0을 반환합니다.

사용 조건과 제한

카메라의 피치·요·롤이 항상 0인 게임을 위한 빠른 경로입니다. 카메라 위치를 뺀 뒤 모든 카메라 각도를 무시하고 128×96에 투영합니다. 피치·요·롤이 0일 때 사용하세요. 깊이가 유효하지 않으면 출력 포인터가 가리키는 값을 바꾸지 않고 거부하며, 성공한 좌표는 뷰포트 범위로 제한합니다. MINIMAL_RUNTIME 빌드에는 없습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:171

선언 주석 원문
Fast path for games whose camera pitch, yaw, and roll stay at zero.

kitaqgb/lib/wire3d_cgb.c:598

c
w3dcgb_u8 Wire3DCGB_ProjectPointNoRotation(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z,
                                            w3dcgb_u8* sx, w3dcgb_u8* sy)
{
    return w3dcgb_project_camera_space((w3dcgb_i16)(x - w3dcgb_cam_x),
                                        (w3dcgb_i16)(y - w3dcgb_cam_y),
                                        (w3dcgb_i16)(z - w3dcgb_cam_z), sx, sy);
}
Wire3DCGB_PutBgTile

EndFrame에서 처리할 배경 타일 번호 변경을 큐에 넣습니다.

사용 형식

c
void Wire3DCGB_PutBgTile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 tile);

매개변수

x

32×32 배경 맵의 X 타일 좌표입니다.

y

32×32 배경 맵의 Y 타일 좌표입니다.

tile

배경 셀의 8비트 타일 번호입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

32×32 BG 맵의 타일 번호 쓰기를 큐에 넣습니다. 유효하지 않은 좌표와 대기 중인 쓰기가 이미 48개일 때의 요청은 무시합니다. EndFrame이 이 전용 큐를 비우며, atomic-map 모드에서는 두 BG 맵에 모두 씁니다. 속성은 큐에 넣지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:188

kitaqgb/lib/wire3d_cgb.c:1067

c
void Wire3DCGB_PutBgTile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 tile)
{
    if (x >= 32) return;
    if (y >= 32) return;
    if (w3dcgb_bgq_count >= W3DCGB_BG_QUEUE_LIMIT) return;
    w3dcgb_bgq_x[(__safe_index w3dcgb_u8)w3dcgb_bgq_count] = x;
    w3dcgb_bgq_y[(__safe_index w3dcgb_u8)w3dcgb_bgq_count] = y;
    w3dcgb_bgq_tile[(__safe_index w3dcgb_u8)w3dcgb_bgq_count] = tile;
    w3dcgb_bgq_count = (w3dcgb_u8)(w3dcgb_bgq_count + 1);
}
WIRE3DCGB_RGB15

5비트 빨강·초록·파랑 채널을 CGB 15비트 색으로 패킹합니다.

사용 형식

c
#define WIRE3DCGB_RGB15(r5, g5, b5) ((w3dcgb_u16)((w3dcgb_u16)((r5) & 31) | ((w3dcgb_u16)((g5) & 31) << 5) | ((w3dcgb_u16)((b5) & 31) << 10)))

매개변수

r5

빨강 채널로, 범위는 0~31입니다.

g5

초록 채널로, 범위는 0~31입니다.

b5

파랑 채널로, 범위는 0~31입니다.

반환값

u16으로 패킹한 RGB15 값입니다.

사용 조건과 제한

각 채널의 하위 5비트를 RGB15로 패킹합니다. 각 인수는 한 번만 평가합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:50

Wire3DCGB_SetCamera

한 바퀴를 16각도 단계로 표현해 투영용 카메라 위치와 방향을 저장합니다.

사용 형식

c
void Wire3DCGB_SetCamera(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 pitch, w3dcgb_i8 yaw, w3dcgb_i8 roll);

매개변수

x

월드 좌표계에서 카메라의 X 성분입니다.

y

월드 좌표계에서 카메라의 Y 성분입니다.

z

월드 좌표계에서 카메라의 Z 성분입니다.

pitch

X축 회전입니다. 16단계가 한 바퀴입니다.

yaw

Y축 회전입니다. 16단계가 한 바퀴입니다.

roll

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

기존 픽셀을 바꾸지 않고 카메라 위치와 각도를 저장합니다. 회전 도우미는 각도의 하위 4비트를 사용하므로 한 바퀴는 16단계입니다. 화면 오프셋은 별도의 LCD 레지스터에 있으며 이 호출로 바뀌지 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Four cubes compare unity/half scale and persistent/temporary line colors.
#include "wire_cgb_example.h"
__prg_rom Wire3DCGB_Vec3 vertices[8]={
    {-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},
    {-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}
};
__prg_rom Wire3DCGB_Edge edges[12]={
    {0,1},{1,2},{2,3},{3,0},{4,5},{5,6},
    {6,7},{7,4},{0,4},{1,5},{2,6},{3,7}
};
Wire3DCGB_Model cube;
u8 sx;
u8 sy;
void main() {
    wire_results_clear();
    cube.vertices=vertices; cube.edges=edges;
    cube.faces=0; cube.edge_faces=0;
    cube.vertex_count=8; cube.edge_count=12; cube.face_count=0; cube.flags=0;
    Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DCGB_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    Wire3DCGB_DrawModelColor(&cube,-32,-32,96,0,0,0,2);
    Wire3DCGB_DrawModelScaledColor(&cube,32,-32,96,0,0,0,128,3);
    result[0]=Wire3DCGB_GetLineColor();
    Wire3DCGB_DrawLine3D(0,56,96,0,-56,96);
    Wire3DCGB_DrawLine3DColor(-80,0,96,80,0,96,3);
    result[1]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[2]=sx; result[3]=sy;
    // Camera setters affect future projection, leaving the staged cubes intact.
    Wire3DCGB_SetCamera(0,0,0,0,4,0);
    result[4]=Wire3DCGB_ProjectPoint(0,0,96,&sx,&sy);
    result[5]=Wire3DCGB_ProjectPointNoRotation(0,0,96,&sx,&sy);
    result[6]=sx;
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

빨강·파랑·초록으로 표시한 원래 크기와 크기 조절 모델, 교차하는 3D 선을 비교합니다. RAM 값으로 카메라 투영과 회전을 생략한 투영도 확인합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_models.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:127

kitaqgb/lib/wire3d_cgb.c:8266

c
void Wire3DCGB_SetCamera(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 pitch, w3dcgb_i8 yaw, w3dcgb_i8 roll)
{
    w3dcgb_cam_x = x;
    w3dcgb_cam_y = y;
    w3dcgb_cam_z = z;
    w3dcgb_cam_pitch = pitch;
    w3dcgb_cam_yaw = yaw;
    w3dcgb_cam_roll = roll;
}
Wire3DCGB_SetLineColor

이후 선 그리기에 사용할 색상 인덱스를 선택합니다.

사용 형식

c
void Wire3DCGB_SetLineColor(w3dcgb_u8 color);

매개변수

color

그리기 색상 인덱스입니다. 샘플 팔레트는 1=빨강, 2=파랑, 3=초록을 사용합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

color & 3을 저장합니다. 이름이 정의된 선 색상 1~3을 사용하세요. 일반 선은 비트플레인을 OR 연산하므로 겹친 색이 합쳐지고, 전체 화면의 고속 선은 픽셀 색을 교체합니다. 선 색상 0은 지우기가 아니라 3으로 취급합니다. 일반 모드의 점 그리기는 별도로 색상 0을 이용한 지우기를 지원합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:119

kitaqgb/lib/wire3d_cgb.c:1140

c
void Wire3DCGB_SetLineColor(w3dcgb_u8 color)
{
    w3dcgb_line_color = (w3dcgb_u8)(color & 3);
}
Wire3DCGB_SetOcclusionActive

이후 선에 대한 가림 검사를 켜거나 끕니다.

사용 형식

c
void Wire3DCGB_SetOcclusionActive(w3dcgb_u8 active);

매개변수

active

0은 가림 검사를 끄고, 그 외의 값은 켭니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

active를 0 또는 1로 정규화하여 가림 스위치로 저장합니다. 마스크를 지우거나 도형을 등록하지는 않습니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Red/blue scanlines stop inside masks; green outlines identify the triangle.
#include "wire_cgb_example.h"
__prg_rom u8 silhouette[5]={0x73,0x74,0xFF,0x75,0x73};
void main() {
    u8 y;
    wire_results_clear(); Wire3DCGB_Init(); wire_colors(); Wire3DCGB_BeginFrame();
    // Clearing this first test mask must leave the upper-left scanline intact.
    Wire3DCGB_MarkTriangle2D(8,8,16,8,8,16);
    Wire3DCGB_ClearOcclusionMask();
    Wire3DCGB_MarkTriangle2D(32,16,64,16,32,48);
    Wire3DCGB_MarkPackedSilhouette2D(silhouette,5,-2,104,32);
    Wire3DCGB_SetOcclusionActive(1);
    for(y=8;y<=56;y=y+4) Wire3DCGB_DrawLine2DColor(8,y,88,y,1);
    for(y=28;y<=36;y++) Wire3DCGB_DrawLine2DColor(92,y,120,y,2);
    Wire3DCGB_SetOcclusionActive(0);
    Wire3DCGB_DrawLine2DColor(32,16,64,16,3);
    Wire3DCGB_DrawLine2DColor(64,16,32,48,3);
    Wire3DCGB_DrawLine2DColor(32,48,32,16,3);
    Wire3DCGB_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

삼각형이 빨간 주사선의 가운데를 가리고, 패킹된 실루엣이 파란 선을 가립니다. 초록 외곽선으로 가림 영역의 위치를 표시합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_mask.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_mask.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:149

kitaqgb/lib/wire3d_cgb.c:1970

c
void Wire3DCGB_SetOcclusionActive(w3dcgb_u8 active)
{
    if (active == 0) w3dcgb_occlusion_active = 0;
    else w3dcgb_occlusion_active = 1;
}
Wire3DCGB_SetPaletteRGB15

그리기에 사용할 네 색과 스탬프에 색을 입히는 배경 팔레트를 설정합니다.

사용 형식

c
void Wire3DCGB_SetPaletteRGB15(w3dcgb_u16 color0, w3dcgb_u16 color1, w3dcgb_u16 color2, w3dcgb_u16 color3);

매개변수

color0

팔레트 항목 0의 RGB15 색입니다.

color1

팔레트 항목 1의 RGB15 색입니다.

color2

팔레트 항목 2의 RGB15 색입니다.

color3

팔레트 항목 3의 RGB15 색입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

전달한 RGB15 색 네 개를 BG 팔레트 0에 설정합니다. 팔레트 1~3은 color0을 공유하고, 각 팔레트에 해당하는 0이 아닌 색을 항목 1~3에 반복해 넣습니다. 따라서 속성으로 단색 스탬프 타일의 색을 바꿀 수 있습니다. 보통 LCD를 끈 초기화 구간이나 VBlank처럼 팔레트에 접근 가능한 시점에 호출하세요.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:118

kitaqgb/lib/wire3d_cgb.c:1112

c
void Wire3DCGB_SetPaletteRGB15(w3dcgb_u16 color0, w3dcgb_u16 color1, w3dcgb_u16 color2, w3dcgb_u16 color3)
{
    w3dcgb_write_bg_color(0, color0);
    w3dcgb_write_bg_color(1, color1);
    w3dcgb_write_bg_color(2, color2);
    w3dcgb_write_bg_color(3, color3);

    w3dcgb_write_bg_color(4, color0);
    w3dcgb_write_bg_color(5, color1);
    w3dcgb_write_bg_color(6, color1);
    w3dcgb_write_bg_color(7, color1);

    w3dcgb_write_bg_color(8, color0);
    w3dcgb_write_bg_color(9, color2);
    w3dcgb_write_bg_color(10, color2);
    w3dcgb_write_bg_color(11, color2);

    w3dcgb_write_bg_color(12, color0);
    w3dcgb_write_bg_color(13, color3);
    w3dcgb_write_bg_color(14, color3);
    w3dcgb_write_bg_color(15, color3);
}
Wire3DCGB_SetScreenOffset

LCD 스크롤 레지스터 SCX와 SCY를 직접 설정합니다.

사용 형식

c
void Wire3DCGB_SetScreenOffset(w3dcgb_u8 scx, w3dcgb_u8 scy);

매개변수

scx

SCX에 기록할 픽셀 단위 스크롤 오프셋입니다.

scy

SCY에 기록할 픽셀 단위 스크롤 오프셋입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

VBlank를 기다리거나 투영 좌표를 바꾸지 않고 SCX/SCY에 즉시 씁니다. 화면에 보이는 스크롤 변경을 언제 허용할지는 호출자가 결정합니다.

CGB 전용입니다. 일반 스테이징은 WRAM 뱅크 2의 D300..DEFF를 예약합니다. 공유 상태를 사용하므로 재진입할 수 없습니다. 인터럽트에서 실행 중인 루틴을 중첩 호출하지 마세요. 샘플은 고정 스택과 전체 런타임을 사용합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// CGB raster paths: a red frame, blue diagonal, green marker and clipped line.
// Build this source together with lib/wire3d_cgb.c in an MBC5 256 KB CGB ROM.
#include "wire3d_cgb.h"
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4D) u8 sample_key1;
__location(0xC110) u16 result[8];
__prg_rom u8 lower_lines[8]={80,56,112,56,112,56,112,80};

void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DCGB_EnableDoubleSpeed();
    Wire3DCGB_Init(); // Already at double speed: its internal request is a no-op.
    result[2]=(u8)(sample_key1&128);
    // Palette writes are performed with the LCD off, after entering VBlank.
    while(sample_ly>=144) {} while(sample_ly<144) {}
    sample_lcdc=0;
    Wire3DCGB_SetPaletteRGB15(WIRE3DCGB_RGB15(0,0,0),WIRE3DCGB_RGB15(31,0,0),WIRE3DCGB_RGB15(0,0,31),WIRE3DCGB_RGB15(0,31,0));
    sample_lcdc=0x81;
    Wire3DCGB_SetScreenOffset(0,0);
    Wire3DCGB_SetCamera(0,0,0,0,0,0);
    Wire3DCGB_BeginFrame();
    Wire3DCGB_SetLineColor(1);
    Wire3DCGB_DrawLine2D(8,8,56,8);
    Wire3DCGB_DrawLine2D(56,8,56,40);
    Wire3DCGB_DrawLine2D(56,40,8,40);
    Wire3DCGB_DrawLine2D(8,40,8,8);
    Wire3DCGB_DrawLine2DColor(8,40,56,8,2);
    result[0]=Wire3DCGB_GetLineColor(); // Temporary blue restores red.
    Wire3DCGB_SetLineColor(3);
    Wire3DCGB_DrawPoint2D(64,48);
    Wire3DCGB_DrawLineClipped2D(-10,72,140,72,3);
    Wire3DCGB_DrawLineList2DColor(lower_lines,2,2);
    result[1]=Wire3DCGB_GetLineColor(); // The blue line list restores green.
    Wire3DCGB_PutBgTile(18,1,0x80); // Queue the supplied zero glyph outside the viewport.
    Wire3DCGB_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에서 기본 선, 점, 지우기와 투영을 보여 주는 샘플입니다. 빨간 테두리 안에 파란 대각선이 있고, 초록 점과 수평선, 파란 L, 오른쪽 위의 초록 숫자 0도 표시됩니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_cgb_raster.c .\kitaqgb\lib\wire3d_cgb.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_cgb_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_cgb.h:117

kitaqgb/lib/wire3d_cgb.c:1091

c
void Wire3DCGB_SetScreenOffset(w3dcgb_u8 scx, w3dcgb_u8 scy)
{
    w3dcgb_reg_scx = scx;
    w3dcgb_reg_scy = scy;
}

Wire3D 시간 측정, 88행 프로파일과 독립 시계

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

88행 전체 전송량은 DMG 1,408바이트, CGB 2,816바이트입니다. DMG 120행 대비 26.67%, 96행 대비 8.33% 줄지만 fps 증가율을 뜻하지 않습니다. DMG는 256바이트 열 간격을 유지하고 CGB는 11타일 열을 촘촘히 배치합니다. CGB 스테이지 예약은 전체 화면 호환성을 위해 3,072바이트를 유지합니다.

ProjectCameraPoint는 카메라 위치 차감이나 회전 없이 카메라 좌표를 투영합니다. Z가 8..255 밖이면 출력 변경 없이 0을 반환합니다. X/Y를 ±120으로 제한하고 역깊이 표의 부호 있는 곱을 32로 내림 나눗셈한 뒤 화면 경계로 제한합니다. 기하학적 선 클리핑은 아닙니다. 일반 CGB ProjectPoint는 각도가 0이어도 회전의 ±220 제한을 유지합니다.

DMG EndFrameNow는 첫 새 VBlank 대기만 생략하며 BG 큐, 전송 모드와 dirty 이력을 처리합니다. CGB EndFrameSparseNow도 동기 처리입니다. Now도 STAT 접근 구간, DMA 완료와 안전한 표시 전환을 기다립니다. DMG 갱신은 원자적이지 않습니다. CGB sparse 삭제는 현재 영역과 대상 뱅크의 두 프레임 전 영역을 포함합니다. 저수준 CGB 선 그리기는 dirty 등록이 필요합니다.

CGB sparse 시작 시 초기화 타일을 지우기 위해 각 대상 뱅크의 첫 사용(처음 두 프레임)에 전체 표시 영역을 갱신합니다. 측정에는 시작 비용이 포함됩니다. 일반 DrawLine2D는 sparse 범위를 등록하지 않으므로 DrawLineClipped2D 또는 명시적인 MarkDirtyRect2D를 사용합니다.

예제는 독자 제작한 움직이는 상자, 막대 계기와 네 음의 BGM을 사용합니다. 이동은 audio_vblank의 경과 tick으로 갱신하고 계기는 짧고 안전한 VBlank 처리로 갱신합니다. 공유 상태 렌더러를 ISR에서 호출하지 마세요. wire3d_audio_vblank.c는 80바이트 큐를 고정 WRAM에, 제어 함수를 ROM 뱅크 5에 배치합니다. 일반 audio_vblank.c를 함께 컴파일하지 마세요. CGB 예제는 WIRE3DCGB_STAGE_BANK2_ALLOCATION을 사용합니다. 8비트 tick 차이는 255프레임 이내에 읽어야 합니다.

측정 도구는 전송·표시 완료 후 마커를 셉니다. PPU dot(초당 4,194,304; 프레임당 70,224)으로 지우기, 투영, 선 그리기, 전송+표시, 외부 대기를 측정하고 평균·중앙값·최대 간격·기한 초과 수를 보고합니다. 전송+표시에는 내부 STAT/DMA/VBlank 대기가 포함됩니다. CGB 배속 CPU의 원시 사이클을 DMG와 직접 비교하지 마세요. 평균 fps 일치만으로 기한 초과가 없다고 할 수 없습니다. 실기 미검증입니다.

독자 예제 7구성이 각각 48회 전송을 완료하여 총 336회 스테이지/VRAM 비교와 84회 빈 프레임의 잔상 제거를 확인했습니다. 5프로파일에서 투영 경계 25,700건을 통과했습니다. Rust 빌드 5구성도 BGM 출력과 함께 48프레임을 완료했습니다. 4 PPU 프레임 기한을 넘는 구간이 있어 평균 fps만으로 처리 지연 없음을 보장하지 않습니다. 에뮬레이터 검증이며 실기 검증은 아닙니다.

KOKURA에서 독자 DMG/CGB 예제를 각각 400프레임 실행하고 SARAKURA 분석과 엄격한 스키마 검증을 통과했습니다. 각 구성은 오류 0건, 대기 루프의 반복 PC 경고 1건, DAC/믹서 팝음 위험 등 정보 3건입니다. 음질이나 실기 동작을 보장하지 않습니다.

공개 예제·이미지·증거에는 독자 제작한 도형, 계기와 음형만 사용합니다. 상용 게임 ROM, 추출 코드·도형·화면·음악·상태 파일은 포함하지 않습니다.

검증 결과와 예제 · C / BGM / HUD

설정fps중앙값 / 최악 (PPU 프레임)기한 초과 / 47
clocked_dmg_88_sparse13.8524.449 / 4.73235
clocked_dmg_96_sparse13.1864.669 / 4.89139
clocked_dmg_120_sparse13.4344.453 / 7.17635
clocked_cgb_88_sparse15.0124.000 / 5.00028
clocked_cgb_96_sparse15.0924.000 / 5.00026
clocked_cgb_88_full12.5325.000 / 6.00041
clocked_cgb_96_full12.5885.000 / 5.02041
Original DMG box and bar gauge
DMG 128×88 · 공개 예제·이미지·증거에는 독자 제작한 도형, 계기와 음형만 사용합니다. 상용 게임 ROM, 추출 코드·도형·화면·음악·상태 파일은 포함하지 않습니다.
Original CGB box and bar gauge
CGB 128×88 · 공개 예제·이미지·증거에는 독자 제작한 도형, 계기와 음형만 사용합니다. 상용 게임 ROM, 추출 코드·도형·화면·음악·상태 파일은 포함하지 않습니다.
Wire3DDMG_ProjectCameraPoint

ProjectCameraPoint는 카메라 위치 차감이나 회전 없이 카메라 좌표를 투영합니다. Z가 8..255 밖이면 출력 변경 없이 0을 반환합니다. X/Y를 ±120으로 제한하고 역깊이 표의 부호 있는 곱을 32로 내림 나눗셈한 뒤 화면 경계로 제한합니다. 기하학적 선 클리핑은 아닙니다. 일반 CGB ProjectPoint는 각도가 0이어도 회전의 ±220 제한을 유지합니다.

사용 형식

c
w3ddmg_u8 Wire3DDMG_ProjectCameraPoint(w3ddmg_i16 x,w3ddmg_i16 y,w3ddmg_i16 z,w3ddmg_u8* sx,w3ddmg_u8* sy);

매개변수

x

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

y

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

z

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

sx

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

sy

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

반환값

투영 성공은 1, 깊이 거부는 0입니다. 거부 시 sx와 sy는 바뀌지 않습니다.

사용 조건과 제한

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

예제는 독자 제작한 움직이는 상자, 막대 계기와 네 음의 BGM을 사용합니다. 이동은 audio_vblank의 경과 tick으로 갱신하고 계기는 짧고 안전한 VBlank 처리로 갱신합니다. 공유 상태 렌더러를 ISR에서 호출하지 마세요. wire3d_audio_vblank.c는 80바이트 큐를 고정 WRAM에, 제어 함수를 ROM 뱅크 5에 배치합니다. 일반 audio_vblank.c를 함께 컴파일하지 마세요. CGB 예제는 WIRE3DCGB_STAGE_BANK2_ALLOCATION을 사용합니다. 8비트 tick 차이는 255프레임 이내에 읽어야 합니다.

측정 도구는 전송·표시 완료 후 마커를 셉니다. PPU dot(초당 4,194,304; 프레임당 70,224)으로 지우기, 투영, 선 그리기, 전송+표시, 외부 대기를 측정하고 평균·중앙값·최대 간격·기한 초과 수를 보고합니다. 전송+표시에는 내부 STAT/DMA/VBlank 대기가 포함됩니다. CGB 배속 CPU의 원시 사이클을 DMG와 직접 비교하지 마세요. 평균 fps 일치만으로 기한 초과가 없다고 할 수 없습니다. 실기 미검증입니다.

사용 예

c
#define WIRE3D_DMG_HEIGHT 88
#include "wire3d_dmg.h"
void project_one() {
    u8 sx; u8 sy;
    if (Wire3DDMG_ProjectCameraPoint(-24, 20, 96, &sx, &sy)) {
        // Use the projected coordinates in a main-thread drawing routine.
    }
}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

독자 예제 7구성이 각각 48회 전송을 완료하여 총 336회 스테이지/VRAM 비교와 84회 빈 프레임의 잔상 제거를 확인했습니다. 5프로파일에서 투영 경계 25,700건을 통과했습니다. Rust 빌드 5구성도 BGM 출력과 함께 48프레임을 완료했습니다. 4 PPU 프레임 기한을 넘는 구간이 있어 평균 fps만으로 처리 지연 없음을 보장하지 않습니다. 에뮬레이터 검증이며 실기 검증은 아닙니다.

사용 예의 전체 프로그램

renderer_dmg_88.c

hardware.c

audio_glue.c

README.md

구현과 소스

kitaqgb/lib/wire3d_dmg.h:146

선언 주석 원문
Validate depth and project coordinates already in camera space.

kitaqgb/lib/wire3d_dmg.c:720

c
w3ddmg_u8 Wire3DDMG_ProjectCameraPoint(w3ddmg_i16 x,w3ddmg_i16 y,w3ddmg_i16 z,w3ddmg_u8* sx,w3ddmg_u8* sy)
{
 return w3ddmg_project_camera_space(x,y,z,sx,sy);
}
Wire3DCGB_ProjectCameraPoint

ProjectCameraPoint는 카메라 위치 차감이나 회전 없이 카메라 좌표를 투영합니다. Z가 8..255 밖이면 출력 변경 없이 0을 반환합니다. X/Y를 ±120으로 제한하고 역깊이 표의 부호 있는 곱을 32로 내림 나눗셈한 뒤 화면 경계로 제한합니다. 기하학적 선 클리핑은 아닙니다. 일반 CGB ProjectPoint는 각도가 0이어도 회전의 ±220 제한을 유지합니다.

사용 형식

c
w3dcgb_u8 Wire3DCGB_ProjectCameraPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);

매개변수

x

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

y

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

z

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

sx

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

sy

카메라 좌표의 부호 있는 16비트 X/Y/Z. sx와 sy는 쓰기 가능한 유효한 u8 포인터여야 합니다.

반환값

투영 성공은 1, 깊이 거부는 0입니다. 거부 시 sx와 sy는 바뀌지 않습니다.

사용 조건과 제한

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

예제는 독자 제작한 움직이는 상자, 막대 계기와 네 음의 BGM을 사용합니다. 이동은 audio_vblank의 경과 tick으로 갱신하고 계기는 짧고 안전한 VBlank 처리로 갱신합니다. 공유 상태 렌더러를 ISR에서 호출하지 마세요. wire3d_audio_vblank.c는 80바이트 큐를 고정 WRAM에, 제어 함수를 ROM 뱅크 5에 배치합니다. 일반 audio_vblank.c를 함께 컴파일하지 마세요. CGB 예제는 WIRE3DCGB_STAGE_BANK2_ALLOCATION을 사용합니다. 8비트 tick 차이는 255프레임 이내에 읽어야 합니다.

측정 도구는 전송·표시 완료 후 마커를 셉니다. PPU dot(초당 4,194,304; 프레임당 70,224)으로 지우기, 투영, 선 그리기, 전송+표시, 외부 대기를 측정하고 평균·중앙값·최대 간격·기한 초과 수를 보고합니다. 전송+표시에는 내부 STAT/DMA/VBlank 대기가 포함됩니다. CGB 배속 CPU의 원시 사이클을 DMG와 직접 비교하지 마세요. 평균 fps 일치만으로 기한 초과가 없다고 할 수 없습니다. 실기 미검증입니다.

사용 예

c
#define WIRE3DCGB_HEIGHT 88
#include "wire3d_cgb.h"
void project_one() {
    u8 sx; u8 sy;
    if (Wire3DCGB_ProjectCameraPoint(-24, 20, 96, &sx, &sy)) {
        // Use the projected coordinates in a main-thread drawing routine.
    }
}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

독자 예제 7구성이 각각 48회 전송을 완료하여 총 336회 스테이지/VRAM 비교와 84회 빈 프레임의 잔상 제거를 확인했습니다. 5프로파일에서 투영 경계 25,700건을 통과했습니다. Rust 빌드 5구성도 BGM 출력과 함께 48프레임을 완료했습니다. 4 PPU 프레임 기한을 넘는 구간이 있어 평균 fps만으로 처리 지연 없음을 보장하지 않습니다. 에뮬레이터 검증이며 실기 검증은 아닙니다.

사용 예의 전체 프로그램

renderer_cgb_88.c

hardware.c

audio_glue.c

README.md

구현과 소스

kitaqgb/lib/wire3d_cgb.h:168

선언 주석 원문
Project camera-space coordinates without subtracting/rotating the camera.
Depth 8..255; outputs unchanged on rejection. Shared scratch: no ISR calls.

kitaqgb/lib/wire3d_cgb.c:552

c
w3dcgb_u8 Wire3DCGB_ProjectCameraPoint(w3dcgb_i16 x,w3dcgb_i16 y,w3dcgb_i16 z,w3dcgb_u8* sx,w3dcgb_u8* sy)
{
    return w3dcgb_project_camera_space(x,y,z,sx,sy);
}
Wire3DDMG_EndFrameNow

DMG EndFrameNow는 첫 새 VBlank 대기만 생략하며 BG 큐, 전송 모드와 dirty 이력을 처리합니다. CGB EndFrameSparseNow도 동기 처리입니다. Now도 STAT 접근 구간, DMA 완료와 안전한 표시 전환을 기다립니다. DMG 갱신은 원자적이지 않습니다. CGB sparse 삭제는 현재 영역과 대상 뱅크의 두 프레임 전 영역을 포함합니다. 저수준 CGB 선 그리기는 dirty 등록이 필요합니다.

사용 형식

c
void Wire3DDMG_EndFrameNow();

반환값

반환값은 없습니다. 전송과 필요한 동기화가 끝난 뒤 반환합니다.

사용 조건과 제한

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

예제는 독자 제작한 움직이는 상자, 막대 계기와 네 음의 BGM을 사용합니다. 이동은 audio_vblank의 경과 tick으로 갱신하고 계기는 짧고 안전한 VBlank 처리로 갱신합니다. 공유 상태 렌더러를 ISR에서 호출하지 마세요. wire3d_audio_vblank.c는 80바이트 큐를 고정 WRAM에, 제어 함수를 ROM 뱅크 5에 배치합니다. 일반 audio_vblank.c를 함께 컴파일하지 마세요. CGB 예제는 WIRE3DCGB_STAGE_BANK2_ALLOCATION을 사용합니다. 8비트 tick 차이는 255프레임 이내에 읽어야 합니다.

측정 도구는 전송·표시 완료 후 마커를 셉니다. PPU dot(초당 4,194,304; 프레임당 70,224)으로 지우기, 투영, 선 그리기, 전송+표시, 외부 대기를 측정하고 평균·중앙값·최대 간격·기한 초과 수를 보고합니다. 전송+표시에는 내부 STAT/DMA/VBlank 대기가 포함됩니다. CGB 배속 CPU의 원시 사이클을 DMG와 직접 비교하지 마세요. 평균 fps 일치만으로 기한 초과가 없다고 할 수 없습니다. 실기 미검증입니다.

사용 예

c
#define WIRE3D_DMG_HEIGHT 88
#include "wire3d_dmg.h"
void draw_one() {
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,32,32);
    Wire3DDMG_PutBgTile(18,16,128);
    Wire3DDMG_EndFrameNow();
}

호출 부분을 보여 주는 코드입니다. 완전한 프로그램에 넣을 때는 명시된 초기화 및 버퍼 조건을 충족해야 합니다.

예상 결과

독자 예제 7구성이 각각 48회 전송을 완료하여 총 336회 스테이지/VRAM 비교와 84회 빈 프레임의 잔상 제거를 확인했습니다. 5프로파일에서 투영 경계 25,700건을 통과했습니다. Rust 빌드 5구성도 BGM 출력과 함께 48프레임을 완료했습니다. 4 PPU 프레임 기한을 넘는 구간이 있어 평균 fps만으로 처리 지연 없음을 보장하지 않습니다. 에뮬레이터 검증이며 실기 검증은 아닙니다.

사용 예의 전체 프로그램

renderer_dmg_88.c

hardware.c

audio_glue.c

README.md

구현과 소스

kitaqgb/lib/wire3d_dmg.h:289

선언 주석 원문
Same queue/gate/history lifecycle, without the initial fresh-VBlank wait.
Synchronous STAT-safe upload; not an atomic swap. LCD must remain enabled.

kitaqgb/lib/wire3d_dmg.c:3826

c
void Wire3DDMG_EndFrameNow()
{
    w3ddmg_flush_bg_queue();



    if (w3ddmg_aux_transfer_enabled)
    {
        w3ddmg_transfer_stage_aux_asm();
    }
    if (w3ddmg_dirty_transfer_enabled)
    {
        w3ddmg_transfer_dirty_stage();
    }
    else
    {
        w3ddmg_transfer_stage_asm();
    }

}

wire3d_dmg.h — DMG용 와이어프레임

고속 렌더링 경로 사용법

뷰포트 안의 선은 그리기 주소와 픽셀 비트를 순차 갱신하며, 남은 픽셀 수와 오차를 CPU 레지스터에 보관합니다. 따라서 픽셀마다 타일 좌표를 계산하지 않고 대각선이 이어지도록 연결 픽셀도 그립니다. 가림 처리가 켜져 있으면 선 위의 다섯 지점을 검사해 그릴지 결정하며, 채택한 선은 같은 고속 경로로 그립니다. 마스크 행은 경계의 일부 비트를 보존하면서 바이트 단위로 채웁니다. 면의 경계 사각형과 다섯 지점에 의한 제외 판정은 근사이며, 픽셀 단위의 정확한 삼각형·선 가림 판정이 아닙니다. 0, 90, 180, 270도 회전은 입력을 제한한 뒤 좌표 교환과 부호 변경으로 처리합니다. 게임 전체 성능은 정점 수, 모서리 길이, 가림과 VRAM 전송에도 좌우됩니다. 개별 연산 시간과 화면 한 장을 완성하는 시간은 따로 측정하세요.

흑백 3D 선 그리기입니다. 모델 정점·모서리·면과 오브젝트 위치·회전·배율을 제공하세요. 초기화, 프레임 시작, 그리기, 업로드 순서로 사용합니다. 물리는 별도입니다. 각도는 한 바퀴당 16단계이고 모델 배율 256이 1배입니다.

Vec3는 x/y/z, Edge는 정점 인덱스 a/b, Face는 삼각형 인덱스 a/b/c를 담습니다. Model의 vertices, edges, faces는 이 배열을 가리키고 각 count는 길이를 나타냅니다. edge_faces에는 인접 면 인덱스 f0/f1이 들어가며, 없는 면은 FACE_NONE입니다. flags의 MODEL_HIDDEN_LINES는 면 기반 모서리 선택을 요청합니다. 투영된 부호 있는 면적으로 면 방향을 결정하므로 정점 순서가 중요합니다.

Object는 모델 참조, 위치 x/y/z, 각도 rx/ry/rz, scale_q8, visible을 저장합니다. 여러 오브젝트가 모델을 공유할 수 있지만 그리기는 테이블을 복사하거나 ROM 뱅크를 자동 전환하지 않습니다. 그리는 동안 참조 데이터를 계속 읽을 수 있어야 합니다. CGB Object에는 색상 인덱스도 있습니다.

높이 96의 Model에는 edge_masks와 edge_mask_count도 있습니다. 오브젝트 요에 따라 선택되는 16비트 모서리 마스크의 RAM 테이블을 제공하거나, 사용하지 않으면 두 필드를 모두 0으로 설정하세요.

Wire3DDMG_BeginFrame

프레임 그리기를 시작하고 가림 검사를 끕니다.

사용 형식

c
void Wire3DDMG_BeginFrame();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_BeginFrame(); 스테이징 픽셀과 가림 마스크를 지우고 가림 필터를 끕니다. 표시 중인 VRAM 프레임과 대기 중인 BG 타일 큐는 바꾸지 않습니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_BeginFrame(); 가림 필터만 끕니다. 스테이징 영역은 보통 전송 중에 지워지고 첫 빈 스테이징 영역은 Init이 제공합니다. 아직 제출하지 않은 프레임을 버리거나 마스크를 지우거나 대기 중인 BG 쓰기/변경 플래그를 재설정하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:144

선언 주석 원문
Disable occlusion filtering only. Stage clearing normally happens during
transfer, and Init supplies the first clean stage. This does not discard an
unsubmitted frame, clear the mask, or reset pending BG writes/dirty flags.

kitaqgb/lib/wire3d_dmg.c:3379

c
void Wire3DDMG_BeginFrame()
{




    /* The consuming stage transfer clears D000 as it uploads, so BeginFrame only
       resets draw state. Wire3DDMG_Init supplies the first clean buffer. */

    w3ddmg_occlusion_active = 0;
}
Wire3DDMG_DrawIndexedEdges

정점과 2바이트 모서리 인덱스 쌍으로 정수 배율의 선 모델을 그립니다.

사용 형식

c
void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale);

매개변수

vertices

3D 정점 배열입니다.

vertex_count

정점 배열의 항목 수입니다.

edges

각 모서리의 정점 인덱스입니다. 선언된 구조체 또는 바이트 쌍 형식을 사용합니다.

edge_count

모서리 수입니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

scale

정수 배율입니다. 0은 1로 처리합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale); 정수 배율과 이동을 적용한 뒤 바이트 쌍 모서리 인덱스를 그립니다. 배율 0은 1이며 오브젝트 회전이나 면 필터는 없습니다. 정점을 최대 24개 투영합니다. 바이트 오프셋이 255를 넘으면 래핑되므로 모서리 쌍은 최대 128개로 지정하세요. 유효하지 않은 정점 ID와 깊이에서 제외된 끝점은 건너뛰며 null 배열은 무시합니다. 좌표 곱과 합은 s16으로 표현할 수 있어야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
    Wire3DDMG_TransferMainNow();
    // Direct auxiliary transfer writes a separate tile after the main upload.
    for(i=24;i<=31;i++) Wire3DDMG_DrawLine2D(40,i,47,i);
    stage_byte=(u8*)0xD518;result[1]=*stage_byte;
    Wire3DDMG_TransferAuxNow();result[2]=*stage_byte;

    // Do not upload the consumed stage again.
    result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_direct.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:253

선언 주석 원문
Draw byte-pair edge indices after integer scaling and translation; scale
zero means one, and there is no object rotation or face filtering. Project at
most 24 vertices. Supply at most 128 edge pairs because byte offsets wrap
after 255. Invalid vertex IDs/depth-rejected endpoints are skipped; null arrays
are ignored. Keep coordinate products/sums representable as s16.

kitaqgb/lib/wire3d_dmg.c:4568

c
void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale)
{
    w3ddmg_u8 i;
    w3ddmg_u8 count;

    if (vertices == 0) return;
    if (edges == 0) return;

    count = vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;
    if (scale == 0) scale = 1;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)(x + (w3ddmg_i16)(v->x * scale));
        vy = (w3ddmg_i16)(y + (w3ddmg_i16)(v->y * scale));
        vz = (w3ddmg_i16)(z + (w3ddmg_i16)(v->z * scale));

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }

        i = (w3ddmg_u8)(i + 1);
    }

    i = 0;
    while (i < edge_count)
    {
        w3ddmg_u8 a;
        w3ddmg_u8 b;

        a = edges[(__safe_index w3ddmg_u8)((w3ddmg_u8)(i << 1))];
        b = edges[(__safe_index w3ddmg_u8)((w3ddmg_u8)((i << 1) + 1))];
        if ((a < count) && (b < count) &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)a] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)b])
        {
            Wire3DDMG_DrawLine2D(
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)a],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)a],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)b],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)b]);
        }

        i = (w3ddmg_u8)(i + 1);
    }
}
Wire3DDMG_DrawLine2D

양 끝점을 포함하는 4방향 연결 화면 좌표 선을 스테이징 영역에 그립니다.

사용 형식

c
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by); 양 끝점을 포함한 연결 선을 128×96 스테이징 영역에 그립니다. DrawScene 중에는 5점 샘플 기반의 대략적인 가림 제외를 사용하고, 그 외에는 바로 그립니다. 뷰포트 좌표를 지정하세요. VRAM은 EndFrame에서만 갱신됩니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by); 변경 영역 전송이 켜져 있으면 경계 타일 직사각형을 표시한 뒤 스테이징 영역에 연결 선을 그립니다. 장면 그리기는 마스크 샘플 5개로 선을 제외할 수 있습니다. 128×120 뷰포트 안의 끝점을 지정하세요. 저수준 픽셀 경계 검사는 선분의 기하학적 클리핑을 수행하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:237

선언 주석 원문
Mark the bounding tile rectangle when dirty transfer is enabled, then draw
a connected staged line. Scene drawing may reject it using five mask samples.
Supply 128x120 viewport endpoints; low-level pixel bounds checks do not clip
the segment geometrically.

kitaqgb/lib/wire3d_dmg.c:3423

c
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by)
{

    w3ddmg_mark_line_dirty(ax, ay, bx, by);


    if (w3ddmg_occlusion_active)
    {
        w3ddmg_line_stage_masked_c(ax, ay, bx, by);
        return;
    }

    w3ddmg_line_x0 = ax;
    w3ddmg_line_y0 = ay;
    w3ddmg_line_x1 = bx;
    w3ddmg_line_y1 = by;
    if (ax < 128 && bx < 128 && ay < WIRE3D_DMG_SCREEN_H && by < WIRE3D_DMG_SCREEN_H)
        w3ddmg_line_inside_asm();
    else
        w3ddmg_line_stage_asm();
}
Wire3DDMG_DrawLine3D

두 월드 좌표 끝점을 투영하고 그 사이에 선을 그립니다.

사용 형식

c
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);

매개변수

ax

월드 좌표계에서 시작점의 X 성분입니다.

ay

월드 좌표계에서 시작점의 Y 성분입니다.

az

월드 좌표계에서 시작점의 Z 성분입니다.

bx

월드 좌표계에서 끝점의 X 성분입니다.

by

월드 좌표계에서 끝점의 Y 성분입니다.

bz

월드 좌표계에서 끝점의 Z 성분입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz); 두 월드 끝점을 투영하고 둘 다 깊이 범위를 통과할 때만 그립니다. 경계를 가로지르는 선분과 근·원평면의 교점을 구하지 않습니다. 투영된 끝점은 각각 화면 가장자리로 제한합니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz); 두 월드 끝점을 투영하고 둘 다 깊이 범위를 통과할 때만 그립니다. 경계를 가로지르는 선분과 근·원평면의 교점을 구하지 않습니다. 투영된 끝점은 각각 화면 가장자리로 제한합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:226

선언 주석 원문
Project both world endpoints and draw only when both pass the depth range.
Do not intersect a crossing segment with near/far planes; projected endpoints
are independently clamped to the screen edges.

kitaqgb/lib/wire3d_dmg.c:3546

c
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz)
{
    w3ddmg_u8 sx0;
    w3ddmg_u8 sy0;
    w3ddmg_u8 sx1;
    w3ddmg_u8 sy1;

    if (w3ddmg_project_world(ax, ay, az, &sx0, &sy0) == 0) return;
    if (w3ddmg_project_world(bx, by, bz, &sx1, &sy1) == 0) return;
    Wire3DDMG_DrawLine2D(sx0, sy0, sx1, sy1);
}
Wire3DDMG_DrawModel

정점과 모서리로 된 모델을 지정한 위치와 회전으로 원래 크기에 그립니다.

사용 형식

c
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz); 배율 256으로 DrawModelScaled를 호출하여 크기를 바꾸지 않고 모델을 그립니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz); 배율 256으로 DrawModelScaled를 호출하여 크기를 바꾸지 않고 모델을 그립니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;

    Wire3DDMG_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3DDMG_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    px=16;py=0;pz=0;Wire3DDMG_RotatePoint(&px,&py,&pz,0,4,0);
    result[1]=px; result[2]=py; result[3]=pz;
    Wire3DDMG_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_models.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:164

선언 주석 원문
Draw an unscaled model by delegating to DrawModelScaled with scale 256.

kitaqgb/lib/wire3d_dmg.c:3565

c
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz)

{
    Wire3DDMG_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}

kitaqgb/lib/wire3d_dmg.c:3563

c
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz)



{
    Wire3DDMG_DrawModelScaled(model, x, y, z, rx, ry, rz, 256);
}
Wire3DDMG_DrawModelScaled

모델 크기를 조절하고 Y/X/Z 순서로 회전한 뒤 정점을 이동·투영하여 모서리를 그립니다.

사용 형식

c
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8); 최대 24개 정점을 크기 조절하고 Y/X/Z 순서로 회전한 뒤 이동·투영합니다. 이어서 요 마스크와 선택적 앞면 필터를 적용해 최대 16개 모서리를 그립니다. 0 이하의 배율은 1배(256)로 바뀝니다. 모델·정점·모서리 포인터가 null이면 무시하며, 참조 테이블은 읽을 수 있어야 합니다. 배율 곱과 이동 결과는 부호 있는 16비트 범위에 유지하세요. 깊이 경계를 가로지르는 모서리는 클리핑하지 않고 제외합니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8); 최대 24개 정점을 크기 조절하고 Y/X/Z 순서로 회전한 뒤 이동·투영합니다. 이어서 선택적 인접 면 필터를 적용하여 바이트형 개수인 edge_count의 모든 항목을 순회합니다. 면 임시 공간은 최대 16개이며, 모서리 테이블에는 선언한 모든 항목이 있어야 합니다. 0 이하의 배율은 256입니다. 모델·정점·모서리 포인터가 null이면 무시합니다. 곱과 이동 결과를 부호 있는 16비트 범위에 유지하세요. 깊이 경계를 가로지르는 모서리는 제외합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;

    Wire3DDMG_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3DDMG_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    px=16;py=0;pz=0;Wire3DDMG_RotatePoint(&px,&py,&pz,0,4,0);
    result[1]=px; result[2]=py; result[3]=pz;
    Wire3DDMG_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_models.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:170

선언 주석 원문
Scale up to 24 vertices, rotate Y/X/Z, translate and project, then traverse
all edge_count entries (a byte count) with optional adjacent-face filtering.
Face scratch is capped at 16; edge tables must contain all declared entries.
Nonpositive scale means 256. Null model/vertex/edge pointers are ignored.
Keep products/translations in signed 16-bit range; depth-crossing edges are dropped.

kitaqgb/lib/wire3d_dmg.c:3710

c
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8)

{
    w3ddmg_u8 i;
    w3ddmg_u8 count;
    w3ddmg_u8 edge_count;
    w3ddmg_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->edges == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &model->vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
        vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
        vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);






        w3ddmg_rotate_y(&vx, &vz, ry);
        w3ddmg_rotate_x(&vy, &vz, rx);
        w3ddmg_rotate_z(&vx, &vy, rz);


        vx = (w3ddmg_i16)(vx + x);
        vy = (w3ddmg_i16)(vy + y);
        vz = (w3ddmg_i16)(vz + z);

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }
        i = (w3ddmg_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
    if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
    {
        w3ddmg_build_face_visibility(model, count, face_count);
    }

    edge_count = model->edge_count;




    i = 0;
    while (i < edge_count)
    {
        const Wire3DDMG_Edge* e;
        e = &model->edges[(__safe_index w3ddmg_u8)i];
        if ((e->a < count) && (e->b < count))
        {
            if (w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->a] &&
                w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->b] &&



                w3ddmg_is_edge_visible(model, i, face_count))

            {
                Wire3DDMG_DrawLine2D(
                    w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->a],
                    w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->a],
                    w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->b],
                    w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->b]);
            }
        }
        i = (w3ddmg_u8)(i + 1);
    }
}

kitaqgb/lib/wire3d_dmg.c:3703

c
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8)








{
    w3ddmg_u8 i;
    w3ddmg_u8 count;
    w3ddmg_u8 edge_count;
    w3ddmg_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->edges == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &model->vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
        vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
        vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);


        w3ddmg_rotate_y(&vx, &vz, (w3ddmg_i8)ry);
        w3ddmg_rotate_x(&vy, &vz, (w3ddmg_i8)rx);
        w3ddmg_rotate_z(&vx, &vy, (w3ddmg_i8)rz);






        vx = (w3ddmg_i16)(vx + x);
        vy = (w3ddmg_i16)(vy + y);
        vz = (w3ddmg_i16)(vz + z);

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }
        i = (w3ddmg_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
    if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) && (model->faces != 0) && (model->edge_faces != 0))
    {
        w3ddmg_build_face_visibility(model, count, face_count);
    }

    edge_count = model->edge_count;

    if (edge_count > WIRE3D_DMG_MODEL_EDGE_LIMIT) edge_count = WIRE3D_DMG_MODEL_EDGE_LIMIT;
    w3ddmg_build_edge_flags(model, edge_count, face_count, rx, ry, rz);

    i = 0;
    while (i < edge_count)
    {
        const Wire3DDMG_Edge* e;
        e = &model->edges[(__safe_index w3ddmg_u8)i];
        if ((e->a < count) && (e->b < count))
        {
            if (w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->a] &&
                w3ddmg_screen_visible[(__safe_index w3ddmg_u8)e->b] &&

                w3ddmg_edge_flags[(__safe_index w3ddmg_u8)i])



            {
                Wire3DDMG_DrawLine2D(
                    w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->a],
                    w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->a],
                    w3ddmg_screen_x[(__safe_index w3ddmg_u8)e->b],
                    w3ddmg_screen_y[(__safe_index w3ddmg_u8)e->b]);
            }
        }
        i = (w3ddmg_u8)(i + 1);
    }
}
Wire3DDMG_DrawScene

가까운 면으로 나중의 모서리를 가리면서 최대 8개 오브젝트를 가까운 순서로 그립니다.

사용 형식

c
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);

매개변수

objects

위치, 회전, 배율, 표시 여부 플래그를 담은 오브젝트 배열입니다.

count

제공한 배열 항목 수입니다. 실제 처리 상한은 해당 연산의 설명을 참조하세요.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count); 처음 최대 8개 오브젝트를 변환한 원점 깊이에 따라 가까운 순서로 정렬해 처리합니다. 보이는 유효 모델을 그린 뒤 앞면의 경계 직사각형을 마스크에 등록하여, 이후 선의 샘플 지점이 모두 가려지면 제외합니다. 깊이 버퍼가 아니라 오브젝트 간 가림의 근사입니다. 자체 마스크는 지우지만 기존 스테이징 픽셀은 유지합니다. null 배열은 무시하며 오브젝트와 그 데이터는 읽을 수 있어야 합니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count); 최대 8개 오브젝트 원점을 카메라 깊이 기준으로 가까운 순서로 정렬합니다. 보이는 유효 모델을 그리고 이후 오브젝트용으로 앞면 경계 직사각형을 등록합니다. 정렬 후 첫 슬롯은 마스크 검사를 생략하고 마지막 슬롯은 새 가림 영역이 필요 없습니다. 깊이 버퍼가 아닌 대략적인 선 제외입니다. null/빈 입력은 무시합니다. 순회 중 호출자 데이터와 현재 투영 캐시는 유효해야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;

    Wire3DDMG_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3DDMG_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    px=16;py=0;pz=0;Wire3DDMG_RotatePoint(&px,&py,&pz,0,4,0);
    result[1]=px; result[2]=py; result[3]=pz;
    Wire3DDMG_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_models.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:201

선언 주석 원문
Sort at most eight object origins by camera depth, near to far. Draw visible
valid models and mark front-face bounding rectangles for later objects. The
first sorted slot bypasses mask tests and the last needs no new occluder.
This is coarse line rejection, not a depth buffer. Null/empty input is ignored;
caller data and the current projection cache must remain valid during traversal.

kitaqgb/lib/wire3d_dmg.c:3461

c
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count)
{
    w3ddmg_u8 scene_count;
    w3ddmg_u8 i;

    if (objects == 0) return;

    scene_count = count;
    if (scene_count > WIRE3D_DMG_SCENE_OBJECT_LIMIT) scene_count = WIRE3D_DMG_SCENE_OBJECT_LIMIT;

    if (scene_count == 0) return;


    i = 0;
    while (i < scene_count)
    {
        w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = i;
        w3ddmg_scene_depth[(__safe_index w3ddmg_u8)i] = w3ddmg_scene_object_depth(&objects[(__safe_index w3ddmg_u8)i]);
        i = (w3ddmg_u8)(i + 1);
    }

    i = 0;
    while (i < scene_count)
    {
        w3ddmg_u8 j;
        j = (w3ddmg_u8)(i + 1);
        while (j < scene_count)
        {
            w3ddmg_u8 oi;
            w3ddmg_u8 oj;
            oi = w3ddmg_scene_order[(__safe_index w3ddmg_u8)i];
            oj = w3ddmg_scene_order[(__safe_index w3ddmg_u8)j];





            if (w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oj] < w3ddmg_scene_depth[(__safe_index w3ddmg_u8)oi])
            {
                w3ddmg_scene_order[(__safe_index w3ddmg_u8)i] = oj;
                w3ddmg_scene_order[(__safe_index w3ddmg_u8)j] = oi;
            }
            j = (w3ddmg_u8)(j + 1);
        }
        i = (w3ddmg_u8)(i + 1);
    }

    w3ddmg_clear_occlusion_mask();



    w3ddmg_occlusion_active = 0;


    i = 0;
    while (i < scene_count)
    {
        Wire3DDMG_Object* obj;
        obj = &objects[(__safe_index w3ddmg_u8)w3ddmg_scene_order[(__safe_index w3ddmg_u8)i]];
        if ((obj->visible != 0) && (obj->model != 0))
        {




            w3ddmg_occlusion_active = i == 0 ? 0 : 1;
            Wire3DDMG_DrawModelScaled(obj->model, obj->x, obj->y, obj->z, obj->rx, obj->ry, obj->rz, obj->scale_q8);
            if ((w3ddmg_u8)(i + 1) < scene_count)
            {
                w3ddmg_mark_model_occluder(obj->model);
            }

        }
        i = (w3ddmg_u8)(i + 1);
    }

    w3ddmg_occlusion_active = 0;
}
Wire3DDMG_EndFrame

대기 중인 배경 쓰기와 스테이징된 그림을 VRAM에 제출합니다.

사용 형식

c
void Wire3DDMG_EndFrame();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EndFrame(); 다음 VBlank를 기다리고 대기 중인 BG 맵 쓰기를 처리한 뒤, 접근 가능 구간을 폴링하며 스테이징 영역을 VRAM에 복사합니다. 복사하면서 스테이징 픽셀을 소비합니다. 전송이 VBlank 밖까지 이어질 수 있으며 원자적인 프레임 교체가 아닙니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EndFrame(); 다음 VBlank를 기다려 BG 쓰기를 처리한 뒤, 설정에 따라 보조 띠를 먼저 소비하고 변경 타일 또는 주 스테이징 영역 전체를 업로드합니다. 보조·주 원본이 겹치므로 이 순서가 중요합니다. 접근 가능 구간을 따라 STAT 폴링이 계속되며 한 번의 VBlank 안에 끝나지 않을 수 있습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:286

선언 주석 원문
Wait for the next VBlank and flush BG writes, then optionally consume the
auxiliary strips before uploading either dirty tiles or the entire main stage.
Auxiliary/main source overlap makes that ordering significant. STAT polling
continues across access windows; the update need not fit one VBlank.

kitaqgb/lib/wire3d_dmg.c:3819

c
void Wire3DDMG_EndFrame()
{
    w3ddmg_wait_vblank_start();
    Wire3DDMG_EndFrameNow();
}
Wire3DDMG_EraseModelFaces

모델의 앞면 삼각형을 투영하고 그 안의 스테이징 픽셀을 지웁니다.

사용 형식

c
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

scale_q8

256을 1배로 하는 배율입니다. 0 이하의 값도 1배를 뜻합니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8); 은선 플래그와 면 데이터를 가진 모델의 정점을 최대 24개 투영하고 앞면 삼각형 내부를 스테이징 영역에서 지웁니다. 0 이하의 배율은 256(1배)입니다. 최대 16개 면을 확인하며 깊이 경계를 가로지르는 면은 건너뜁니다. 공유 투영 캐시도 교체하지만 VRAM은 갱신하지 않습니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8); 은선 플래그와 면 데이터를 가진 모델의 정점을 최대 24개 투영하고 앞면 삼각형 내부를 스테이징 영역에서 지웁니다. 0 이하의 배율은 256(1배)입니다. 최대 16개 면을 확인하며 깊이 경계를 가로지르는 면은 건너뜁니다. 공유 투영 캐시도 교체하지만 VRAM은 갱신하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom Wire3DDMG_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom Wire3DDMG_Face faces[2]={{0,2,1},{0,3,2}};
Wire3DDMG_Model plane;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
    plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;
    Wire3DDMG_BeginFrame();
    // Separate panels show a direct screen triangle and a projected square face.
    for(i=8;i<=32;i++) Wire3DDMG_DrawLine2D(8,i,32,i);
    for(i=36;i<=84;i++) Wire3DDMG_DrawLine2D(40,i,88,i);
    Wire3DDMG_EraseTriangle2D(12,12,28,12,12,28);
    Wire3DDMG_EraseModelFaces(&plane,0,0,64,0,0,0,256);

    Wire3DDMG_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_faces.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:179

선언 주석 원문
Project up to 24 vertices and erase front-facing triangle interiors from
the stage for a model with hidden-line flags and face data. Nonpositive scale
means 256 (unity). Up to 16 faces are considered; depth-crossing faces are
skipped. This also replaces shared projection caches, but does not update VRAM.

kitaqgb/lib/wire3d_dmg.c:3581

c
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8)

{
    w3ddmg_u8 i;
    w3ddmg_u8 count;
    w3ddmg_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->faces == 0) return;
    if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &model->vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
        vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
        vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);






        w3ddmg_rotate_y(&vx, &vz, ry);
        w3ddmg_rotate_x(&vy, &vz, rx);
        w3ddmg_rotate_z(&vx, &vy, rz);


        vx = (w3ddmg_i16)(vx + x);
        vy = (w3ddmg_i16)(vy + y);
        vz = (w3ddmg_i16)(vz + z);

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }
        i = (w3ddmg_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
    w3ddmg_build_face_visibility(model, count, face_count);

    i = 0;
    while (i < face_count)
    {
        const Wire3DDMG_Face* f;
        f = &model->faces[(__safe_index w3ddmg_u8)i];
        if (w3ddmg_face_visible[(__safe_index w3ddmg_u8)i] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->a] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->b] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->c])
        {
            w3ddmg_clear_triangle(
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->a],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->a],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->b],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->b],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->c],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->c]);
        }
        i = (w3ddmg_u8)(i + 1);
    }
}

kitaqgb/lib/wire3d_dmg.c:3579

c
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8)



{
    w3ddmg_u8 i;
    w3ddmg_u8 count;
    w3ddmg_u8 face_count;

    if (model == 0) return;
    if (model->vertices == 0) return;
    if (model->faces == 0) return;
    if ((model->flags & WIRE3D_DMG_MODEL_HIDDEN_LINES) == 0) return;
    if (scale_q8 <= 0) scale_q8 = 256;

    count = model->vertex_count;
    if (count > WIRE3D_DMG_MODEL_VERTEX_LIMIT) count = WIRE3D_DMG_MODEL_VERTEX_LIMIT;

    i = 0;
    while (i < count)
    {
        const Wire3DDMG_Vec3* v;
        w3ddmg_i16 vx;
        w3ddmg_i16 vy;
        w3ddmg_i16 vz;
        w3ddmg_u8 sx;
        w3ddmg_u8 sy;

        v = &model->vertices[(__safe_index w3ddmg_u8)i];
        vx = (w3ddmg_i16)((v->x * scale_q8) >> 8);
        vy = (w3ddmg_i16)((v->y * scale_q8) >> 8);
        vz = (w3ddmg_i16)((v->z * scale_q8) >> 8);


        w3ddmg_rotate_y(&vx, &vz, (w3ddmg_i8)ry);
        w3ddmg_rotate_x(&vy, &vz, (w3ddmg_i8)rx);
        w3ddmg_rotate_z(&vx, &vy, (w3ddmg_i8)rz);






        vx = (w3ddmg_i16)(vx + x);
        vy = (w3ddmg_i16)(vy + y);
        vz = (w3ddmg_i16)(vz + z);

        if (w3ddmg_project_world(vx, vy, vz, &sx, &sy))
        {
            w3ddmg_screen_x[(__safe_index w3ddmg_u8)i] = sx;
            w3ddmg_screen_y[(__safe_index w3ddmg_u8)i] = sy;
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 1;
        }
        else
        {
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)i] = 0;
        }
        i = (w3ddmg_u8)(i + 1);
    }

    face_count = model->face_count;
    if (face_count > WIRE3D_DMG_MODEL_FACE_LIMIT) face_count = WIRE3D_DMG_MODEL_FACE_LIMIT;
    w3ddmg_build_face_visibility(model, count, face_count);

    i = 0;
    while (i < face_count)
    {
        const Wire3DDMG_Face* f;
        f = &model->faces[(__safe_index w3ddmg_u8)i];
        if (w3ddmg_face_visible[(__safe_index w3ddmg_u8)i] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->a] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->b] &&
            w3ddmg_screen_visible[(__safe_index w3ddmg_u8)f->c])
        {
            w3ddmg_clear_triangle(
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->a],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->a],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->b],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->b],
                w3ddmg_screen_x[(__safe_index w3ddmg_u8)f->c],
                w3ddmg_screen_y[(__safe_index w3ddmg_u8)f->c]);
        }
        i = (w3ddmg_u8)(i + 1);
    }
}
Wire3DDMG_EraseSpan2D

스테이징 영역 한 행에서 양 끝점을 포함하는 수평 스팬을 지웁니다.

사용 형식

c
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);

매개변수

y

지울 행의 픽셀 Y 좌표입니다.

x0

뷰포트 픽셀 단위의 작은 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

x1

뷰포트 픽셀 단위의 큰 쪽 X 끝점입니다. 순서와 경계 처리는 이 연산의 주의 사항을 따릅니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1); X 끝점 순서를 맞추고 양 끝점을 포함하는 스테이징 스팬을 지웁니다. 두 끝점은 모두 0~127이어야 합니다. 유효하지 않은 Y는 무시합니다. X를 자동으로 잘라 주지 않습니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1); X 끝점 순서를 맞추고 양 끝점을 포함하는 스테이징 스팬을 지웁니다. 두 끝점은 모두 0~127이어야 합니다. 유효하지 않은 Y는 무시합니다. X를 자동으로 잘라 주지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:187

선언 주석 원문
Order the X endpoints and erase the inclusive staged span. Both endpoints
must be in 0..127; invalid Y is ignored. The routine does not clip X for you.

kitaqgb/lib/wire3d_dmg.c:3681

c
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1)
{
    w3ddmg_u8 tx;

    if (x0 > x1)
    {
        tx = x0;
        x0 = x1;
        x1 = tx;
    }
    w3ddmg_stage_clear_span(y, x0, x1);
}
Wire3DDMG_EraseTriangle2D

수평 주사선 스팬을 사용해 화면 좌표 삼각형을 스테이징 영역에서 지웁니다.

사용 형식

c
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);

매개변수

ax

뷰포트 픽셀 단위의 정점 A X 좌표입니다.

ay

뷰포트 픽셀 단위의 정점 A Y 좌표입니다.

bx

뷰포트 픽셀 단위의 정점 B X 좌표입니다.

by

뷰포트 픽셀 단위의 정점 B Y 좌표입니다.

cx

뷰포트 픽셀 단위의 정점 C X 좌표입니다.

cy

뷰포트 픽셀 단위의 정점 C Y 좌표입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy); 정수 주사선 교점으로 스테이징 픽셀에서 삼각형을 지웁니다. 뷰포트 좌표를 지정하세요. 퇴화 삼각형은 무시하며 가림 마스크와 VRAM은 바꾸지 않습니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy); 정수 주사선 교점으로 스테이징 픽셀에서 삼각형을 지웁니다. 뷰포트 좌표를 지정하세요. 퇴화 삼각형은 무시하며 가림 마스크와 VRAM은 바꾸지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Erase a screen triangle and a projected model face from separate filled panels.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[4]={{-24,-24,0},{24,-24,0},{24,24,0},{-24,24,0}};
__prg_rom Wire3DDMG_Edge edges[4]={{0,1},{1,2},{2,3},{3,0}};
__prg_rom Wire3DDMG_Face faces[2]={{0,2,1},{0,3,2}};
Wire3DDMG_Model plane;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        plane.vertices=vertices;plane.edges=edges;plane.faces=faces;plane.edge_faces=0;
    plane.vertex_count=4;plane.edge_count=4;plane.face_count=2;plane.flags=1;
    Wire3DDMG_BeginFrame();
    // Separate panels show a direct screen triangle and a projected square face.
    for(i=8;i<=32;i++) Wire3DDMG_DrawLine2D(8,i,32,i);
    for(i=36;i<=84;i++) Wire3DDMG_DrawLine2D(40,i,88,i);
    Wire3DDMG_EraseTriangle2D(12,12,28,12,12,28);
    Wire3DDMG_EraseModelFaces(&plane,0,0,64,0,0,0,256);

    Wire3DDMG_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 면으로 채워진 영역을 지워, 남은 부분과 지운 부분을 확인할 수 있습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_faces.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_faces.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:184

선언 주석 원문
Erase a triangle from staged pixels using integer scanline intersections.
Supply viewport coordinates. Degenerate triangles are ignored; the occlusion
mask and VRAM are unchanged.

kitaqgb/lib/wire3d_dmg.c:3671

c
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy)
{
    w3ddmg_clear_triangle(ax, ay, bx, by, cx, cy);
}
Wire3DDMG_Init

흑백 와이어프레임 뷰포트용으로 LCD, 타일, 배경 맵을 초기화합니다.

사용 형식

c
void Wire3DDMG_Init();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_Init(); LCD 상태를 제어합니다. VBlank를 기다려 LCD를 끄고 타일 6144바이트와 BG 맵을 지운 뒤, HUD 타일과 부호 있는 타일 번호의 128×96 뷰포트를 설치하고 스크롤 0, BGP=0xB4로 BG 표시를 켭니다. 카메라, BG 큐, 스테이징 영역을 재설정합니다. 스테이징용 0xD000..0xDFFF를 예약하고 WRAM 뱅크 매핑을 유지하세요. 그리기 전에 BeginFrame을 호출해 가림 상태도 초기화하세요. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_Init(); LCD 상태를 제어하고 타일 VRAM과 BG 맵을 지운 뒤, 맵 타일 (3,1)부터 16×15 뷰포트를 설치합니다. 스크롤 (8,0), BGP=0xB4와 BG 표시를 설정합니다. 카메라, 큐, 전송 모드, 두 변경 테이블과 스테이징 영역을 재설정합니다. 0xD000..0xDFFF를 예약하고 WRAM 매핑을 유지하세요. 보조 저장 영역이 이 영역과 겹칩니다. 그리기 전에 BeginFrame을 호출해 가림 상태를 설정하세요.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:135

선언 주석 원문
Take over LCD state, clear tile VRAM and the BG map, and install a 16x15
viewport beginning at map tile (3,1). Set scroll (8,0), BGP=0xB4 and BG display.
Reset camera, queues, transfer modes, both dirty tables and stage. Reserve
0xD000..0xDFFF and retain its WRAM mapping; auxiliary storage aliases it.
Call BeginFrame before drawing to establish occlusion state.

kitaqgb/lib/wire3d_dmg.c:3310

c
void Wire3DDMG_Init()
{
    w3ddmg_u8 row;
    w3ddmg_u8 col;
    w3ddmg_u8 tid;
    w3ddmg_u16 off;

    w3ddmg_wait_vblank_start();
    w3ddmg_reg_lcdc = 0;

    w3ddmg_clear_vram_asm();



    w3ddmg_fill_bg_map_asm();

    row = 0;
    tid = 0x90;
    while (row < WIRE3D_DMG_TILE_H)
    {



        off = (w3ddmg_u16)(0x23 + ((w3ddmg_u16)row << 5));

        col = 0;
        while (col < WIRE3D_DMG_TILE_W)
        {
            w3ddmg_bg_map_9800[(w3ddmg_u16)(off + (w3ddmg_u16)col)] = tid;
            tid = (w3ddmg_u8)(tid + WIRE3D_DMG_TILE_H);
            col = (w3ddmg_u8)(col + 1);
        }
        row = (w3ddmg_u8)(row + 1);
        tid = (w3ddmg_u8)(0x90 + row);
    }




    w3ddmg_reg_scx = 8;

    w3ddmg_reg_scy = 0;
    w3ddmg_reg_bgp = 0xB4;
    w3ddmg_reg_lcdc = 0x81;
    w3ddmg_bgq_count = 0;

    w3ddmg_aux_transfer_enabled = 0;
    w3ddmg_dirty_transfer_enabled = 0;


    Wire3DDMG_SetCamera((w3ddmg_i16)0, (w3ddmg_i16)0, (w3ddmg_i16)0, (w3ddmg_u8)0, (w3ddmg_u8)0, (w3ddmg_u8)0);
    w3ddmg_clear_stage_asm();

    w3ddmg_clear_stage_aux_asm();
    w3ddmg_clear_dirty_tables();

}
Wire3DDMG_ProjectPoint

월드 좌표의 점을 카메라를 통해 뷰포트 좌표로 투영합니다.

사용 형식

c
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);

매개변수

x

월드 좌표계에서 점 또는 오브젝트 원점의 X 성분입니다.

y

월드 좌표계에서 점 또는 오브젝트 원점의 Y 성분입니다.

z

월드 좌표계에서 점 또는 오브젝트 원점의 Z 성분입니다.

sx

투영된 X 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

sy

투영된 Y 좌표를 받을 쓰기 가능한 유효 u8 포인터입니다.

반환값

투영에 성공하면 1, 깊이 검사에서 제외되면 0을 반환합니다.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy); 현재 카메라로 월드 점을 투영합니다. 깊이 검사에서 제외되면 출력은 유지하고 0을 반환하며, 성공하면 128×96 범위로 제한한 좌표를 씁니다. 출력 포인터는 유효해야 합니다. 화면 좌표 제한은 기하학적 클리핑이 아닙니다. WIRE3D_DMG_HEIGHT = 120 w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy); 현재 카메라로 월드 점을 투영합니다. 깊이가 유효하지 않으면 출력을 바꾸지 않고 0을 반환하며, 성공하면 128×120 범위로 제한한 좌표를 씁니다. 두 출력 포인터 모두 유효해야 하며 좌표 차이는 s16에 들어가야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:216

선언 주석 원문
Project a world point with the current camera. Return zero for invalid
depth without changing outputs; success writes clamped 128x120 coordinates.
Both output pointers must be valid. Coordinate differences must fit s16.

kitaqgb/lib/wire3d_dmg.c:688

c
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy)
{
    return w3ddmg_project_world(x, y, z, sx, sy);
}
Wire3DDMG_PutBgTile

배경 맵 셀 하나의 타일 번호 쓰기를 큐에 넣습니다.

사용 형식

c
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);

매개변수

x

32×32 배경 맵의 X 타일 좌표입니다.

y

32×32 배경 맵의 Y 타일 좌표입니다.

tile

배경 셀의 8비트 타일 번호입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile); 0x9800의 32×32 맵에 쓸 타일을 EndFrame용 큐에 넣습니다. 잘못된 맵 좌표와 대기 중인 쓰기 48개를 초과하는 요청은 조용히 무시합니다. 이 큐는 일반 vram 라이브러리 큐와 별개입니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile); 0x9800의 32×32 맵에 쓸 타일을 EndFrame용 큐에 넣습니다. 잘못된 맵 좌표와 대기 중인 쓰기 48개를 초과하는 요청은 조용히 무시합니다. 이 큐는 일반 vram 라이브러리 큐와 별개입니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:258

선언 주석 원문
Queue a tile write to the 32x32 map at 0x9800 for EndFrame. Invalid map
coordinates and submissions beyond 48 pending writes are silently ignored.
This queue is separate from the general vram library queue.

kitaqgb/lib/wire3d_dmg.c:731

c
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile)
{
    if (x >= 32) return;
    if (y >= 32) return;
    if (w3ddmg_bgq_count >= WIRE3D_DMG_BG_QUEUE_LIMIT) return;
    w3ddmg_bgq_x[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = x;
    w3ddmg_bgq_y[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = y;
    w3ddmg_bgq_tile[(__safe_index w3ddmg_u8)w3ddmg_bgq_count] = tile;
    w3ddmg_bgq_count = (w3ddmg_u8)(w3ddmg_bgq_count + 1);
}
Wire3DDMG_RotatePoint

주어진 각도로 점 하나를 제자리 회전시킵니다.

사용 형식

c
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);

매개변수

x

X 성분용 쓰기 가능한 s16 포인터입니다. 다른 성분과 별도 주소여야 합니다.

y

Y 성분용 쓰기 가능한 s16 포인터입니다. 다른 성분과 별도 주소여야 합니다.

z

Z 성분용 쓰기 가능한 s16 포인터입니다. 다른 성분과 별도 주소여야 합니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz); 한 바퀴를 16단계로 하여 Y/X/Z 순서로 제자리 회전합니다. 성분 포인터 하나라도 null이면 호출 전체가 아무것도 하지 않습니다. 포인터는 각각 다른 주소를 사용하세요. 각 축 회전은 입력을 ±220으로 제한합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
s16 px; s16 py; s16 pz;
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;

    Wire3DDMG_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3DDMG_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    px=16;py=0;pz=0;Wire3DDMG_RotatePoint(&px,&py,&pz,0,4,0);
    result[1]=px; result[2]=py; result[3]=pz;
    Wire3DDMG_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_models.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:221

선언 주석 원문
Rotate in place in Y/X/Z order using 16 steps per full turn. A null
component pointer makes the whole call a no-op; use distinct pointers.
Each axis rotation clamps its inputs to +/-220.

kitaqgb/lib/wire3d_dmg.c:3865

c
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz)
{
    if (x == 0) return;
    if (y == 0) return;
    if (z == 0) return;

    w3ddmg_rotate_y(x, z, ry);
    w3ddmg_rotate_x(y, z, rx);
    w3ddmg_rotate_z(x, y, rz);
}
Wire3DDMG_SelectEdgeMask

오브젝트의 요에 맞는 미리 계산된 모서리 가시성 마스크를 선택합니다.

사용 형식

c
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);

매개변수

model

정점·모서리·면 배열과 각 개수를 담은 모델입니다. 호출 중에는 해당 테이블을 읽을 수 있어야 합니다.

rx

X축 회전입니다. 16단계가 한 바퀴입니다.

ry

Y축 회전입니다. 16단계가 한 바퀴입니다.

rz

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

16비트 모서리 가시성 마스크입니다. 테이블이 없으면 0xFFFF입니다.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz); 오브젝트 요의 하위 4비트로 미리 계산한 마스크를 선택합니다. 피치·롤·카메라 방향은 무시합니다. 구간 수는 16, 8, 4, 2를 사용하세요. 다른 양수 개수는 항목 0을 선택하며, 16 이상이면 처음 16개를 사용합니다. 데이터가 없으면 0xFFFF를 반환합니다. 현재 데이터 포인터 매핑을 통해 마스크 테이블을 읽을 수 있어야 합니다.

이 샘플은 128×96 설정을 사용하며 뷰포트는 화면 (0,0)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Compare direct model scaling with an object-array scene.
// The selected 96-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 96
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[8]={{-16,-16,-16},{16,-16,-16},{16,16,-16},{-16,16,-16},{-16,-16,16},{16,-16,16},{16,16,16},{-16,16,16}};
__prg_rom Wire3DDMG_Edge edges[12]={{0,1},{1,2},{2,3},{3,0},{4,5},{5,6},{6,7},{7,4},{0,4},{1,5},{2,6},{3,7}};
Wire3DDMG_Model cube;
Wire3DDMG_Object objects[2];
u16 masks[2];
void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;

    cube.vertices=vertices;cube.edges=edges;cube.faces=0;cube.edge_faces=0;
    cube.vertex_count=8;cube.edge_count=12;cube.face_count=0;cube.flags=0;
    cube.edge_masks=0; cube.edge_mask_count=0;
    Wire3DDMG_BeginFrame();
    // Upper pair: direct model calls at unity and half scale.
    Wire3DDMG_DrawModel(&cube,-32,32,96,0,0,0);
    Wire3DDMG_DrawModelScaled(&cube,32,32,96,0,0,0,128);
    // Lower pair: the caller owns both object records and the model tables.
    for(i=0;i<2;i++) {
        objects[i].model=&cube;objects[i].x=-32+(s16)i*64;
        objects[i].y=-32;objects[i].z=96;
        objects[i].rx=0;objects[i].ry=0;objects[i].rz=0;
        objects[i].scale_q8=256-(s16)i*128;objects[i].visible=1;
    }
    Wire3DDMG_DrawScene(objects,2);
    // Numeric checks cover the operation supplied by this viewport profile.
    masks[0]=3;masks[1]=12;cube.edge_masks=masks; cube.edge_mask_count=2;
    result[1]=Wire3DDMG_SelectEdgeMask(&cube,0,0,0);
    result[2]=Wire3DDMG_SelectEdgeMask(&cube,0,8,0);
    Wire3DDMG_EndFrame(); result[7]=0xA55A;
    while(1) {}
}

예상 결과

원래 크기와 절반 크기의 모델 아래에 같은 배율의 오브젝트 배열 장면이 표시되어 투영과 크기 조절을 보여 줍니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg96_models.c .\kitaqgb\lib\wire3d_dmg_96.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg96_models.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:207

선언 주석 원문
Select a precomputed mask from the low four bits of object yaw; pitch,
roll and camera orientation are ignored. Use 16, 8, 4 or 2 bins; other positive
counts select entry zero (counts >=16 use the first 16). Missing data returns
0xFFFF. Keep the mask table readable through the current data-pointer mapping.

kitaqgb/lib/wire3d_dmg.c:1258

c
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz)
{
    w3ddmg_u8 count;
    w3ddmg_u8 bin;

    if (model == 0) return 0xFFFF;
    if (model->edge_masks == 0) return 0xFFFF;
    count = model->edge_mask_count;
    if (count == 0) return 0xFFFF;

    (void)rx;
    (void)rz;

    bin = (w3ddmg_u8)(((w3ddmg_u8)ry) & 15);
    if (count >= 16) return model->edge_masks[(__safe_index w3ddmg_u8)bin];
    if (count == 8) bin = (w3ddmg_u8)(bin >> 1);
    else if (count == 4) bin = (w3ddmg_u8)(bin >> 2);
    else if (count == 2) bin = (w3ddmg_u8)(bin >> 3);
    else bin = 0;

    if (bin >= count) bin = (w3ddmg_u8)(count - 1);
    return model->edge_masks[(__safe_index w3ddmg_u8)bin];
}
Wire3DDMG_SetAuxTransfer

EndFrame이 보조 띠도 전송할지 선택합니다.

사용 형식

c
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag);

매개변수

flag

0은 전송 기능을 끄고 그 외의 값은 켭니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag); EndFrame의 보조 전송 허용 상태를 저장합니다. 0이 아닌 값이면 켭니다. 여기서는 데이터를 복사하거나 지우지 않습니다. 보조 원본 바이트는 주 스테이징 영역과 주소를 공유합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Use the auxiliary-transfer gate to consume an overlapping stage strip.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        Wire3DDMG_SetDirtyTransfer(1); Wire3DDMG_SetAuxTransfer(1);
    Wire3DDMG_BeginFrame();
    for(i=24;i<=31;i++) Wire3DDMG_DrawLine2D(40,i,47,i);
    // Auxiliary upload consumes this source before the dirty main tile is sent.

    Wire3DDMG_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

주 스테이징 영역 일부가 보조 전송으로 소비되어 화면 좌표 (80,24)에 검은 8×8 블록이 생깁니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_aux_gate.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_aux_gate.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:268

선언 주석 원문
Store the EndFrame auxiliary-transfer gate; any nonzero value enables it.
No data is copied or cleared here. Auxiliary source bytes alias the main stage.

kitaqgb/lib/wire3d_dmg.c:4639

c
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag)
{
    w3ddmg_aux_transfer_enabled = flag;
}
Wire3DDMG_SetCamera

이후 투영에 사용할 카메라 위치와 방향을 저장합니다.

사용 형식

c
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);

매개변수

x

월드 좌표계에서 카메라의 X 성분입니다.

y

월드 좌표계에서 카메라의 Y 성분입니다.

z

월드 좌표계에서 카메라의 Z 성분입니다.

pitch

X축 회전입니다. 16단계가 한 바퀴입니다.

yaw

Y축 회전입니다. 16단계가 한 바퀴입니다.

roll

Z축 회전입니다. 16단계가 한 바퀴입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll); 이후 그리기를 위해 카메라 위치와 각도를 저장합니다. 한 바퀴는 16각도 단계입니다. 기존 그림을 다시 투영하거나 입력 범위를 검사하지 않습니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll); 이후 그리기를 위해 카메라 위치와 각도를 저장합니다. 한 바퀴는 16각도 단계입니다. 기존 그림을 다시 투영하거나 입력 범위를 검사하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:152

선언 주석 원문
Store camera position and angles for later draws; a full turn is 16 angle
steps. No existing drawing is reprojected and no input range validation occurs.

kitaqgb/lib/wire3d_dmg.c:3399

c
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll)

{
    w3ddmg_cam_x = x;
    w3ddmg_cam_y = y;
    w3ddmg_cam_z = z;
    w3ddmg_cam_pitch = pitch;
    w3ddmg_cam_yaw = yaw;
    w3ddmg_cam_roll = roll;
}

kitaqgb/lib/wire3d_dmg.c:3397

c
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll)



{
    w3ddmg_cam_x = x;
    w3ddmg_cam_y = y;
    w3ddmg_cam_z = z;
    w3ddmg_cam_pitch = pitch;
    w3ddmg_cam_yaw = yaw;
    w3ddmg_cam_roll = roll;
}
Wire3DDMG_SetDirtyTransfer

높이 120인 주 뷰포트의 변경 타일 전송을 선택합니다.

사용 형식

c
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag);

매개변수

flag

0은 전송 기능을 끄고 그 외의 값은 켭니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag); 변경 영역 전송 허용 상태를 저장하고 값이 그대로여도 두 변경 이력과 주 스테이징 영역을 지웁니다. VRAM은 유지합니다. 기존 그림 위에서 켜면 표시되지 않은 옛 타일이 남을 수 있으므로, 미리 깨끗한 표시 상태를 마련하세요.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Remove the previous frame and upload only the tracked current/previous tiles.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        Wire3DDMG_SetDirtyTransfer(1); Wire3DDMG_SetAuxTransfer(0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,24,8); Wire3DDMG_DrawLine2D(24,8,24,24);
    Wire3DDMG_DrawLine2D(24,24,8,24); Wire3DDMG_DrawLine2D(8,24,8,8);
    Wire3DDMG_EndFrame();
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(80,80,104,80); Wire3DDMG_DrawLine2D(104,80,104,104);
    Wire3DDMG_DrawLine2D(104,104,80,104); Wire3DDMG_DrawLine2D(80,104,80,80);

    Wire3DDMG_EndFrame(); result[7]=0xA55A; while(1) {}
}

예상 결과

이전의 왼쪽 위 테두리가 사라지고 화면 좌표 (96,88)..(120,112)에 새 테두리만 남습니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_dirty.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_dirty.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:272

선언 주석 원문
Store the dirty-transfer gate and clear both dirty histories and the main
stage, even if the value is unchanged. VRAM is retained; enabling this over an
old image can leave unmarked old tiles, so arrange a clean displayed baseline.

kitaqgb/lib/wire3d_dmg.c:4699

c
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag)
{
    w3ddmg_dirty_transfer_enabled = flag;
    w3ddmg_clear_dirty_tables();
    w3ddmg_clear_stage_asm();
}
Wire3DDMG_SetPalette

흑백 배경 팔레트 레지스터 BGP의 네 명암 매핑을 씁니다.

사용 형식

c
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp);

매개변수

bgp

2비트 명암 할당 네 개를 담은 BGP 레지스터 값입니다.

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 96 void Wire3DDMG_SetPalette(w3ddmg_u8 bgp); DMG BGP 팔레트의 원시 인코딩 값을 즉시 씁니다. 프레임 동기화는 하지 않습니다. WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_SetPalette(w3ddmg_u8 bgp); DMG BGP 팔레트의 원시 인코딩 값을 즉시 씁니다. 프레임 동기화는 하지 않습니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Draw a frame with a gap, a projected diagonal, and a copied corner tile.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
u8 projected_x;
u8 projected_y;
void main() {
    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
    Wire3DDMG_SetCamera(8,0,0,0,0,0);
    result[1]=Wire3DDMG_ProjectPoint(0,0,96,&projected_x,&projected_y);
    result[2]=projected_x; result[3]=projected_y;
    projected_x=91; projected_y=92;
    result[4]=Wire3DDMG_ProjectPoint(0,0,7,&projected_x,&projected_y);
    result[5]=projected_x; result[6]=projected_y;
    Wire3DDMG_SetCamera(0,0,0,0,0,0);
    Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawLine2D(8,8,56,8);
    Wire3DDMG_DrawLine2D(56,8,56,40);
    Wire3DDMG_DrawLine2D(56,40,8,40);
    Wire3DDMG_DrawLine2D(8,40,8,8);
    Wire3DDMG_EraseSpan2D(8,40,24); // Inclusive endpoints are ordered internally.
    Wire3DDMG_DrawLine3D(-24,-24,96,24,24,96);
    // Copy the viewport's top-left frame corner to a separate map cell.
    Wire3DDMG_PutBgTile(1,1,160);
    Wire3DDMG_EndFrame();
    result[7]=0xA55A;
    while(1) {}
}

예상 결과

한 프레임에 기본 선, 점, 지우기와 투영을 보여 줍니다. 왼쪽 위 테두리의 윗변 가운데가 지워지고 중앙 근처에 대각선이 투영됩니다. 거부된 투영은 출력값 91과 92를 그대로 유지합니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_raster.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_raster.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:260

선언 주석 원문
Write the raw DMG BGP palette encoding immediately; no frame synchronization occurs.

kitaqgb/lib/wire3d_dmg.c:746

c
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp)
{
    w3ddmg_reg_bgp = bgp;
}
Wire3DDMG_TransferAuxNow

보조 띠 6개를 즉시 업로드하고 원본 바이트를 지웁니다.

사용 형식

c
void Wire3DDMG_TransferAuxNow();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_TransferAuxNow(); 보조 전송 허용 상태와 관계없이 보조 원본 띠를 즉시 업로드·소비합니다. VBlank 시작을 기다리거나 변경 이력/BG 큐를 갱신하지 않습니다. 원본은 주 스테이징 영역과 겹치므로 주 영역 업로드와 순서를 조정해야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
    Wire3DDMG_TransferMainNow();
    // Direct auxiliary transfer writes a separate tile after the main upload.
    for(i=24;i<=31;i++) Wire3DDMG_DrawLine2D(40,i,47,i);
    stage_byte=(u8*)0xD518;result[1]=*stage_byte;
    Wire3DDMG_TransferAuxNow();result[2]=*stage_byte;

    // Do not upload the consumed stage again.
    result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_direct.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:280

선언 주석 원문
Upload and consume auxiliary source strips immediately, independent of the
auxiliary gate. No VBlank-start wait or dirty-history/BG-queue update occurs.
The source overlaps the main stage and must be coordinated with its upload.

kitaqgb/lib/wire3d_dmg.c:4727

c
void Wire3DDMG_TransferAuxNow()
{
    w3ddmg_transfer_stage_aux_asm();
}
Wire3DDMG_TransferMainNow

주 스테이징 영역 전체를 즉시 업로드하고 소비한 원본 픽셀을 지웁니다.

사용 형식

c
void Wire3DDMG_TransferMainNow();

반환값

반환값은 없습니다. 변경되는 상태와 표시 타이밍은 위 설명을 참조하세요.

사용 조건과 제한

WIRE3D_DMG_HEIGHT = 120 void Wire3DDMG_TransferMainNow(); 다음 VBlank를 기다리지 않고 STAT를 폴링하면서 주 스테이징 영역 전체를 즉시 업로드·소비합니다. 전송 게이트는 무시하고 변경 이력과 BG 타일 큐는 유지합니다. 프레임 처리 순서는 호출자가 조정해야 합니다.

이 샘플은 128×120 설정을 사용하며 뷰포트는 화면 (16,8)에서 시작합니다. WRAM D000..DFFF를 예약하고 CGB에서도 뱅크 매핑을 유지하세요. 공유 상태는 재진입할 수 없습니다.

WIRE3D_DMG_HEIGHT의 기본값은 120입니다. 높이 96에는 wire3d_dmg_96.c를 사용하세요. SelectEdgeMask는 높이 96에서 제공되며 RotatePoint, DrawIndexedEdges, 전송 게이트와 직접 전송은 높이 120이 필요합니다.

DMG의 WIRE3D_DMG_HEIGHT는 88·96·120, CGB의 WIRE3DCGB_HEIGHT는 88·96을 지원합니다. 기본값은 DMG 120, CGB 96입니다. 88행 화면은 128×88이며 중심 Y=44입니다. 라이브러리와 호출 코드의 설정을 맞추고 일반 진입점 대신 wire3d_dmg_88.c / wire3d_cgb_88.c를 컴파일합니다. DMG 88은 96행의 모델 구조와 16개 변 제한을 사용합니다. CGB 160×144 모드는 그대로입니다.

사용 예

c
#pragma bank 0
// Upload a main line and an auxiliary block separately; verify source consumption.
// The selected 120-line profile determines the stage layout and camera center.
#define WIRE3D_DMG_HEIGHT 120
#include "wire3d_dmg.h"
__location(0xC110) u16 result[8];
__location(0xFF47) u8 sample_bgp;
__location(0xFF40) u8 sample_lcdc;
__location(0xFF44) u8 sample_ly;
__location(0xFF4F) u8 sample_vbk;
__location(0xFF68) u8 sample_bgpi;
__location(0xFF69) u8 sample_bgpd;
__prg_rom Wire3DDMG_Vec3 vertices[2]={{-32,0,0},{32,0,0}};
__prg_rom u8 edge_pairs[2]={0,1};
u8* stage_byte;

void main() {

    u8 i;
    for(i=0;i<8;i++) result[i]=0;
    Wire3DDMG_Init();
    // A CGB-compatible ROM also needs CGB palette and tile-map attributes.
    if(__cgb_is_cgb()) {
        while(sample_ly>=144) {} while(sample_ly<144) {}
        sample_lcdc=0; sample_vbk=1;
        __vram_memset_unsafe(0x9800,0,1024); sample_vbk=0;
        sample_bgpi=0x80; sample_bgpd=255; sample_bgpd=127;
        for(i=0;i<6;i++) sample_bgpd=0;
        sample_lcdc=0x81;
    }
    Wire3DDMG_SetPalette(0xFC); // White background; every nonzero shade is black.
    result[0]=sample_bgp;
        Wire3DDMG_BeginFrame();
    Wire3DDMG_DrawIndexedEdges(vertices,2,edge_pairs,1,-64,104,96,1);
    Wire3DDMG_TransferMainNow();
    // Direct auxiliary transfer writes a separate tile after the main upload.
    for(i=24;i<=31;i++) Wire3DDMG_DrawLine2D(40,i,47,i);
    stage_byte=(u8*)0xD518;result[1]=*stage_byte;
    Wire3DDMG_TransferAuxNow();result[2]=*stage_byte;

    // Do not upload the consumed stage again.
    result[7]=0xA55A; while(1) {}
}

예상 결과

투영된 수평선과 보조 8×8 블록으로 직접 전송을 보여 줍니다. 소비되는 원본 바이트 하나가 255에서 0으로 바뀝니다.

사용 예의 전체 프로그램

빌드 명령

powershell
New-Item -ItemType Directory -Force .\out | Out-Null
.\kitaqgb\kitaqgb.exe .\kitaq-docs\samples\api-examples\gb\wire_dmg120_direct.c .\kitaqgb\lib\wire3d_dmg.c -I .\kitaqgb\lib -I .\kitaq-docs\samples -o .\out\wire_dmg120_direct.gb --profile=dev --stack-bank=fixed --rst-disable --cgb=cgb --cart=mbc5 --romsize=256k --no-cache --no-disasm
구현과 소스

kitaqgb/lib/wire3d_dmg.h:276

선언 주석 원문
Upload and consume the full main stage immediately, polling STAT but not
waiting for the next VBlank. Ignore transfer gates and leave dirty histories
and BG tile queue unchanged; the caller coordinates the frame lifecycle.

kitaqgb/lib/wire3d_dmg.c:4714

c
void Wire3DDMG_TransferMainNow()
{
    w3ddmg_transfer_stage_asm();
}

구조체, 상수, 전체 헤더

함수 외 매크로, 구조체, 배열 한도, 열거형, 별칭은 이 헤더에서 확인하세요. 원래 주석을 포함하여 수집한 소스를 그대로 실었습니다.

asset.h — 리소스 ID와 데이터 기술자
c
#pragma once

#define ASSET_TYPE_RAW   ((u8)0)
#define ASSET_TYPE_TILES ((u8)1)
#define ASSET_TYPE_MAP   ((u8)2)
#define ASSET_TYPE_SONG  ((u8)3)

// Packed ROM descriptor: type tag, payload bank, bank-window address and byte length.
// The table itself may live in a different bank from the payload.
typedef __packed struct {
    u8 type;
    u8 bank;
    const u8* ptr;
    u16 len;
} AssetDesc;

void __farmemcpy(void* dst, u8 bank, const void* src, u16 len);
void __vram_copy(u16 dst, const void* src, u16 len);

// Retain the descriptor table address, bank and count; the table is not copied.
void asset_set_table(u8 bank, const AssetDesc* table, u8 count);
// Copy one descriptor from its ROM bank into caller storage. Return zero for a
// null destination or an out-of-range ID; table validity is the caller's responsibility.
u8 asset_get(u8 asset_id, AssetDesc* out_desc);
// Copy at most max_len bytes using the asset's bank. Success means the ID was
// valid, even when the payload was truncated to fit the supplied limit.
u8 asset_load_raw(u8 asset_id, void* dst, u16 max_len);
// Accept tile/raw descriptors and transfer their bytes to VRAM. This path passes
// the descriptor pointer directly; callers must arrange the correct visible ROM bank.
u8 asset_load_tiles(u8 asset_id, u16 vram_dst);
// Return the descriptor bank, or zero on lookup failure; zero can also be a valid bank.
u8 asset_get_bank(u8 asset_id);
// Return the stored address without switching banks. Use the descriptor bank
// with far-data helpers before dereferencing banked assets; failure returns null.
const u8* asset_get_ptr(u8 asset_id);
// Return the descriptor byte length, or zero if its ID cannot be resolved.
u16 asset_get_len(u8 asset_id);

kitaqgb/lib/asset.h

audio.h — 음악, 효과음, 음향 제어
c
#pragma once

// Shared Game Boy audio driver for KITAQGB projects.
//
// Integration notes:
// - Compile a hardware-register file before audio.c so NR10..NR52 and
//   WAVE0..WAVE15 are already declared.
// - Call Audio_Init() once during startup.
// - Call Audio_Update() once per frame, ideally from your VBlank-driven main loop.
// - audio.c is intended to stay in bank 0.
// - Music streams are banked explicitly with Audio_PlayMusic(bank, song).
// - Audio_PlaySFX(sfx, priority) captures the currently visible ROM bank.
// - Audio_PlaySFXBanked(bank, sfx, priority) safely classifies CH1/CH3 data
//   after switching to the requested bank, so banked SFX can be started from
//   any currently visible ROM bank.
// - GBDAW-Stream v1.2 extends the legacy command set with explicit per-channel
//   automation commands that map more directly from GUI and Python tooling.

// Physical APIs and music-stream commands share zero-based CH1..CH4 IDs.
#define AUDIO_CHANNEL_CH1 ((u8)0)
#define AUDIO_CHANNEL_CH2 ((u8)1)
#define AUDIO_CHANNEL_CH3 ((u8)2)
#define AUDIO_CHANNEL_CH4 ((u8)3)

// Music-stream IDs used by NOTE, SET_INST and STOP_CHANNEL.
#define AUDIO_STREAM_CHANNEL_CH1 AUDIO_CHANNEL_CH1
#define AUDIO_STREAM_CHANNEL_CH2 AUDIO_CHANNEL_CH2
#define AUDIO_STREAM_CHANNEL_CH3 AUDIO_CHANNEL_CH3
#define AUDIO_STREAM_CHANNEL_CH4 AUDIO_CHANNEL_CH4

#define AUDIO_PAN_CENTER ((u8)0)
#define AUDIO_PAN_LEFT ((u8)1)
#define AUDIO_PAN_RIGHT ((u8)2)
#define AUDIO_PAN_MUTE ((u8)3)
#define AUDIO_PAN_INHERIT ((u8)0xFF)

#define AUDIO_WAVE_TRIANGLE ((u8)0)
#define AUDIO_WAVE_SAW ((u8)1)
#define AUDIO_WAVE_VOWEL_A ((u8)2)
#define AUDIO_WAVE_VOWEL_I ((u8)3)
#define AUDIO_WAVE_VOWEL_U ((u8)4)
#define AUDIO_WAVE_VOWEL_E ((u8)5)
#define AUDIO_WAVE_VOWEL_O ((u8)6)
#define AUDIO_WAVE_CUSTOM ((u8)7)

#define AUDIO_CH3_LEVEL_MUTE ((u8)0x00)
#define AUDIO_CH3_LEVEL_100 ((u8)0x20)
#define AUDIO_CH3_LEVEL_50 ((u8)0x40)
#define AUDIO_CH3_LEVEL_25 ((u8)0x60)

#define AUDIO_VOLUME_MIN ((u8)0)
#define AUDIO_VOLUME_MAX ((u8)7)
#define AUDIO_NOTE_MAX ((u8)67)

#define AUDIO_CMD_WAIT ((u8)0x00)
#define AUDIO_CMD_NOTE ((u8)0x10)
#define AUDIO_CMD_SET_INST ((u8)0x11)
#define AUDIO_CMD_SET_PAN ((u8)0x12)
#define AUDIO_CMD_SET_SWEEP ((u8)0x13)
#define AUDIO_CMD_SET_WAVE ((u8)0x14)
#define AUDIO_CMD_SET_CH3_CUSTOM_WAVE ((u8)0x15)
#define AUDIO_CMD_SET_CH4_PARAM ((u8)0x16)
#define AUDIO_CMD_SET_MASTER_VOLUME ((u8)0x17)
#define AUDIO_CMD_SET_CH1_DUTY ((u8)0x18)
#define AUDIO_CMD_SET_CH2_DUTY ((u8)0x19)
#define AUDIO_CMD_SET_CH3_LEVEL ((u8)0x1A)
#define AUDIO_CMD_STOP_CHANNEL ((u8)0x20)
#define AUDIO_CMD_LOOP ((u8)0x30)
#define AUDIO_CMD_STOP ((u8)0x40)

#define AUDIO_SFX_CH3_MARKER ((u8)0xFF)

// Enable the APU and reset software streams, instruments, mix and fade state.
// Load the initial triangle wave, then leave every channel silent. Call at startup
// before concurrent interrupt-driven audio service can access these shared fields.
void Audio_Init();
// Advance the master fade first. Unless paused, service both effect streams
// then the optional legacy music decoder. Call once per frame for frame-based timing.
void Audio_Update();
// Retain the bank and song pointer, reset legacy instruments/cursors, and arm
// playback from the beginning. Supply a valid, persistent song; no bytes are copied
// and null is not checked. Existing effect streams remain active.
void __stackcall Audio_PlayMusic(u8 bank, u8 *song);
// Stop legacy music and clear its resume mask, then silence all physical channels.
// Effect pointers remain active and may produce sound on a later update.
void Audio_StopMusic();
// On pause entry, silence hardware while retaining cursors. On resume, retrigger
// eligible legacy CH1, CH2 and CH4 notes; CH3 is not retriggered here. Updates still
// advance master fades while paused, and effect playback resumes on a later update.
void __stackcall Audio_SetPaused(u8 on);
// Capture the currently mapped ROM bank and start an effect with inherited pan.
// Use the explicit-bank API when the pointer belongs to another bank.
void __stackcall Audio_PlaySFX(u8 *sfx, u8 priority);
// Start a banked effect with the channel's base pan, subject to priority arbitration.
void __stackcall Audio_PlaySFXBanked(u8 bank, u8 *sfx, u8 priority);
// Capture the currently mapped ROM bank and request an effect with a pan override.
// Use the explicit-bank API when the pointer belongs to another bank.
void __stackcall Audio_PlaySFXPanned(u8 *sfx, u8 priority, u8 pan);
// Retain a banked effect stream if its priority equals or exceeds the current
// owner's priority, or that slot is empty. A leading CH3 marker selects the wave
// slot and is skipped; other streams use the pulse slot. Paused requests are ignored.
// Keep stream storage valid until completion; acceptance does not trigger a note.
void __stackcall Audio_PlaySFXPannedBanked(u8 bank, u8 *sfx, u8 priority, u8 pan);
// Clear both effect streams and their pan overrides. When not paused, release
// borrowed channels through the configured legacy or VBlank recovery path.
void Audio_StopSfx();
// Stop a physical channel and clear its legacy resume bit. CH1 also clears the
// pulse effect stream; CH3 clears the wave effect stream. This is the legacy
// channel API and does not clear a VBlank driver's independently latched notes.
void __stackcall Audio_StopChannel(u8 ch);

// Set the music-processing gate. This does not silence notes already playing
// or stop the legacy stream cursor from consuming commands.
void __stackcall Audio_SetMusicEnabled(u8 on);
// Enable effect note writes, or disable them and release both effect streams.
// Disabling follows Audio_StopSfx recovery rules rather than silencing all channels.
void __stackcall Audio_SetSfxEnabled(u8 on);

// Clamp both output levels to 0..7, cancel any fade, and write NR50 immediately.
void __stackcall Audio_SetMasterVolume(u8 left, u8 right);
// Move left/right volume toward clamped targets at the requested Audio_Update
// call interval. An interval of zero applies the levels immediately.
void __stackcall Audio_FadeToMasterVolume(u8 left, u8 right, u8 step_frames);
// Cancel further volume steps, retaining the current cached levels and hardware output.
void Audio_CancelMasterVolumeFade();

// Update the base pan for a physical channel and reapply active effect overrides.
// Unknown channel IDs select CH4; unsupported pan values mute the selected channel.
void __stackcall Audio_SetPan(u8 ch, u8 pan);
// Two bits per channel (CH1 in bits 0-1): center, left, right, mute.
// Applies all four positions with one NR51 update for sequencer automation.
void __stackcall Audio_SetPanPacked(u8 packed);
// Install a named preset or the cached custom wave. Unknown IDs are ignored.
// This does not update Audio_Ch3Wave or trigger a new note.
void __stackcall Audio_LoadWave(u8 wave_id);
// Copy 16 packed sample bytes into the persistent custom cache and wave RAM.
// A null pointer is ignored; the source is needed only for this call.
void __stackcall Audio_LoadCustomWave(const u8 *wave16);

// Cache the low two duty bits for the next CH1 note; do not change the active register.
void __stackcall Audio_SetCh1Duty(u8 duty);
// Cache the low two duty bits for the next CH2 note; do not change the active register.
void __stackcall Audio_SetCh2Duty(u8 duty);
// Cache the raw NR32 level encoding for the next CH3 note without writing hardware.
void __stackcall Audio_SetCh3Level(u8 level);
// Cache the raw noise polynomial encoding for the next CH4 note without writing hardware.
void __stackcall Audio_SetCh4Param(u8 param);

// Trigger CH1 with the cached sweep and the supplied raw envelope. Clamp the
// note index; duty values 0, 1 and 3 select their encodings, and all others use 2.
void __stackcall Audio_Ch1NoteOn(u8 note, u8 vol_env, u8 duty2);
// Trigger CH2 with the supplied raw envelope and a clamped note index. Duty
// values 0, 1 and 3 select their encodings; all other values use duty 2.
void __stackcall Audio_Ch2NoteOn(u8 note, u8 vol_env, u8 duty2);
// Clamp the note index, program the raw NR32 output level, and trigger CH3.
// Wave RAM must already contain the desired waveform; this does not load one.
void __stackcall Audio_Ch3NoteOn(u8 note, u8 level);
// Cache the supplied noise parameter, program the raw envelope and polynomial
// registers, then trigger CH4 with the length-enable bit clear.
void __stackcall Audio_Ch4NoteOn(u8 param, u8 vol_env);

kitaqgb/lib/audio.h

audio_vblank.h — VBlank IRQ를 통한 음악 재생
c
#pragma once

// Fixed-bank VBlank BGM driver.
//
// Stream format:
//   delay, ch1_note, ch2_note, ch3_note, ch4_noise_param
//   IMMEDIATE, ch1_note, ch2_note, ch3_note, ch4_noise_param
//   CONTROL, command, arg0, arg1, arg2
//
// Notes are 0..67. To stay inside the useful CGB register range, C6..G6
// (60..67) alias C5..G5 (48..55) in the fixed pitch table. REST leaves a
// channel unchanged, while STOP silences it. END stops either playback mode.
// LOOP jumps to MusicLoopPoint only in direct-pointer mode; a queue producer
// must expand loops itself. IMMEDIATE is recognized only in queue mode.
// Direct streams treat 0xFB as an ordinary delay, and queues treat 0xFE as one.

#define AUDIO_VBLANK_REST ((u8)0xFF)
#define AUDIO_VBLANK_END  ((u8)0xFF)
#define AUDIO_VBLANK_LOOP ((u8)0xFE)
#define AUDIO_VBLANK_STOP ((u8)0xFD)
#define AUDIO_VBLANK_CONTROL ((u8)0xFC)
#define AUDIO_VBLANK_IMMEDIATE ((u8)0xFB)
#define AUDIO_VBLANK_CONTROL_RESET ((u8)0x01)

#define AUDIO_VBLANK_W8 ((u8)15)
#define AUDIO_VBLANK_WQ ((u8)30)
#define AUDIO_VBLANK_WH ((u8)60)

#define AUDIO_VBLANK_QUEUE_RECORDS 16
#define AUDIO_VBLANK_QUEUE_BYTES 80

typedef void (*AudioVBlankFrameHook)();

extern __wram u8 AudioVBlank_MusicPlaying;
extern __wram u8 AudioVBlank_MusicEnabled;
extern __wram u8 AudioVBlank_MusicDelay;
extern __wram u8 *AudioVBlank_MusicStart;
extern __wram u8 *AudioVBlank_MusicPointer;
extern __wram u8 *AudioVBlank_MusicLoopPoint;
extern __wram u8 AudioVBlank_Step;
extern __wram u8 AudioVBlank_Ch2Note;
extern __wram u8 AudioVBlank_Ch1Note;
extern __wram u8 AudioVBlank_Ch3Note;
extern __wram u8 AudioVBlank_Ch2LatchedNote;
extern __wram u8 AudioVBlank_Ch1LatchedNote;
extern __wram u8 AudioVBlank_Ch3LatchedNote;
// Sound effects temporarily own CH1/CH2/CH3.  A pending value of 1 means a BGM
// note/stop event was suppressed and must be applied once the effect ends;
// value 2 means release the effect channel without retriggering an old note.
extern __wram u8 AudioVBlank_RestoreCh1Pending;
extern __wram u8 AudioVBlank_RestoreCh3Pending;
extern __wram u8 AudioVBlank_Ch4Param;
extern __wram u8 AudioVBlank_Ch1Envelope;
extern __wram u8 AudioVBlank_Ch2Envelope;
extern __wram u8 AudioVBlank_Ch4Envelope;
extern __wram u8 AudioVBlank_Ch1Duty;
extern __wram u8 AudioVBlank_Ch2Duty;
extern __wram u8 AudioVBlank_Ch1Sweep;
extern __wram u8 AudioVBlank_Ch3Level;
extern __wram u8 AudioVBlank_ControlCommand;
extern __wram u8 AudioVBlank_ControlArg0;
extern __wram u8 AudioVBlank_ControlArg1;
extern __wram u8 AudioVBlank_ControlArg2;
// QueueReset/QueueRefill/QueuePlay provide the foreground producer. The ISR owns
// ReadIndex and decreases Count; use the producer APIs instead of editing the
// indices/count while playback is running. Records contain exactly five bytes.
// MusicPlaying and all enable/pause gates still apply in queue mode.
extern __wram u8 AudioVBlank_QueueMode;
extern __wram u8 AudioVBlank_QueueReadIndex;
extern __wram u8 AudioVBlank_QueueWriteIndex;
extern __wram u8 AudioVBlank_QueueCount;
extern __wram u8 AudioVBlank_QueueUnderruns;
// Queue bytes reside in WRAM bank 1. A producer must select that bank while
// writing and restore the caller bank; publish the record only after all bytes
// are complete. The ISR selects bank 1 itself and restores SVBK before returning.
extern __wramx_bank(1) u8 AudioVBlank_QueueBuffer[AUDIO_VBLANK_QUEUE_BYTES];
// The ISR invokes this hook even when music processing is gated off. It runs
// with SVBK=1 using a direct-address call; keep hook code/data accessible in that
// context and synchronize pointer changes with interrupt execution.
extern __wram AudioVBlankFrameHook AudioVBlank_FrameHook;

// Reset software playback state, queue counters, instruments and the frame hook.
// Call before enabling this ISR; the routine does not mask interrupts or
// initialize the APU registers and cannot synchronize with an active handler.
void AudioVBlank_Init();
// Stop music and select an empty WRAM queue; preserve IE, IME and enable/pause gates.
void AudioVBlank_QueueReset();
// Copy complete records from the currently mapped source; return records accepted.
// Each call attempts at most 16 records and stops when full. Null/zero returns 0.
// Supports ROM and RAM sources, restores SVBK and IE, and never changes IME.
// Single foreground producer only: do not call from an ISR or frame hook.
// LOOP must be expanded by the producer. END occupies a full five-byte record.
u8 __stackcall AudioVBlank_QueueRefill(const u8 *records, u8 count);
// Start/resume queued playback; return 1 on success, 0 for an empty/nonqueue mode.
// Does not enable the interrupt, music gate or clear pause. Queue before starting.
u8 AudioVBlank_QueuePlay();
// Select a directly addressed song and reset its cursors, leaving the playing
// flag unchanged. Song storage must remain accessible to the fixed-bank ISR;
// coordinate this multi-field update with interrupt execution.
void __stackcall AudioVBlank_SetMusic(u8 *song);
// Restart the selected direct song at its beginning, leaving queue mode.
// A null song invokes Stop; this does not enable the music or IRQ gates.
void AudioVBlank_Play();
// Select and restart a directly addressed song. This is not the banked WRAM-queue path.
void __stackcall AudioVBlank_PlayMusic(u8 *song);
// Stop software playback and silence pulse/noise envelopes and the wave DAC.
// Song pointers and the IRQ enable remain unchanged; the routine writes the
// physical channels directly, so coordinate ownership with sound effects.
void AudioVBlank_Stop();
// Gate music processing and clear pending CH1/CH3 recovery on disable.
// No audio register is written here: disabling does not itself silence a note
// already playing or disable the VBlank interrupt.
void __stackcall AudioVBlank_SetEnabled(u8 on);
// Enable the VBlank source in IE and execute EI, enabling CPU interrupts globally.
// Install the correct interrupt vector and initialize driver state first.
void AudioVBlank_EnableIrq();
// Clear only the VBlank bit in IE. Other interrupt sources and current sound remain unchanged.
void AudioVBlank_DisableIrq();
// Recover the borrowed pulse channel (CH1 or CH2) from its latched music event.
// Pending value 2, disabled music, or a non-note latch silences it instead.
// The caller must first establish that the effect has released the channel.
void AudioVBlank_RestoreCh1();
// Recover a latched wave-channel music event after effect release, or disable
// the DAC for a release-only request, disabled music, or a non-note latch.
// The caller owns effect arbitration and clearing the pending flag.
void AudioVBlank_RestoreCh3();
// Request deferred pulse-channel release only when no recovery is pending.
// Preserve value 1, which records a music event suppressed while an effect owned it.
void AudioVBlank_RequestRestoreCh1();
// Request a deferred wave-channel release only if no recovery is pending.
// Preserve value 1, which records a new music event suppressed by the effect.
void AudioVBlank_RequestRestoreCh3();

kitaqgb/lib/audio_vblank.h

bank.h — 뱅크를 고려한 코드·데이터 접근
c
#pragma once

// A bank byte accompanies the CPU-visible ROM address; the pointer alone is not a far address.
typedef __packed struct {
    u8 bank;
    const u8* ptr;
} BankPtr;

extern u8 kq_bank_current;

void __bankswitch(u8 bank);
u8 __farpeek8(u8 bank, const void* addr);
u16 __farpeek16(u8 bank, const void* addr);
void __farmemcpy(void* dst, u8 bank, const void* src, u16 len);
void __farcall_ptr(u8 bank, const void* func);

// Update both the library bank record and the compiler shadow used by far
// reads and calls. Invoke this permanent bank change from fixed-bank code.
void bank_switch(u8 bank);
// Return the last bank recorded by bank_switch; this does not read cartridge hardware.
u8 bank_get_current();
// Read one byte through the compiler intrinsic that accepts an explicit ROM bank.
u8 far_data_read8(u8 bank, const void* addr);
// Read a 16-bit value from the supplied bank and address through the far-read intrinsic.
u16 far_data_read16(u8 bank, const void* addr);
// Copy len bytes from banked ROM into caller-owned writable storage.
void far_data_read(u8 bank, const void* addr, void* dst, u16 len);
// Invoke a no-argument callback in its ROM bank, then restore the caller
// bank. The pointer must identify executable code; no arguments are forwarded.
void far_call(u8 bank, const void* func);
// Store a bank/address pair without accessing ROM; a null output pointer is ignored.
void farptr_make(BankPtr* out, u8 bank, const u8* ptr);
// Read one byte using both components of the bank-qualified pointer.
u8 farptr_read8(BankPtr ptr);
// Read a 16-bit value using both components of the bank-qualified pointer.
u16 farptr_read16(BankPtr ptr);
// Copy len bytes from a bank-qualified pointer; dst must have room for the full copy.
void farptr_read(BankPtr ptr, void* dst, u16 len);

kitaqgb/lib/bank.h

camera.h — 월드 좌표와 가시 영역
c
#pragma once

#include "scroll.h"

// All position, target and bound fields use signed Q8.8 (-128 to just below 128 pixels).
// Pass initialized, non-null storage; world/screen conversion arguments use integer pixels.
typedef struct Camera8_8 {
    s16 fx;
    s16 fy;
    s16 target_fx;
    s16 target_fy;
    s16 min_fx;
    s16 min_fy;
    s16 max_fx;
    s16 max_fy;
    u8 use_target;
    u8 use_bounds;
} Camera8_8;

// Zero all position/target/bound fields and disable targeting and bounds.
void Camera_Init(Camera8_8* cam);
// Replace the current Q8.8 position and immediately apply enabled bounds.
void Camera_Set(Camera8_8* cam, s16 fx, s16 fy);
// Store a Q8.8 target and enable subsequent step-toward-target updates.
void Camera_SetTarget(Camera8_8* cam, s16 fx, s16 fy);
// Disable target following without moving the camera or erasing the stored target.
void Camera_ClearTarget(Camera8_8* cam);
// Install ordered Q8.8 bounds, enable them and clamp the current position immediately.
void Camera_SetBounds(Camera8_8* cam, s16 min_fx, s16 min_fy, s16 max_fx, s16 max_fy);
// Disable clamping while retaining the stored bounds and current position.
void Camera_ClearBounds(Camera8_8* cam);
// Add Q8.8 deltas and clamp afterward. Keep the intermediate sums within s16;
// clamping cannot repair arithmetic that already overflowed.
void Camera_Add(Camera8_8* cam, s16 dfx, s16 dfy);
// Move by the signed target delta shifted by 0..7 bits, then apply bounds.
// Quantization can make a small delta produce no movement; only exact equality
// clears targeting, and a target outside the bounds may remain active indefinitely.
void Camera_StepTowardTarget(Camera8_8* cam, u8 shift);
// Discard fractional bits and write the low eight integer bits to background scroll registers.
void Camera_ApplyBg(const Camera8_8* cam);
// Convert the Q8.8 position to byte scroll values and stage them for a later flush.
void Camera_ApplyBgBuffered(const Camera8_8* cam);
// Derive nonnegative camera extents from world minus screen size, then convert
// them to Q8.8 bounds. Extents must fit signed Q8.8; the u16 input type does
// not imply support for arbitrary large worlds.
void Camera_ClampToSize(Camera8_8* cam, u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);
// Convert an integer-pixel world X by subtracting the camera's integer X component.
s16 Camera_WorldToScreenX(const Camera8_8* cam, s16 world_x);
// Convert an integer-pixel world Y by subtracting the camera's integer Y component.
s16 Camera_WorldToScreenY(const Camera8_8* cam, s16 world_y);
// Convert integer-pixel screen X back to world X using the camera's integer component.
s16 Camera_ScreenToWorldX(const Camera8_8* cam, s16 screen_x);
// Convert integer-pixel screen Y back to world Y using the camera's integer component.
s16 Camera_ScreenToWorldY(const Camera8_8* cam, s16 screen_y);

// Set the shared camera from integer pixels, converting to the representable Q8.8 range.
void camera_set(s16 x, s16 y);
// Position the shared camera so the world point appears at the requested screen
// anchor. This is an immediate move, not the smoothed target-following path.
void camera_follow_xy(s16 x, s16 y, u8 screen_cx, u8 screen_cy);
// Derive and apply world/screen bounds to the shared convenience camera.
void camera_clamp(u16 world_w_px, u16 world_h_px, u8 screen_w_px, u8 screen_h_px);
// Write the shared camera's current integer position to background scroll registers.
void camera_apply();
// Convert integer-pixel world X using the shared convenience camera.
s16 camera_world_to_screen_x(s16 world_x);
// Convert integer-pixel world Y using the shared convenience camera.
s16 camera_world_to_screen_y(s16 world_y);

kitaqgb/lib/camera.h

cgb_palette.h — CGB 배경·OBJ 팔레트
c
#pragma once

// High-level CGB palette helpers for KITAQGB.
// Palette writes no-op on DMG; RGB packing works on either hardware model.

// Safe here means CGB hardware gating. Palette data writes still require an accessible
// PPU phase (for example LCD off or a sufficiently short VBlank update).
u8 __cgb_is_cgb();
void __cgb_safe_set_bcps(u8 value);
void __cgb_safe_set_bcpd(u8 value);
void __cgb_safe_set_ocps(u8 value);
void __cgb_safe_set_ocpd(u8 value);

// Mask each component to five bits: red in 0..4, green in 5..9, blue in 10..14.
// These macros wrap oversized components rather than saturating them.
#define CGB_RGB15(r5, g5, b5) ((u16)((u16)((r5) & 31) | ((u16)((g5) & 31) << 5) | ((u16)((b5) & 31) << 10)))

// Pack the red, green and blue components using the public RGB15 macro.
u16 cgb_rgb15(u8 r5, u8 g5, u8 b5);

// Set one background color through the indexed palette wrapper.
void cgb_bg_color(u8 palette_index, u8 color_index, u16 rgb15);
// Set one object color through the indexed palette wrapper.
void cgb_obj_color(u8 palette_index, u8 color_index, u16 rgb15);
// Pack component values and write one background color.
void cgb_bg_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);
// Pack component values and write one object color.
void cgb_obj_rgb(u8 palette_index, u8 color_index, u8 r5, u8 g5, u8 b5);

// Write background colors starting at the indexed slot. The range may cross
// palette boundaries and is clamped only at the end of all 32 slots.
void cgb_bg_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);
// Write object colors from the indexed slot, potentially crossing into later palettes.
void cgb_obj_colors(u8 palette_index, u8 start_color_index, const u16* colors, u8 color_count);

// Write four consecutive colors for one background palette.
void cgb_bg_palette(u8 palette_index, const u16* colors);
// Write four consecutive colors for one object palette.
void cgb_obj_palette(u8 palette_index, const u16* colors);

// Expose sequential background writes using an absolute color-slot index.
void cgb_bg_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);
// Expose sequential object writes using an absolute color-slot index.
void cgb_obj_colors_raw(u8 start_color_slot, const u16* colors, u8 color_count);

kitaqgb/lib/cgb_palette.h

cgb_tile.h — CGB 타일 번호와 속성
c
#pragma once

// Declarations for compiler-intrinsic CGB tile helpers.
// Canonical intrinsic entry points use the "__" prefix.
// Attr writes no-op on DMG. Combined tile+attr writes still write the tile on DMG.

// These helpers emit compiler code; cgb_tile.c has no runtime bodies. Scalar coordinates address 32x32 maps.
// Safe write paths poll VRAM access; LCD-on paths can enable interrupts after writing.
// Use _unsafe/_fast only with caller-managed writable VRAM timing, especially inside an ISR.
// Tile writes use the selected VRAM bank; choose bank zero before combined tile/attribute operations.
#define KQ_CGB_ATTR_PAL_MASK 0x07
#define KQ_CGB_ATTR_BANK1 0x08
#define KQ_CGB_ATTR_XFLIP 0x20
#define KQ_CGB_ATTR_YFLIP 0x40
#define KQ_CGB_ATTR_PRIORITY 0x80

#define KQ_CGB_ATTR_NONE ((u8)0)
#define KQ_CGB_ATTR_PAL(n) ((u8)((n) & KQ_CGB_ATTR_PAL_MASK))
#define KQ_CGB_ATTR_BANK(bank) ((u8)((bank) ? KQ_CGB_ATTR_BANK1 : 0))
#define KQ_CGB_ATTR_XFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_XFLIP : 0))
#define KQ_CGB_ATTR_YFLIP_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_YFLIP : 0))
#define KQ_CGB_ATTR_PRIORITY_IF(enabled) ((u8)((enabled) ? KQ_CGB_ATTR_PRIORITY : 0))
#define KQ_CGB_ATTR(palette, bank, xflip, yflip, priority) ((u8)(((palette) & KQ_CGB_ATTR_PAL_MASK) | ((bank) ? KQ_CGB_ATTR_BANK1 : 0) | ((xflip) ? KQ_CGB_ATTR_XFLIP : 0) | ((yflip) ? KQ_CGB_ATTR_YFLIP : 0) | ((priority) ? KQ_CGB_ATTR_PRIORITY : 0)))

// Return the compiler/runtime CGB mode test as a byte Boolean.
u8 __cgb_is_cgb();
// Write the VRAM bank selection only on CGB. Safe here means hardware-mode guarded, not PPU-timed.
void __cgb_safe_set_vbk(u8 value);

// Write a tile number to map 9800, waiting for VRAM access when necessary.
void __settile(u8 x, u8 y, u8 tile);
// Write a tile number to map 9800 without waiting for writable VRAM.
void __settile_unsafe(u8 x, u8 y, u8 tile);
// Write at base+32*y+x with VRAM access checks; supply a valid tile-map base.
void __settileat(u16 base, u8 x, u8 y, u8 tile);
// Use an explicit map base without waiting for VRAM access.
void __settileat_unsafe(u16 base, u8 x, u8 y, u8 tile);
// Select the window map from LCDC bit 6, then write a tile with access checks.
void __settilewin(u8 x, u8 y, u8 tile);
// Select the LCDC window map and write without access waits.
void __settilewin_unsafe(u8 x, u8 y, u8 tile);
// Select the background map from LCDC bit 3, then write with access checks.
void __settilebg(u8 x, u8 y, u8 tile);
// Select the LCDC background map and write without access waits.
void __settilebg_unsafe(u8 x, u8 y, u8 tile);

// Copy count sequential bytes to dest using the current VRAM bank and access-checked transfer.
void __settile_bulk(u16 dest, const u8* src, u8 count);
// Copy count sequential bytes to dest without VRAM access waits; retain source-bank visibility.
void __settile_bulk_fast(u16 dest, const u8* src, u8 count);

// Write attributes in bank one at map 9800 on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settileattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at map 9800 on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settileattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at map 9800; DMG receives only the tile write. Use the access-checked write path.
void __settilecgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at map 9800; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilecgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);

// Write attributes in bank one at the explicit map base on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settileatattr(u16 base, u8 x, u8 y, u8 attr);
// Write attributes in bank one at the explicit map base on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settileatattr_unsafe(u16 base, u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the explicit map base; DMG receives only the tile write. Use the access-checked write path.
void __settileatcgb(u16 base, u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the explicit map base; DMG receives only the tile write. No VRAM access waits are inserted.
void __settileatcgb_unsafe(u16 base, u8 x, u8 y, u8 tile, u8 attr);

// Write attributes in bank one at the LCDC window map on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settilewinattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at the LCDC window map on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settilewinattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the LCDC window map; DMG receives only the tile write. Use the access-checked write path.
void __settilewincgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the LCDC window map; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilewincgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);

// Write attributes in bank one at the LCDC background map on CGB, then leave VBK zero; skip on DMG. Use the access-checked write path.
void __settilebgattr(u8 x, u8 y, u8 attr);
// Write attributes in bank one at the LCDC background map on CGB, then leave VBK zero; skip on DMG. No VRAM access waits are inserted.
void __settilebgattr_unsafe(u8 x, u8 y, u8 attr);
// Write tile and CGB attributes at the LCDC background map; DMG receives only the tile write. Use the access-checked write path.
void __settilebgcgb(u8 x, u8 y, u8 tile, u8 attr);
// Write tile and CGB attributes at the LCDC background map; DMG receives only the tile write. No VRAM access waits are inserted.
void __settilebgcgb_unsafe(u8 x, u8 y, u8 tile, u8 attr);

// Copy count attributes to dest in bank one on CGB, then leave VBK zero; skip on DMG. Transfers use access checks.
void __settileattr_bulk(u16 dest, const u8* src, u8 count);
// Copy count attributes to dest in bank one on CGB, then leave VBK zero; skip on DMG. The caller supplies writable VRAM timing.
void __settileattr_bulk_fast(u16 dest, const u8* src, u8 count);
// Copy tile and attribute streams to dest; DMG receives only tiles. Keep both sources readable. Transfers use access checks.
void __settilecgb_bulk(u16 dest, const u8* tile_src, const u8* attr_src, u8 count);
// Copy tile and attribute streams to dest; DMG receives only tiles. Keep both sources readable. The caller supplies writable VRAM timing.
void __settilecgb_bulk_fast(u16 dest, const u8* tile_src, const u8* attr_src, u8 count);

kitaqgb/lib/cgb_tile.h

chain.h — 위치 이력용 링 버퍼
c
#pragma once

typedef __packed struct {
    s16 x;
    s16 y;
} ChainPoint;

typedef __packed struct {
    ChainPoint* points;
    u8 capacity;
    u8 count;
    u8 head;
} Chain;

// Attach caller-owned ring storage and start with no recorded points.
// The storage must remain valid for the lifetime of the chain.
// Use a valid chain pointer and capacity entries of caller-owned storage.
// Capacity at most 128 keeps every head+age sum in the byte range used by the reader.
void chain_init(Chain* chain, ChainPoint* storage, u8 capacity);
// Forget the recorded points without clearing or freeing the backing storage.
void chain_clear(Chain* chain);
// Move the ring head backward and store the newest point. Once full, each push
// replaces the oldest point; zero capacity is a no-op.
void chain_push_head(Chain* chain, s16 x, s16 y);
// Read a point by age, with index zero denoting the newest point. Return zero
// for an invalid request and clear a non-null output first. Keep head + index
// within the 8-bit range: addition is narrowed before the capacity wrap.
u8 chain_get_segment(const Chain* chain, u8 index, ChainPoint* out);
// Return the number of stored points, or zero for a null chain.
u8 chain_get_count(const Chain* chain);

// Return target minus current along the shortest wrapped route.
// Supply size 1..256 and coordinates in 0..size-1; inputs are not normalized.
// Exactly half a field retains the direct displacement sign.
s16 chain_wrap_delta(u8 target, u8 current, u16 size);

// Articulated body: one current pose per joint, including the head at index 0.
// Caller-owned byte arrays keep the inner loop compact on both GB and FC.
// Heading sectors run clockwise: 0=right, 4=down, 8=left, 12=up.
// Coordinates are pixels; each wrapped dimension accepts 1..256 pixels.
typedef __packed struct {
    u8* x;
    u8* y;
    u8* heading;
    u8 capacity;
    u8 count;
    u16 width;
    u16 height;
} ChainBody;

// Attach three non-overlapping capacity-byte arrays. Return 1 on success.
// Invalid storage, zero capacity or dimensions outside 1..256 disable the body.
u8 chain_body_init(ChainBody* body, u8* x, u8* y, u8* heading, u8 capacity, u16 width, u16 height);
// Seed count joints in a straight pose behind the head; count includes the head.
// Return 0 without changing the pose if count is zero or exceeds capacity.
// Coordinates wrap to the playfield and headings are masked to 0..15.
u8 chain_body_reset(ChainBody* body, u8 count, u8 head_x, u8 head_y, u8 heading);
// Install the caller's head pose, then pull joints from front to rear.
// Each joint aims four pixels behind its updated predecessor and receives that
// predecessor's OLD heading. Each axis moves 1 pixel, or 2 when error exceeds 4.
// Call once per simulation tick; this does not advance head physics or render.
void chain_body_step(ChainBody* body, u8 head_x, u8 head_y, u8 heading);
// Append a copy of the current tail; later steps separate the new joint.
// Return 1 on growth, or 0 for an empty, disabled or full body.
u8 chain_body_grow(ChainBody* body);
// Remove all joints while retaining caller-owned storage and playfield settings.
void chain_body_clear(ChainBody* body);

kitaqgb/lib/chain.h

danmaku.h — 탄환 풀, 부채꼴 발사, 충돌, 스침
c
#pragma once

// Fixed-capacity, allocation-free bullet field for a 160 x 128 play area.
// Positions/velocities are signed Q12.4 / Q4.4; +Y points down.
// Tile ids 0..15 encode the four 4x4 quadrants of an 8x8 tile.
// Reserve those tiles in VRAM, with a 3x3 bullet centered at (2,2)
// in every set quadrant. Other tile ids in the map are decoration.
#define DANMAKU_MAX 96
#define DANMAKU_MAP_BYTES 576
typedef __packed struct {
    s16 x;
    s16 y;
    s8 vx;
    s8 vy;
    u8 active;
    u8 grazed;
} DanmakuBullet;

extern DanmakuBullet dm_bullets[DANMAKU_MAX];
extern __wram __aligned(16) u8 dm_map[DANMAKU_MAP_BYTES];
extern u8 dm_count;
extern u8 dm_peak;
// Per-step hit is a Boolean latch; graze counts newly grazed bullets this step. Spawn/rejection counters wrap at 65536.
extern u8 dm_hit;
extern u8 dm_graze;
extern u8 dm_player_x;
extern u8 dm_player_y;
extern u8 dm_invulnerable;
extern u16 dm_spawned;
extern u16 dm_rejected;

// Reset pool, peak and lifetime counters; player fields and map contents remain caller-owned state.
void danmaku_reset();
// Deactivate the pool while retaining peak/spawn/rejection counters and the RAM map.
void danmaku_clear();
// Use pixel origins inside 160x128 and signed sixteenth-pixel velocities; return one if a slot was allocated.
u8 danmaku_spawn(u8 x, u8 y, s8 vx, s8 vy);
// Attempt a fan using wrapping 32-step angles; count is capped at 96 and speed at 64.
void danmaku_fan(u8 x, u8 y, u8 direction, u8 step, u8 count, u8 speed);
// 32 directions, 0=right, 8=down, 16=left, 24=up. speed in 1/16 px.
// Clear the 32x18 RAM map before drawing the next frame; no transfer is performed.
void danmaku_clear_map();
// Caller fills decoration after clear_map, then calls step to overlay bullets.
// hit and graze are events for this step. Collision uses rendered centers.
void danmaku_step();
// Requires CGB and LCD off or the beginning of VBlank. VBK restored to 0.
// Transfers 18 rows (32-byte stride) to BG map 9800 with 36-block GDMA.
void danmaku_present_now();

kitaqgb/lib/danmaku.h

debug.h — RAM 기록과 단언
c
#pragma once

// Use a capacity from 1 through 255; the length counter is a byte.
// Compile every unit with the same override so the array declaration and storage agree.
#ifndef DEBUG_TRACE_MAX
#define DEBUG_TRACE_MAX 32
#endif

// Each packed entry retains a name pointer and two 16-bit values; name text is not copied.
typedef __packed struct {
    const u8* name;
    u16 value;
    u16 frame;
} DebugTraceEntry;

extern DebugTraceEntry kq_debug_trace_log[DEBUG_TRACE_MAX];
extern u8 kq_debug_trace_count;
extern u16 kq_debug_frame;
extern u16 kq_debug_last_assert;

// Reset log length, frame tag and last assertion code; existing entry bytes are not erased.
void debug_init();
// Set the frame tag copied into subsequently recorded entries.
void debug_set_frame(u16 frame);
// Append a named frame marker using 0xFFFF as its value.
void debug_mark_frame(const u8* label);
// Append an unsigned byte value, widened to the log's 16-bit value field.
void debug_trace_u8(const u8* name, u8 value);
// Append a 16-bit value with the current frame tag.
void debug_trace_u16(const u8* name, u16 value);
// Record the assertion code and attempt to append an ASSERT entry. This helper
// does not halt execution, and the code is retained even if the log is full.
void debug_assert_fail(u16 code);
// Return the number of valid entries in the fixed trace buffer.
u8 debug_get_trace_count();
// Expose the internal trace array for inspection; use the count to bound reads.
const DebugTraceEntry* debug_get_trace_log();
// Read the last recorded assertion code, or the zero value installed by initialization.
u16 debug_get_last_assert();

#define KITAQGB_TRACE_U8(name, value) debug_trace_u8((const u8*)(name), (u8)(value))
#define KITAQGB_TRACE_U16(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
#define KITAQGB_TRACE(name, value) debug_trace_u16((const u8*)(name), (u16)(value))
#define KITAQGB_MARK_FRAME(label) debug_mark_frame((const u8*)(label))
#define KITAQGB_ASSERT(cond) do { if (!(cond)) debug_assert_fail((u16)1); } while (0)
#define KITAQGB_ASSERT_CODE(cond, code) do { if (!(cond)) debug_assert_fail((u16)(code)); } while (0)

kitaqgb/lib/debug.h

dmg3d.h — DMG용 128×120 단색 와이어프레임
c
// Compatibility names for the shared wire3d_dmg renderer.
// Select the same profile in every translation unit; compile one renderer entry.
#pragma once
#ifndef WIRE3D_DMG_HEIGHT
#define WIRE3D_DMG_HEIGHT 120
#endif
#if WIRE3D_DMG_HEIGHT != 120
#error Incompatible wire3d_dmg profile
#endif
#include "wire3d_dmg.h"

// The aliases below add no calls or storage. Their contracts are documented at the corresponding wire3d_dmg.h declarations.
#define DMG3D_ANGLE_STEPS WIRE3D_DMG_ANGLE_STEPS
#define DMG3D_AUX_COL_BYTES WIRE3D_DMG_AUX_COL_BYTES
#define DMG3D_AUX_ROWS WIRE3D_DMG_AUX_ROWS
#define DMG3D_BG_QUEUE_LIMIT WIRE3D_DMG_BG_QUEUE_LIMIT
#define DMG3D_BeginFrame Wire3DDMG_BeginFrame
#define DMG3D_CENTER_X WIRE3D_DMG_CENTER_X
#define DMG3D_CENTER_Y WIRE3D_DMG_CENTER_Y
#define DMG3D_DrawIndexedEdges Wire3DDMG_DrawIndexedEdges
#define DMG3D_DrawLine2D Wire3DDMG_DrawLine2D
#define DMG3D_DrawLine3D Wire3DDMG_DrawLine3D
#define DMG3D_DrawModel Wire3DDMG_DrawModel
#define DMG3D_DrawModelScaled Wire3DDMG_DrawModelScaled
#define DMG3D_DrawScene Wire3DDMG_DrawScene
#define DMG3D_Edge Wire3DDMG_Edge
#define DMG3D_EdgeFaces Wire3DDMG_EdgeFaces
#define DMG3D_EndFrame Wire3DDMG_EndFrame
#define DMG3D_EraseModelFaces Wire3DDMG_EraseModelFaces
#define DMG3D_EraseSpan2D Wire3DDMG_EraseSpan2D
#define DMG3D_EraseTriangle2D Wire3DDMG_EraseTriangle2D
#define DMG3D_FACE_NONE WIRE3D_DMG_FACE_NONE
#define DMG3D_FAR_Z WIRE3D_DMG_FAR_Z
#define DMG3D_Face Wire3DDMG_Face
#define DMG3D_Init Wire3DDMG_Init
#define DMG3D_MODEL_FACE_LIMIT WIRE3D_DMG_MODEL_FACE_LIMIT
#define DMG3D_MODEL_HIDDEN_LINES WIRE3D_DMG_MODEL_HIDDEN_LINES
#define DMG3D_MODEL_VERTEX_LIMIT WIRE3D_DMG_MODEL_VERTEX_LIMIT
#define DMG3D_Model Wire3DDMG_Model
#define DMG3D_NEAR_Z WIRE3D_DMG_NEAR_Z
#define DMG3D_Object Wire3DDMG_Object
#define DMG3D_PROJECT_LIMIT WIRE3D_DMG_PROJECT_LIMIT
#define DMG3D_ProjectPoint Wire3DDMG_ProjectPoint
#define DMG3D_PutBgTile Wire3DDMG_PutBgTile
#define DMG3D_ROW_BYTES WIRE3D_DMG_ROW_BYTES
#define DMG3D_RotatePoint Wire3DDMG_RotatePoint
#define DMG3D_SCENE_OBJECT_LIMIT WIRE3D_DMG_SCENE_OBJECT_LIMIT
#define DMG3D_SCREEN_H WIRE3D_DMG_SCREEN_H
#define DMG3D_SCREEN_W WIRE3D_DMG_SCREEN_W
#define DMG3D_SetAuxTransfer Wire3DDMG_SetAuxTransfer
#define DMG3D_SetCamera Wire3DDMG_SetCamera
#define DMG3D_SetDirtyTransfer Wire3DDMG_SetDirtyTransfer
#define DMG3D_SetPalette Wire3DDMG_SetPalette
#define DMG3D_TILE_H WIRE3D_DMG_TILE_H
#define DMG3D_TILE_W WIRE3D_DMG_TILE_W
#define DMG3D_TRANSFORM_LIMIT WIRE3D_DMG_TRANSFORM_LIMIT
#define DMG3D_TransferAuxNow Wire3DDMG_TransferAuxNow
#define DMG3D_TransferMainNow Wire3DDMG_TransferMainNow
#define DMG3D_Vec3 Wire3DDMG_Vec3
// The remaining aliases retain internal identifiers for source compatibility; they do not define an independent renderer.
#define DMG3D_abs_i16 w3ddmg_abs_i16
#define DMG3D_angle_index w3ddmg_angle_index
#define DMG3D_aux_transfer_enabled w3ddmg_aux_transfer_enabled
#define DMG3D_bg_map_9800 w3ddmg_bg_map_9800
#define DMG3D_bgq_addr_hi w3ddmg_bgq_addr_hi
#define DMG3D_bgq_addr_lo w3ddmg_bgq_addr_lo
#define DMG3D_bgq_count w3ddmg_bgq_count
#define DMG3D_bgq_tile w3ddmg_bgq_tile
#define DMG3D_bgq_value w3ddmg_bgq_value
#define DMG3D_bgq_x w3ddmg_bgq_x
#define DMG3D_bgq_y w3ddmg_bgq_y
#define DMG3D_bit_mask w3ddmg_bit_mask
#define DMG3D_build_face_visibility w3ddmg_build_face_visibility
#define DMG3D_cam_pitch w3ddmg_cam_pitch
#define DMG3D_cam_roll w3ddmg_cam_roll
#define DMG3D_cam_x w3ddmg_cam_x
#define DMG3D_cam_y w3ddmg_cam_y
#define DMG3D_cam_yaw w3ddmg_cam_yaw
#define DMG3D_cam_z w3ddmg_cam_z
#define DMG3D_clamp_i16 w3ddmg_clamp_i16
#define DMG3D_clamp_screen w3ddmg_clamp_screen
#define DMG3D_clear_dirty_tables w3ddmg_clear_dirty_tables
#define DMG3D_clear_occlusion_mask w3ddmg_clear_occlusion_mask
#define DMG3D_clear_occlusion_mask_asm w3ddmg_clear_occlusion_mask_asm
#define DMG3D_clear_stage_asm w3ddmg_clear_stage_asm
#define DMG3D_clear_stage_aux_asm w3ddmg_clear_stage_aux_asm
#define DMG3D_clear_triangle w3ddmg_clear_triangle
#define DMG3D_clear_vram_asm w3ddmg_clear_vram_asm
#define DMG3D_cos_q6 w3ddmg_cos_q6
#define DMG3D_dirty_dst_hi w3ddmg_dirty_dst_hi
#define DMG3D_dirty_dst_lo w3ddmg_dirty_dst_lo
#define DMG3D_dirty_src_hi w3ddmg_dirty_src_hi
#define DMG3D_dirty_src_lo w3ddmg_dirty_src_lo
#define DMG3D_dirty_tiles w3ddmg_dirty_tiles
#define DMG3D_dirty_transfer_enabled w3ddmg_dirty_transfer_enabled
#define DMG3D_edge_area w3ddmg_edge_area
#define DMG3D_face_visible w3ddmg_face_visible
#define DMG3D_fill_bg_map_asm w3ddmg_fill_bg_map_asm
#define DMG3D_flush_bg_queue w3ddmg_flush_bg_queue
#define DMG3D_i16 w3ddmg_i16
#define DMG3D_i8 w3ddmg_i8
#define DMG3D_inv_depth w3ddmg_inv_depth
#define DMG3D_is_edge_visible w3ddmg_is_edge_visible
#define DMG3D_line_dx w3ddmg_line_dx
#define DMG3D_line_dy w3ddmg_line_dy
#define DMG3D_line_err w3ddmg_line_err
#define DMG3D_line_stage_asm w3ddmg_line_stage_asm
#define DMG3D_line_stage_masked_c w3ddmg_line_stage_masked_c
#define DMG3D_line_sx w3ddmg_line_sx
#define DMG3D_line_sy w3ddmg_line_sy
#define DMG3D_line_x w3ddmg_line_x
#define DMG3D_line_x0 w3ddmg_line_x0
#define DMG3D_line_x1 w3ddmg_line_x1
#define DMG3D_line_y w3ddmg_line_y
#define DMG3D_line_y0 w3ddmg_line_y0
#define DMG3D_line_y1 w3ddmg_line_y1
#define DMG3D_mark_line_dirty w3ddmg_mark_line_dirty
#define DMG3D_mark_model_occluder w3ddmg_mark_model_occluder
#define DMG3D_mark_rect_dirty w3ddmg_mark_rect_dirty
#define DMG3D_mark_tile_dirty w3ddmg_mark_tile_dirty
#define DMG3D_mark_triangle w3ddmg_mark_triangle
#define DMG3D_mask_get w3ddmg_mask_get
#define DMG3D_mask_offset w3ddmg_mask_offset
#define DMG3D_mask_set w3ddmg_mask_set
#define DMG3D_mask_set_span w3ddmg_mask_set_span
#define DMG3D_neg_angle w3ddmg_neg_angle
#define DMG3D_occlusion_active w3ddmg_occlusion_active
#define DMG3D_occlusion_mask w3ddmg_occlusion_mask
#define DMG3D_plot_stage_asm w3ddmg_plot_stage_asm
#define DMG3D_plot_tx w3ddmg_plot_tx
#define DMG3D_plot_x w3ddmg_plot_x
#define DMG3D_plot_y w3ddmg_plot_y
#define DMG3D_prev_dirty_tiles w3ddmg_prev_dirty_tiles
#define DMG3D_project_camera_space w3ddmg_project_camera_space
#define DMG3D_project_world w3ddmg_project_world
#define DMG3D_put_bg_tile_safe_asm w3ddmg_put_bg_tile_safe_asm
#define DMG3D_reg_bgp w3ddmg_reg_bgp
#define DMG3D_reg_lcdc w3ddmg_reg_lcdc
#define DMG3D_reg_ly w3ddmg_reg_ly
#define DMG3D_reg_scx w3ddmg_reg_scx
#define DMG3D_reg_scy w3ddmg_reg_scy
#define DMG3D_rotate_x w3ddmg_rotate_x
#define DMG3D_rotate_y w3ddmg_rotate_y
#define DMG3D_rotate_z w3ddmg_rotate_z
#define DMG3D_scene_depth w3ddmg_scene_depth
#define DMG3D_scene_object_depth w3ddmg_scene_object_depth
#define DMG3D_scene_order w3ddmg_scene_order
#define DMG3D_screen_delta w3ddmg_screen_delta
#define DMG3D_screen_visible w3ddmg_screen_visible
#define DMG3D_screen_x w3ddmg_screen_x
#define DMG3D_screen_y w3ddmg_screen_y
#define DMG3D_sin_q6 w3ddmg_sin_q6
#define DMG3D_stage w3ddmg_stage
#define DMG3D_stage_clear_pixel w3ddmg_stage_clear_pixel
#define DMG3D_stage_clear_span w3ddmg_stage_clear_span
#define DMG3D_transfer_dirty_stage w3ddmg_transfer_dirty_stage
#define DMG3D_transfer_dirty_tile_asm w3ddmg_transfer_dirty_tile_asm
#define DMG3D_transfer_stage_asm w3ddmg_transfer_stage_asm
#define DMG3D_transfer_stage_aux_asm w3ddmg_transfer_stage_aux_asm
#define DMG3D_u16 w3ddmg_u16
#define DMG3D_u8 w3ddmg_u8
#define DMG3D_vram_tiles w3ddmg_vram_tiles
#define DMG3D_wait_vblank_start w3ddmg_wait_vblank_start
#define dmg3d w3ddmg
#define dmg3d_pair_aux_block w3ddmg_pair_aux_block
#define dmg3d_pair_aux_done w3ddmg_pair_aux_done
#define dmg3d_pair_aux_wait_0 w3ddmg_pair_aux_wait_0
#define dmg3d_pair_aux_wait_1 w3ddmg_pair_aux_wait_1
#define dmg3d_pair_aux_wait_10 w3ddmg_pair_aux_wait_10
#define dmg3d_pair_aux_wait_11 w3ddmg_pair_aux_wait_11
#define dmg3d_pair_aux_wait_12 w3ddmg_pair_aux_wait_12
#define dmg3d_pair_aux_wait_13 w3ddmg_pair_aux_wait_13
#define dmg3d_pair_aux_wait_14 w3ddmg_pair_aux_wait_14
#define dmg3d_pair_aux_wait_15 w3ddmg_pair_aux_wait_15
#define dmg3d_pair_aux_wait_16 w3ddmg_pair_aux_wait_16
#define dmg3d_pair_aux_wait_17 w3ddmg_pair_aux_wait_17
#define dmg3d_pair_aux_wait_18 w3ddmg_pair_aux_wait_18
#define dmg3d_pair_aux_wait_19 w3ddmg_pair_aux_wait_19
#define dmg3d_pair_aux_wait_2 w3ddmg_pair_aux_wait_2
#define dmg3d_pair_aux_wait_20 w3ddmg_pair_aux_wait_20
#define dmg3d_pair_aux_wait_21 w3ddmg_pair_aux_wait_21
#define dmg3d_pair_aux_wait_22 w3ddmg_pair_aux_wait_22
#define dmg3d_pair_aux_wait_23 w3ddmg_pair_aux_wait_23
#define dmg3d_pair_aux_wait_24 w3ddmg_pair_aux_wait_24
#define dmg3d_pair_aux_wait_25 w3ddmg_pair_aux_wait_25
#define dmg3d_pair_aux_wait_26 w3ddmg_pair_aux_wait_26
#define dmg3d_pair_aux_wait_27 w3ddmg_pair_aux_wait_27
#define dmg3d_pair_aux_wait_3 w3ddmg_pair_aux_wait_3
#define dmg3d_pair_aux_wait_4 w3ddmg_pair_aux_wait_4
#define dmg3d_pair_aux_wait_5 w3ddmg_pair_aux_wait_5
#define dmg3d_pair_aux_wait_6 w3ddmg_pair_aux_wait_6
#define dmg3d_pair_aux_wait_7 w3ddmg_pair_aux_wait_7
#define dmg3d_pair_aux_wait_8 w3ddmg_pair_aux_wait_8
#define dmg3d_pair_aux_wait_9 w3ddmg_pair_aux_wait_9
#define dmg3d_pair_main_block w3ddmg_pair_main_block
#define dmg3d_pair_main_wait_0 w3ddmg_pair_main_wait_0
#define dmg3d_pair_main_wait_1 w3ddmg_pair_main_wait_1
#define dmg3d_pair_main_wait_10 w3ddmg_pair_main_wait_10
#define dmg3d_pair_main_wait_11 w3ddmg_pair_main_wait_11
#define dmg3d_pair_main_wait_12 w3ddmg_pair_main_wait_12
#define dmg3d_pair_main_wait_13 w3ddmg_pair_main_wait_13
#define dmg3d_pair_main_wait_14 w3ddmg_pair_main_wait_14
#define dmg3d_pair_main_wait_2 w3ddmg_pair_main_wait_2
#define dmg3d_pair_main_wait_3 w3ddmg_pair_main_wait_3
#define dmg3d_pair_main_wait_4 w3ddmg_pair_main_wait_4
#define dmg3d_pair_main_wait_5 w3ddmg_pair_main_wait_5
#define dmg3d_pair_main_wait_6 w3ddmg_pair_main_wait_6
#define dmg3d_pair_main_wait_7 w3ddmg_pair_main_wait_7
#define dmg3d_pair_main_wait_8 w3ddmg_pair_main_wait_8
#define dmg3d_pair_main_wait_9 w3ddmg_pair_main_wait_9
#define dmg3dac_col w3ddmgac_col
#define dmg3dac_enter w3ddmgac_enter
#define dmg3dac_row w3ddmgac_row
#define dmg3dbg_enter w3ddmgbg_enter
#define dmg3dco_enter w3ddmgco_enter
#define dmg3dco_loop w3ddmgco_loop
#define dmg3dco_page w3ddmgco_page
#define dmg3dcs_enter w3ddmgcs_enter
#define dmg3dcs_inner w3ddmgcs_inner
#define dmg3dcs_outer w3ddmgcs_outer
#define dmg3dcv_enter w3ddmgcv_enter
#define dmg3dcv_loop w3ddmgcv_loop
#define dmg3dcv_page w3ddmgcv_page
#define dmg3ddt_enter w3ddmgdt_enter
#define dmg3ddt_loop w3ddmgdt_loop
#define dmg3dfb_enter w3ddmgfb_enter
#define dmg3dfb_loop w3ddmgfb_loop
#define dmg3dfb_page w3ddmgfb_page
#define dmg3dls_branch w3ddmgls_branch
#define dmg3dls_done w3ddmgls_done
#define dmg3dls_enter w3ddmgls_enter
#define dmg3dls_shallow w3ddmgls_shallow
#define dmg3dls_shallow_loop w3ddmgls_shallow_loop
#define dmg3dls_shallow_skip_bridge w3ddmgls_shallow_skip_bridge
#define dmg3dls_steep w3ddmgls_steep
#define dmg3dls_steep_loop w3ddmgls_steep_loop
#define dmg3dls_steep_skip_bridge w3ddmgls_steep_skip_bridge
#define dmg3dls_x_reverse w3ddmgls_x_reverse
#define dmg3dls_y_reverse w3ddmgls_y_reverse
#define dmg3dls_y_start w3ddmgls_y_start
#define dmg3dps_enter w3ddmgps_enter
#define dmg3dps_ret w3ddmgps_ret

kitaqgb/lib/dmg3d.h

entity.h — 고정 배열 기반 오브젝트 풀
c
#pragma once

// Keep capacity in 1..255: IDs and scan counters are bytes and FF is reserved for failure.
// Use the same definition in every compilation unit.
#ifndef ENTITY_MAX
#define ENTITY_MAX ((u8)16)
#endif

// Position, velocity, state and timer units are game-defined; the pool does not advance them.
// The sprite field is only bookkeeping and does not allocate or release OAM entries.
typedef __packed struct {
    u8 active;
    u8 type;
    s16 x;
    s16 y;
    s16 vx;
    s16 vy;
    u8 state;
    u8 timer;
    u8 sprite;
} Entity;

// An entity callback receives a slot ID, not a persistent object handle.
typedef void (*EntityFn)(u8 id);

// Reset every slot before the game starts using the pool.
void entity_init();
// Returns a reusable slot ID, or 0xFF if no slot is free.
u8 entity_create(u8 type, s16 x, s16 y);
// Release a valid slot without clearing its payload. Reallocation resets the payload;
// a saved pointer or ID must not be treated as a persistent entity identity.
void entity_destroy(u8 id);
// Returns null for an invalid or inactive ID; the returned pointer aliases reusable pool storage.
Entity* entity_get(u8 id);
// Call fn for each slot that is active when the scan reaches it; null is a no-op.
// Callbacks may change the pool, so newly activated later slots can run in this pass.
void entity_update_all(EntityFn fn);
// Use the same active-slot traversal for drawing; the callback supplies all rendering.
void entity_draw_all(EntityFn fn);
// Count occupied slots without changing entity state.
u8 entity_count_active();
// Release every entity and restore deterministic defaults, including the no-sprite sentinel.
void entity_clear_all();

kitaqgb/lib/entity.h

fixed.h — Q8.8 고정소수점 연산과 사각형
c
#pragma once

// Signed Q8.8 uses 256 units per pixel/value: the range is -128 to 127 + 255/256.
typedef s16 fix8;

#define FIX_ONE ((fix8)256)
#define FIX_HALF ((fix8)128)

typedef __packed struct {
    fix8 x;
    fix8 y;
} Vec2;

typedef __packed struct {
    s16 x;
    s16 y;
    s16 w;
    s16 h;
} KQRect;

// Convert an integer to signed 8.8 fixed point by moving it into the high byte.
// The caller must keep the result within the representable 16-bit range.
fix8 fix_from_int(s16 n);
// Discard the eight fractional bits using a signed right shift.
s16 fix_to_int(fix8 x);
// Approximate 8.8 multiplication by discarding four low bits from each operand
// before multiplying. This trades precision for a smaller intermediate product.
fix8 fix_mul(fix8 a, fix8 b);
// Scale the reduced-precision quotient back to 8.8 and return zero for b == 0.
// Callers must also ensure (b >> 4) is nonzero; the explicit check only tests b.
// The intermediate product must fit the compiler's integer arithmetic.
fix8 fix_div(fix8 a, fix8 b);
// Interpolate toward b using a quantized Q0.8 weight. Both shifts discard low
// bits, so small changes may vanish and a weight of 255 need not reach b.
fix8 fix_lerp(fix8 a, fix8 b, u8 t_q8);
// Return the magnitude in s16. The most-negative s16 has no positive s16
// representation and must be excluded by callers needing a nonnegative result.
s16 kq_abs_s16(s16 v);
// Select the smaller signed value.
s16 kq_min_s16(s16 a, s16 b);
// Select the larger signed value.
s16 kq_max_s16(s16 a, s16 b);
// Clamp to an inclusive interval; callers must provide lo <= hi.
s16 kq_clamp_s16(s16 v, s16 lo, s16 hi);
// Test overlap using exclusive right/bottom edges; touching edges do not collide.
// Require positive dimensions and edge sums that fit s16; zero-sized rectangles
// are not explicitly rejected and may be reported as overlapping.
u8 kq_rect_intersect(KQRect a, KQRect b);
// Test a half-open rectangle: left/top edges are included, right/bottom excluded.
// The coordinate-plus-size sums must remain representable as s16.
u8 kq_point_in_rect(s16 x, s16 y, KQRect r);

kitaqgb/lib/fixed.h

input.h — 버튼 상태, 누름, 놓음, 반복 입력
c
#pragma once

#define BTN_RIGHT  ((u8)0x01)
#define BTN_LEFT   ((u8)0x02)
#define BTN_UP     ((u8)0x04)
#define BTN_DOWN   ((u8)0x08)
#define BTN_A      ((u8)0x10)
#define BTN_B      ((u8)0x20)
#define BTN_SELECT ((u8)0x40)
#define BTN_START  ((u8)0x80)

// A fresh press pulses immediately. The next pulse occurs DELAY + 1 updates later.
#ifndef INPUT_REPEAT_DELAY
#define INPUT_REPEAT_DELAY ((u8)18)
#endif

// Subsequent pulses are RATE + 1 updates apart; zero repeats on every held update.
#ifndef INPUT_REPEAT_RATE
#define INPUT_REPEAT_RATE ((u8)5)
#endif

extern u8 kq_input_prev_keys;
extern u8 kq_input_keys;
extern u8 kq_input_press_keys;
extern u8 kq_input_release_keys;
extern u8 kq_input_repeat_keys;

u16 __readpadex(u8 prev_keys);

// Clear sampled/edge state and initialize an independent repeat timer for each button.
void input_init();
// Sample input once per game tick and derive press, release and repeat masks.
// Repeat delays are measured in calls to this function, not elapsed wall-clock time.
void input_update();
// Return whether any masked button is currently held.
u8 input_down(u8 mask);
// Return whether any masked button became pressed in the latest sample.
u8 input_pressed(u8 mask);
// Return whether any masked button became released in the latest sample.
u8 input_released(u8 mask);
// Return whether any masked button produced a fresh press or scheduled repeat pulse.
u8 input_repeat(u8 mask);
// Return the complete held-button mask from the latest update.
u8 input_current();
// Return the held-button mask that preceded the latest update.
u8 input_previous();

#define btn_down input_down
#define btn_pressed input_pressed
#define btn_released input_released
#define btn_repeat input_repeat

kitaqgb/lib/input.h

link.h — 시리얼 통신과 논리 패킷
c
#pragma once

// Shared Game Boy serial link library for KITAQGB projects.
//
// Integration notes:
// - Compile a hardware-register file before link.c / link_packet.c so SB, SC,
//   IF_REG, and IE_REG are already declared.
// - Call Link_InitMaster() on the clock-source side and Link_InitSlave() on the
//   other side.
// - Call Link_Poll() or Link_PollPacket() regularly from the main loop.
// - If you enable serial IRQ mode, call Link_OnSerialIRQ() from your own
//   serial interrupt handler at vector 0x0058.
// - The packet layer is intentionally small and one-deep. It works best as a
//   master-driven command/response layer. The low-level byte API remains the
//   escape hatch for custom protocols.

#define LINK_MODE_SLAVE   ((u8)0)
#define LINK_MODE_MASTER  ((u8)1)

#define LINK_CLOCK_NORMAL ((u8)0)
#define LINK_CLOCK_FAST   ((u8)1)

#define LINK_ERR_NONE        ((u8)0)
#define LINK_ERR_BUSY        ((u8)1)
#define LINK_ERR_TIMEOUT     ((u8)2)
#define LINK_ERR_OVERFLOW    ((u8)3)
#define LINK_ERR_PROTOCOL    ((u8)4)
#define LINK_ERR_DISCONNECT  ((u8)5)

#define LINK_PKT_MAX_PAYLOAD ((u8)24)
#define LINK_RX_QUEUE_SIZE   ((u8)8)
#define LINK_TX_QUEUE_SIZE   ((u8)8)

#define LINK4_MODE_NONE      ((u8)0)
#define LINK4_MODE_HOST      ((u8)1)
#define LINK4_MODE_PEER      ((u8)2)
#define LINK4_MAX_PLAYERS    ((u8)4)
#define LINK4_HOST_SLOT      ((u8)0)
#define LINK4_INVALID_SLOT   ((u8)0xFF)

// Reset byte queues, packet mailboxes, cooperative-peer state and errors, then
// disable serial transfers and serial IRQ delivery. Existing data is discarded.
void Link_InitCommon();
// Reset link state and select the internal-clock role for subsequent transfers.
void Link_InitMaster();
// Reset link state and select the external-clock role for subsequent transfers.
void Link_InitSlave();
// Enable or disable serial IRQ delivery and clear its pending flag. Enabling
// does not install the handler. Leaving its outer critical section enables CPU interrupts.
void __stackcall Link_SetUseInterrupt(u8 on);
// Select the fast-clock bit for future master transfers; this does not restart
// an active transfer or verify that the hardware supports CGB fast mode.
void __stackcall Link_SetFastClock(u8 on);

// Poll once before returning busy state, so this query may collect a completed byte.
u8 Link_IsBusy();
// Read the ordinary receive-ready flag without polling hardware.
u8 Link_HasByte();
// Return the latest latched error without clearing it.
u8 Link_LastError();
// Clear the error latch without resetting queues or an active transfer.
void Link_ClearError();

// Start one full-duplex byte exchange, or return BUSY without replacing an
// active transfer. Slave mode arms reception and waits for external clocks.
u8 __stackcall Link_BeginTransfer(u8 out);
// Collect a pending transfer only after hardware clears the SC start bit.
void Link_Poll();
// Stop the hardware transfer under interrupt protection. Queued receive bytes
// and packet-layer state remain available; this is not a full protocol reset.
void Link_Cancel();
// Acknowledge serial IRQ and finish a software-busy transfer. Call this from
// the actual serial interrupt handler, not an unrelated interrupt.
void Link_OnSerialIRQ();

// Pop the ordinary receive queue without waiting or polling hardware; null discards a byte.
u8 __stackcall Link_TryReadByte(u8 *out);
// Pop one byte, returning zero when empty. Use Link_TryReadByte when a received
// zero byte must be distinguished from an empty queue.
u8 Link_ReadByte();
// Require an output pointer, poll immediately, then wait at most timeout_frames
// VBlanks for a byte. Zero timeout still performs the initial poll and read.
u8 __stackcall Link_WaitByte(u16 timeout_frames, u8 *out);

// Validate payload size and idle packet state, copy payload bytes into owned
// storage and schedule transmission. Return success means queued, not acknowledged;
// keep polling to progress the exchange and inspect the error latch.
u8 __stackcall Link_SendPacket(const u8 *data, u8 len, u8 cmd);
// Drain received bytes, advance one outgoing exchange and update the retry
// timer. Timeout ticks count calls without progress, not hardware frames; call
// with a controlled cadence and avoid mixing raw reads with packet consumption.
void Link_PollPacket();
// Inspect the shared completed-packet flag without advancing the protocol.
u8 Link_HasPacket();
// Consume the shared packet mailbox and its matching peer flag. Any output
// may be null; a nonnull destination needs room for the received payload because
// there is no destination-capacity argument.
u8 __stackcall Link_ReadPacket(u8 *cmd, u8 *len, u8 *dst);

// Cooperative 4-player adapter helpers.
//
// This layer models the common host-selected adapter pattern:
// - Slot 0 is always the host.
// - The host selects one active peer slot at a time.
// - Packet mailboxes stay one-deep per peer.
// - The original Link_* API remains available for normal 2-player projects.
// Reset as master, validate slot count and select logical peer one. Invalid configuration still discards old link state.
u8 __stackcall Link4_InitHost(u8 slot_count);
// Reset as slave and validate the local nonzero slot and total slot count.
// An invalid configuration still discards the previous link state.
u8 __stackcall Link4_InitPeer(u8 local_slot, u8 slot_count);
// Return the configured cooperative role; this is not a hardware connection probe.
u8 Link4_GetMode();
// Return the configured zero-based local slot.
u8 Link4_GetLocalSlot();
// Return the configured number of logical slots, not a live connection count.
u8 Link4_GetSlotCount();
// Return the current logical destination, or the invalid-slot sentinel when unset.
u8 Link4_GetSelectedPeer();
// Return the peer attributed to the last completed byte transfer.
u8 Link4_GetLastRxPeer();
// Return the peer attributed when the last byte transfer was started.
u8 Link4_GetLastTxPeer();
// Poll completion, then change the logical destination only while byte and
// packet state are idle. A peer can select only the host. No adapter-routing
// command is sent here; the transport must provide the matching physical route.
u8 __stackcall Link4_SelectPeer(u8 peer_slot);
// Select the logical peer and start a byte exchange, returning the first error.
u8 __stackcall Link4_BeginTransferTo(u8 peer_slot, u8 out);
// Inspect a valid peer ring without polling the hardware.
u8 __stackcall Link4_HasByteFrom(u8 peer_slot);
// Pop one byte from the selected peer ring; null output discards it.
u8 __stackcall Link4_TryReadByteFrom(u8 peer_slot, u8 *out);
// Scan remote rings in increasing slot order and return the first available
// byte. Null output pointers are allowed; lower slots have polling priority.
u8 __stackcall Link4_TryReadByteAny(u8 *peer_slot, u8 *out);
// Select a logical peer, then copy and schedule a packet; return the first error.
u8 __stackcall Link4_SendPacketTo(u8 peer_slot, const u8 *data, u8 len, u8 cmd);
// Advance the shared packet engine; this does not poll every logical peer in turn.
void Link4_PollPacket();
// Inspect the one-packet mailbox for a valid remote slot without consuming it.
u8 __stackcall Link4_HasPacketFrom(u8 peer_slot);
// Consume a peer mailbox, copying to optional outputs. A nonnull destination
// needs room for the entire payload. Clear the shared mailbox only when it
// refers to this same peer.
u8 __stackcall Link4_ReadPacketFrom(u8 peer_slot, u8 *cmd, u8 *len, u8 *dst);

kitaqgb/lib/link.h

link_dmg07.h — DMG-07 외부 클록 통신
c
#pragma once

// Polling driver for the physical Nintendo DMG-07 Four Player Adapter.
//
// The adapter supplies every serial clock.  LinkDmg07_Poll() must therefore be
// called frequently enough to re-arm the serial port between adapter bytes;
// calling it only once per video frame is not sufficient.  Call
// LinkDmg07_TickFrame() exactly once per frame for timeout accounting.
//
// Transmission uses SIZE=1: every adapter packet contains four bytes, one for
// each physical player slot.  A console sends its local byte during byte 0 and
// sends zero during bytes 1..3, except while emitting an aligned FF restart
// packet.  The adapter broadcasts those four submitted bytes in the following
// packet.  The initial broadcast contains undefined adapter data and is
// discarded by this driver.

#define LINK_DMG07_PHASE_PING       ((u8)0)
#define LINK_DMG07_PHASE_REQUEST_AA ((u8)1)
#define LINK_DMG07_PHASE_WAIT_CC    ((u8)2)
#define LINK_DMG07_PHASE_TRANSFER   ((u8)3)

#define LINK_DMG07_MAX_PLAYERS  ((u8)4)
#define LINK_DMG07_PACKET_BYTES ((u8)4)
#define LINK_DMG07_SIZE         ((u8)1)
// Physical slots here are one-based; do not substitute the zero-based Link4 cooperative slot identifiers.
#define LINK_DMG07_NO_SLOT      ((u8)0)

// RATE $10 gives the shortest documented packet period for SIZE=1 while
// retaining the adapter's normal inter-byte pacing.  RATE $00 is not used.
#define LINK_DMG07_DEFAULT_RATE ((u8)0x10)

#ifndef LINK_DMG07_TIMEOUT_FRAMES
#define LINK_DMG07_TIMEOUT_FRAMES ((u8)12)
#endif

#define LINK_DMG07_ERR_NONE        ((u8)0)
#define LINK_DMG07_ERR_STATE       ((u8)1)
#define LINK_DMG07_ERR_NOT_PLAYER1 ((u8)2)
#define LINK_DMG07_ERR_NOT_READY   ((u8)3)
#define LINK_DMG07_ERR_TIMEOUT     ((u8)4)
#define LINK_DMG07_ERR_PROTOCOL    ((u8)5)
#define LINK_DMG07_ERR_OVERFLOW    ((u8)6)

#define LINK_DMG07_RESTART_NONE    ((u8)0)
#define LINK_DMG07_RESTART_PENDING ((u8)1)
#define LINK_DMG07_RESTART_SENDING ((u8)2)

// Initializes polling-only external-clock operation.  A zero RATE is replaced
// with LINK_DMG07_DEFAULT_RATE.  This driver disables only the serial IRQ bit.
void __stackcall LinkDmg07_Init(u8 rate);

// Services at most one completed serial byte and immediately re-arms SC=$80.
// Call continuously from the main loop, including between VBlanks.
void LinkDmg07_Poll();

// Advances saturating frame-based silence and handshake timeout counters.
void LinkDmg07_TickFrame();

// Return the discovery, start-handshake or transfer phase without polling.
u8 LinkDmg07_GetPhase();
// Return the one-based player slot, or LINK_DMG07_NO_SLOT before discovery.
u8 LinkDmg07_GetLocalSlot();

// Normalized mask: bit 0 is player 1, ..., bit 3 is player 4.
u8 LinkDmg07_GetConnectedMask();
// Return the last validated raw adapter status byte.
u8 LinkDmg07_GetLastStatus();
// Read the completed-discovery status flag without clearing it.
u8 LinkDmg07_HasPingStatus();
// Clear and report the completed-discovery flag; return zero if no new status exists.
u8 LinkDmg07_ConsumePingStatus();

// Only physical player 1 may request AA AA AA AA.  The bytes are aligned to
// the next FE/status/status/status ping packet.  All consoles enter transfer
// mode only after receiving four consecutive CC bytes.
u8 LinkDmg07_RequestTransmission();

// Any physical slot may schedule FF FF FF FF at the next four-byte packet
// boundary while remaining in TRANSFER phase.  The driver keeps sending aligned
// FF bytes until it sees the adapter's complete all-FF indicator packet, then
// returns to PING.  A transfer-phase silence timeout schedules the same recovery
// automatically and preserves the current byte position for clocks that resume.
u8 LinkDmg07_RequestRestart();
// Return whether aligned recovery is absent, pending or sending control traffic.
u8 LinkDmg07_GetRestartState();

// Sets the byte sampled when byte 0 of the next adapter packet is armed.
// Set it before the current packet completes (and before requesting start for
// the first submission).  During normal transfer, bytes 1..3 are sent as zero.
void __stackcall LinkDmg07_SetLocalByte(u8 value);

// The first incoming adapter data packet is discarded.  Thereafter ReadPacket
// copies four bytes in physical slot order (players 1..4).
u8 LinkDmg07_IsPipelinePrimed();
// Inspect the one-packet receive mailbox without consuming it.
u8 LinkDmg07_HasPacket();
// Consume the latest four-byte packet. A nonnull destination must hold four
// bytes; null discards the packet. Packet storage remains after the flag clears.
u8 __stackcall LinkDmg07_ReadPacket(u8 *dst);
// Read one cached player byte using a one-based slot. Invalid slots return
// zero; the function neither requires readiness nor consumes the packet.
u8 __stackcall LinkDmg07_GetPacketSlot(u8 player_slot);

// SentSequence increments when this console's packet byte is clocked out.
// PacketSequence labels the returned four-byte packet.  For a valid packet it
// is one less than SentSequence, making the DMG-07 one-packet delay explicit.
u8 LinkDmg07_GetSentSequence();
// Return the modulo-256 sequence associated with the most recently published packet.
u8 LinkDmg07_GetPacketSequence();

// SilenceFrames is reset by every completed serial byte.  TimeoutCount counts
// distinct serial-silence or AA/CC/restart handshake timeouts. DisconnectCount counts
// adapter-silence outages and ping-status membership drops.  All saturate.
u8 LinkDmg07_GetSilenceFrames();
// Return the saturating lifetime timeout count, preserved across protocol restarts.
u8 LinkDmg07_GetTimeoutCount();
// Return the saturating count of removed-player and previously-seen-adapter timeout events.
u8 LinkDmg07_GetDisconnectCount();
// Return the saturating protocol/overflow error count. Timeout and request
// validation paths use separate counters or latches and do not increment this value.
u8 LinkDmg07_GetErrorCount();
// Return the latest error latch without clearing counters or restarting the protocol.
u8 LinkDmg07_LastError();
// Clear only the latest error code, preserving counters and protocol state.
void LinkDmg07_ClearError();

kitaqgb/lib/link_dmg07.h

physics2d.h — 2D 이동과 충돌
c
#pragma once

// Position and velocity use caller-selected integer units with one integration
// step per call; no hidden pixel or time conversion occurs. Keep intermediate
// signed arithmetic in range. World/body storage is owned by the caller.
#include "fixed.h"

// Multiply a signed word by a signed byte; divide by 256, truncating toward zero.
s16 __smul16x8(s16 a, s8 b);

// Lightweight deterministic 2D physics for KITAQGB.
// Integer pixels per step are one possible unit convention; inv_mass is Q8.

typedef struct {
    s16 x;
    s16 y;
    s16 vx;
    s16 vy;
    s16 half_x;
    s16 half_y;
    s16 inv_mass_q8;      // 0 means static body.
    s16 restitution_q8;   // 0..255 (reserved for future tuning).
    u8 active;
} KQBody2D;

typedef struct {
    KQBody2D* bodies;
    u8 body_count;
    s16 gravity_x;
    s16 gravity_y;
    u8 solver_iterations;
    s16 max_speed;
} KQWorld2D;

// Retain the caller-owned body array without initializing its elements.
// Set gravity to (0,32), four contact iterations and a per-axis speed limit of 512.
// A null world is ignored; the array must outlive subsequent world operations.
void kq2d_world_init(KQWorld2D* world, KQBody2D* bodies, u8 body_count);
// Advance active dynamic bodies, then visit each active unordered pair for
// the configured contact passes (zero means one). Static bodies still participate
// as obstacles. The world borrows its array and shares non-reentrant ASM scratch.
// This is discrete integration; fast bodies can pass through thin obstacles.
void kq2d_step(KQWorld2D* world);
// For one active dynamic body, add gravity, clamp each velocity axis and then
// add velocity to position. Null inputs are ignored; no contacts are solved.
// Use a nonnegative speed limit and keep additions in signed 16-bit range.
void kq2d_integrate_body(KQWorld2D* world, KQBody2D* body);
// Test strict overlap of two centered boxes; touching edges return false.
// Both pointers must be valid. Active/mass flags are ignored, and coordinate
// differences and extent sums must fit the signed 16-bit calculations.
u8 kq2d_overlap_aabb(const KQBody2D* a, const KQBody2D* b);
// Initialize an active unit-inverse-mass body at the supplied center and half
// extents, with zero velocity and reserved restitution set to zero. Null is ignored.
void kq2d_body_init(KQBody2D* body, s16 x, s16 y, s16 half_x, s16 half_y);
// Replace the center without altering velocity, extents or activity. Null is ignored.
void kq2d_body_set_pos(KQBody2D* body, s16 x, s16 y);
// Replace velocity without clamping or checking activity/mass. Null is ignored.
void kq2d_body_set_velocity(KQBody2D* body, s16 vx, s16 vy);
// Add gravity and clamp each velocity axis separately for an active dynamic
// body. Null, inactive and static bodies are ignored. Supply a nonnegative limit
// and avoid overflow in the additions before clamping; position is unchanged.
void kq2d_body_apply_gravity(KQBody2D* body, s16 gravity_x, s16 gravity_y, s16 max_speed);
// Scale both velocities through the signed 8-bit coefficient intrinsic.
// Despite the unsigned parameter, values 128..255 become negative coefficients;
// this is not a full-range unsigned Q8 damping helper. Null is ignored.
void kq2d_body_apply_friction(KQBody2D* body, u8 friction_q8);
// Delegate strict rectangle overlap to the fixed-point utility; edge-only
// contact is false. Coordinate-plus-size sums must remain representable as s16.
u8 kq2d_rect_intersect(KQRect a, KQRect b);
// Delegate the half-open point test: include left/top and exclude right/bottom.
// Coordinate-plus-size sums must remain representable as s16.
u8 kq2d_point_in_rect(s16 x, s16 y, KQRect r);

// Opt-in surface solver. Velocities/threshold/kick share the caller's units.
// Normal must be unit length in Q8; coefficients are 0..255.
typedef struct {
    s16 nx_q8;
    s16 ny_q8;
    s16 vx;
    s16 vy;
    s16 bounce_threshold;
    s16 kick;
    u8 restitution_q8;
    u8 friction_q8;
} KQSurface2D;

// Truncates toward zero, including negative values; coefficient is -256..256.
s16 kq2d_scale_q8(s16 value, s16 coefficient);
// Conservative circular bound, with a shared Q8 scale for both components.
// Quantizes toward zero; very small limits relative to input may yield zero.
// Components and positive max_speed must be <= 16383 in magnitude.
void kq2d_body_limit_speed(KQBody2D* body, s16 max_speed);
// Kinematic surface response; returns incoming normal speed, or zero if separating.
// Caller resolves penetration separately. Relative components must fit +/-8191.
s16 kq2d_body_resolve_surface(KQBody2D* body, const KQSurface2D* surface);
// Linear crossing time in Q8 (0..256); positive separation is outside.
// Returns 0 for initial overlap, 256 for no crossing. Gaps must fit +/-8191.
u16 kq2d_surface_toi_q8(s16 start_gap, s16 end_gap);

kitaqgb/lib/physics2d.h

physics2d_circle.h — 원형 물체의 물리
c
#pragma once

// Deterministic 2D circle physics for KITAQGB.
// Intended for top-down ball games such as billiards, air hockey, and marbles.

// Use consistent caller-selected units for centers, radii and per-step velocity.
// The implementation uses 16-bit arithmetic: reduced squared-distance sums and
// weight products must fit their types. Reduction to byte-sized components alone
// is insufficient to guarantee this. Body storage remains caller-owned.
typedef struct {
    s16 x;
    s16 y;
    s16 vx;
    s16 vy;
    s16 radius;
    s16 inv_mass_q8;      // 0 means static body.
    u8 restitution_q8;    // 0..255, higher means bouncier.
    u8 friction_q8;       // 0..255, higher removes more tangential motion.
    u8 active;
} KQCircleBody2D;

typedef struct {
    KQCircleBody2D* bodies;
    u8 body_count;
    s16 gravity_x;
    s16 gravity_y;
    u8 solver_iterations;
    s16 max_speed;
    u8 linear_damping_q8;   // 255 is almost no damping, lower values damp faster.
    u8 use_bounds;
    s16 min_x;
    s16 min_y;
    s16 max_x;
    s16 max_y;
    u8 wall_restitution_q8;
    u8 wall_friction_q8;
} KQCircleWorld2D;

// Retain a caller-owned array without initializing bodies. Set zero gravity,
// four contact passes, per-axis limit 768 and damping 252/256; bounds start disabled.
// A null world is ignored. Keep the array alive for subsequent steps.
void kq2dc_world_init(KQCircleWorld2D* world, KQCircleBody2D* bodies, u8 body_count);
// Store and enable bounds without validating their order or fitting bodies
// immediately. Supply extents large enough for body diameters. Null is ignored.
void kq2dc_set_bounds(KQCircleWorld2D* world, s16 min_x, s16 min_y, s16 max_x, s16 max_y);
// Integrate active dynamic bodies, apply bounds, solve contacts, then damp
// velocity and snap components in -1..1 to zero. Zero solver iterations means one.
// Pairs with both velocities zero are skipped, so resting overlaps can remain.
// Bounds can reposition static bodies; null world/array inputs are ignored.
void kq2dc_step(KQCircleWorld2D* world);
// Compare a reduced integer center distance with the reduced radius sum.
// Valid pointers and positive radii are required; activity and mass are ignored.
// This approximate test requires representable differences, radius sums and
// squared-distance sum. Touching at the computed distance returns false.
u8 kq2dc_overlap_circle(const KQCircleBody2D* a, const KQCircleBody2D* b);

kitaqgb/lib/physics2d_circle.h

physics3d.h — 3D AABB 물리
c
#pragma once

// Lightweight deterministic 3D physics for KITAQGB.
// AABB contacts, acceleration, mass-weighted bounce, and impact state flags.

// The game owns break decisions: the solver records impact speeds but never
// sets this flag or deactivates a body based on break_speed. Positions, extents,
// velocities and acceleration use consistent caller-selected per-step units.
#define KQ3D_BODY_BROKEN ((u8)0x01)

typedef struct {
    s16 x;
    s16 y;
    s16 z;
    s16 vx;
    s16 vy;
    s16 vz;
    s16 ax;
    s16 ay;
    s16 az;
    s16 half_x;
    s16 half_y;
    s16 half_z;
    s16 mass_q8;        // 256 means mass 1.0.
    s16 inv_mass_q8;    // 0 means static body.
    s16 restitution_q8; // 256 means perfectly elastic.
    s16 break_speed;    // Reserved for game-side impact thresholds.
    s16 last_impact_speed;
    u8 active;
    u8 flags;
} KQBody3D;

typedef struct {
    KQBody3D* bodies;
    u8 body_count;
    s16 gravity_x;
    s16 gravity_y;
    s16 gravity_z;
    u8 solver_iterations;
    s16 max_speed;
} KQWorld3D;

// Borrow the body array without initializing it. Set gravity (0,24,0), four
// contact passes and a per-axis speed limit of 512. Null world is ignored;
// the caller retains ownership and must keep the array alive.
void kq3d_world_init(KQWorld3D* world, KQBody3D* bodies, u8 body_count);
// Initialize an active centered box with zero velocity/acceleration,
// restitution 224, cleared impact/flags and mass set through the weight helper.
// The caller supplies valid half extents. Null body is ignored.
void kq3d_body_init(KQBody3D* body, s16 x, s16 y, s16 z, s16 half_x, s16 half_y, s16 half_z, s16 mass_q8);
// Store the requested mass; nonpositive mass makes the body static.
// For positive mass compute inverse weight as max(1,32767/max(mass,64)).
// The stored mass retains the original input; this is a relative solver weight,
// not an exact Q8 reciprocal. Null body is ignored.
void kq3d_body_set_mass(KQBody3D* body, s16 mass_q8);
// Integrate active dynamic bodies and reset their impact values, then solve
// each active unordered pair for the configured passes (zero means one).
// Static bodies retain previous impact maxima until the game clears them.
// Acceleration persists; flags and break thresholds remain game-owned.
// This discrete solver shares non-reentrant ASM scratch and can miss fast crossings.
void kq3d_step(KQWorld3D* world);
// Reset impact for one active dynamic body, add gravity and persistent body
// acceleration, clamp velocity per axis and advance position. Static/inactive
// bodies retain impact state. Null inputs are ignored; no contacts are solved.
// Use a nonnegative speed limit and avoid overflow before clamping.
void kq3d_integrate_body(KQWorld3D* world, KQBody3D* body);
// Test strict overlap on all three axes; face-only contact returns false.
// Valid pointers are required and flags are ignored. Center differences and
// extent sums must fit the signed 16-bit magnitude calculations.
u8 kq3d_overlap_aabb(const KQBody3D* a, const KQBody3D* b);

// Sum three signed products, shifting each by eight bits before addition.
// Coefficients are signed bytes scaled by 1/256; the 16-bit sum is not saturated.
s16 kq3d_dot_q8_8(s16 x, s16 y, s16 z, s8 ax, s8 ay, s8 az);

kitaqgb/lib/physics3d.h

raster.h — 구간·주사선별 스크롤 테이블
c
#pragma once

#include "scroll.h"

// Keep wrapper capacity consistent with the compiler split-table capacity; wrapper checks do not enlarge it.
#define KQ_RASTER_MAX_BANDS 8

#define KQ_RASTER_OK        0
#define KQ_RASTER_FULL      1
#define KQ_RASTER_BAD_LY    2
#define KQ_RASTER_UNSORTED  3
#define KQ_RASTER_BAD_RANGE 4

#define KQ_RASTER_BG        KQ_SCROLL_SPLIT_USE_BG
#define KQ_RASTER_WIN       KQ_SCROLL_SPLIT_USE_WIN
#define KQ_RASTER_WIN_SHOW  KQ_SCROLL_SPLIT_WIN_SHOW
#define KQ_RASTER_WIN_HIDE  KQ_SCROLL_SPLIT_WIN_HIDE
#define KQ_RASTER_BG_COLOR0 KQ_SCROLL_SPLIT_BG_COLOR0
#define KQ_RASTER_FLAG_MASK 0x1F

#define KQ_RASTER_LINE_FLAT        0
#define KQ_RASTER_LINE_X_TITLE     1
#define KQ_RASTER_LINE_TRAVEL_GATE 2

// Caller-owned wave state. Initialize it before use and keep it non-null for every LineX operation.
// frame_counter measures RunFrame calls, not an independent hardware clock.
typedef struct RasterLineX {
    u8 profile;
    u8 base_x;
    u8 phase;
    u8 phase_step;
    u8 frame_divider;
    u8 frame_counter;
} RasterLineX;

// Stop split scheduling, empty the shared table and clear error/count state.
void Raster_Init();
// Stop splits immediately and clear bookkeeping. Build and commit a new table to restart.
void Raster_Clear();
// Commit an empty split table so no raster bands remain active.
void Raster_Disable();

// Read the number of bands currently recorded by this wrapper.
u8 Raster_GetCount();
// Read the last stored status without clearing it.
u8 Raster_GetLastError();

// Append a validated background-scroll band and advance the monotonic-LY
// bookkeeping. A successful append clears the previous error.
u8 Raster_Push(u8 ly, u8 scx, u8 scy);
// Append a validated extended band after masking flags to supported operations.
u8 Raster_PushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);

// Enable window updates and pass hardware WX/WY values without coordinate conversion.
u8 Raster_PushWindowRaw(u8 ly, u8 wx, u8 wy, u8 flags);
// Convert screen X to hardware WX by adding seven, then queue a window band.
// The byte addition wraps if callers supply an excessive X coordinate.
u8 Raster_PushWindowScreen(u8 ly, u8 screen_x, u8 screen_y, u8 flags);
// Queue both background and window updates, converting window screen X to WX.
u8 Raster_PushBgWindowScreen(u8 ly, u8 scx, u8 scy, u8 screen_x, u8 screen_y, u8 flags);
// Pack a 15-bit color into the extended band's two scroll-byte fields and select
// the color-zero operation, which interprets those fields as color data.
u8 Raster_PushBgColor0(u8 ly, u16 rgb15);

// Publish pending splits and return the stored status. This commits even if an
// earlier append failed; callers should inspect errors while building the table.
u8 Raster_Commit();

// Validate the HUD height, then replace pending splits with a fixed top band
// and scrolling playfield. The new table still requires an explicit commit.
u8 Raster_BuildHudTop(u8 hud_height, u8 camera_x, u8 camera_y);
// Build a scrolling upper playfield and fixed bottom HUD after validating the split.
u8 Raster_BuildHudBottom(u8 hud_y, u8 camera_x, u8 camera_y);

// Build two horizontal-scroll bands sharing one vertical scroll value.
u8 Raster_BuildParallax2(u8 split_y, u8 far_scx, u8 near_scx, u8 scy);
// Build three horizontal-scroll bands at ordered visible split lines. Invalid
// parameters leave the previous pending table intact and set the error status.
u8 Raster_BuildParallax3(u8 y1, u8 y2, u8 scx0, u8 scx1, u8 scx2, u8 scy);

// Initialize a scanline-wave state with phase zero and one phase step per frame.
void Raster_LineXInit(RasterLineX* effect, u8 profile, u8 base_x);
// Change the wave profile and restart its phase/divider counter.
void Raster_LineXSetProfile(RasterLineX* effect, u8 profile);
// Configure the phase increment and frame interval; clamp a zero interval to one.
void Raster_LineXSetSpeed(RasterLineX* effect, u8 phase_step, u8 frame_divider);
// Set the byte phase directly without resetting the frame-divider counter.
void Raster_LineXSetPhase(RasterLineX* effect, u8 phase);
// Look up the selected periodic profile at LY + phase and add base X modulo
// 256. An unknown profile returns the unmodified base X.
u8 Raster_LineXGetOffset(const RasterLineX* effect, u8 ly);
// Render all 144 visible lines with one SCX write per line, then advance phase.
// This foreground renderer masks interrupts during the visible frame. Do game
// and audio work between calls; do not combine it with a STAT raster driver.
// Returns without changing the effect when the LCD is off.
void Raster_LineXRunFrame(RasterLineX* effect);

kitaqgb/lib/raster.h

rpg.h — 난수, 문자, 맵, 저장, RPG·ADV·SLG 기능
c
#pragma once

// The application supplies frame/cursor/font tiles at these indices; these constants do not load graphics.
#ifndef TEXT_TILE_FILL
#define TEXT_TILE_FILL ((u8)0)
#endif
#ifndef TEXT_TILE_FRAME_TL
#define TEXT_TILE_FRAME_TL ((u8)1)
#endif
#ifndef TEXT_TILE_FRAME_TR
#define TEXT_TILE_FRAME_TR ((u8)2)
#endif
#ifndef TEXT_TILE_FRAME_BL
#define TEXT_TILE_FRAME_BL ((u8)3)
#endif
#ifndef TEXT_TILE_FRAME_BR
#define TEXT_TILE_FRAME_BR ((u8)4)
#endif
#ifndef TEXT_TILE_FRAME_H
#define TEXT_TILE_FRAME_H ((u8)5)
#endif
#ifndef TEXT_TILE_FRAME_V
#define TEXT_TILE_FRAME_V ((u8)6)
#endif
#ifndef TEXT_TILE_CURSOR
#define TEXT_TILE_CURSOR ((u8)7)
#endif
#ifndef TEXT_TILE_PAGE_WAIT
#define TEXT_TILE_PAGE_WAIT ((u8)8)
#endif
#ifndef TEXT_DIGIT_BASE
#define TEXT_DIGIT_BASE ((u8)'0')
#endif

#define TEXT_CTRL_END       ((u8)0x00)
#define TEXT_CTRL_NEWLINE   ((u8)0x0A)
#define TEXT_CTRL_WAIT      ((u8)0x01)
#define TEXT_CTRL_PAGE_WAIT ((u8)0x02)

#define PAD_KEY_RIGHT  ((u8)0x01)
#define PAD_KEY_LEFT   ((u8)0x02)
#define PAD_KEY_UP     ((u8)0x04)
#define PAD_KEY_DOWN   ((u8)0x08)
#define PAD_KEY_A      ((u8)0x10)
#define PAD_KEY_B      ((u8)0x20)
#define PAD_KEY_SELECT ((u8)0x40)
#define PAD_KEY_START  ((u8)0x80)

// Default layout: four 512-byte slots, each with a six-byte header and at most 506 payload bytes.
#define SAVE_SLOT_COUNT ((u8)4)
#define SAVE_SLOT_SIZE  ((u16)512)
#define SAVE_MAGIC0     ((u8)0x4B)
#define SAVE_MAGIC1     ((u8)0x51)
#define SAVE_VERSION    ((u8)1)

#define SAVE_OK         ((u8)1)
#define SAVE_ERR        ((u8)0)

// A bank byte plus a CPU-visible address forms this data reference; it does not switch banks by itself.
typedef __packed struct {
    u8 bank;
    const u8* ptr;
} far_ptr_t;

typedef __packed struct {
    u8 x;
    u8 y;
    u8 w;
    u8 h;
    const u8* const* items;
    u8 count;
    u8 cursor;
} menu_t;

typedef __packed struct {
    u8 id;
    u8 qty;
    const u8* name;
} item_t;

// Packed nine-byte ordinary-map descriptor. Tile IDs use bank_tiles; collision bits and event bytes
// use the descriptor bank. Width/height are tile cells, with row-major data.
typedef __packed struct {
    u8 width;
    u8 height;
    u8 bank_tiles;
    const u8* tiles;
    const u8* collision_bits;
    const void* events;
} map_t;

// One 2x2 metatile: four tile IDs plus collision, palette metadata and event ID.
// The map drawing routine uses tile IDs only; it does not apply palette attributes.
typedef __packed struct {
    u8 tile_tl;
    u8 tile_tr;
    u8 tile_bl;
    u8 tile_br;
    u8 collision;
    u8 palette;
    u8 event;
} metatile_t;

// Metatile dimensions count 2x2 cells. bank_tiles=0 means use the descriptor bank;
// nonzero bank_tiles supplies both ID-array and definition-table reads.
typedef __packed struct {
    u8 width;
    u8 height;
    u8 bank_tiles;
    const u8* metatile_ids;
    const metatile_t* metatiles;
} metatile_map_t;

typedef __packed struct {
    u8 x;
    u8 y;
    u8 w;
    u8 h;
    const u8* const* items;
    u8 count;
    u8 cursor;
    u8 prev_keys;
    u8 selected;
    u8 cancelled;
} menu_state_t;

typedef __packed struct {
    u8 x;
    u8 y;
    u8 hp;
    u8 move;
    u8 atk_min;
    u8 atk_max;
    u8 team;
    u8 acted;
} unit_t;

void __wait_vblank();
u16 __readpadex(u8 prev_keys);
u16 __getbgmapbase();
void __memset(void* dst, u8 value, u16 count);
void __memcpy(void* dst, const void* src, u16 count);
void __settile(u8 x, u8 y, u8 tile);
void __settilebg(u8 x, u8 y, u8 tile);
void __settileat(u16 base, u8 x, u8 y, u8 tile);
void __vram_memcpy(u16 dst, const void* src, u16 len);
void __vram_memset(u16 dst, u8 value, u16 len);
void __far_memcpy(void* dst, u8 bank, const void* src, u16 len);
u8 __rng8();
void __rng_seed(u16 seed);
void __scroll_bg_set(u8 scx, u8 scy);

void __settile_xy(u8 x, u8 y, u8 tile);
void __settile_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
void __settile_row(u8 x, u8 y, const u8* src, u8 len);
void __settile_col(u8 x, u8 y, const u8* src, u8 len);
void __fill_tilemap(u16 base, u8 tile, u16 count);
void __settilemap_rect(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);

void __vram_copy(u16 dst, const void* src, u16 len);
void __vram_fill(u16 dst, u8 value, u16 len);
void __vram_copy_hblank(u16 dst, const void* src, u16 len);
void __vram_copy_dma(u16 dst, const void* src, u16 len);

u8 __farpeek8(u8 bank, const void* addr);
u16 __farpeek16(u8 bank, const void* addr);
void __farmemcpy(void* dst, u8 bank, const void* src, u16 len);
// The current GB backend evaluates/discards these arguments but emits no indirect call.
void __farcall_ptr(u8 bank, const void* func);

#define far_read8(p) __farpeek8((p).bank, (p).ptr)
#define far_read16(p) __farpeek16((p).bank, (p).ptr)
#define far_read_block(dst, p, len) __farmemcpy((dst), (p).bank, (p).ptr, (len))

void __memcpy_small(void* dst, const void* src, u8 len);
void __memset_small(void* dst, u8 value, u8 len);
void __copy16(void* dst, const void* src);
void __copy32(void* dst, const void* src);

u16 __tile_addr(u16 base, u8 x, u8 y);
u16 __map_index(u8 x, u8 y, u8 width);
u8 __xy_in_rect(u8 x, u8 y, u8 rx, u8 ry, u8 rw, u8 rh);
u8 __manhattan(u8 x1, u8 y1, u8 x2, u8 y2);

u8 __bit_test(const u8* p, u16 bit_index);
void __bit_set(u8* p, u16 bit_index);
void __bit_clear(u8* p, u16 bit_index);
void __bit_toggle(u8* p, u16 bit_index);

// Compiler intrinsic, separate from the RAM rle_decode helpers below; it is not a bounded-stream API.
u16 __rle_decode_vram(u16 dst, u8 bank, const void* src);

// Advance the compiler-provided pseudorandom generator and return one byte.
u8 rng8();
// Consume two generator bytes in high-byte/low-byte order to form a 16-bit value.
u16 rng16();
// Reduce a random byte modulo max; zero returns zero without consuming randomness.
// Modulo reduction is biased unless max divides the generator range.
u8 rand_range(u8 max);
// Select an index from cumulative byte weights using a 16-bit random draw.
// A zero total, including an empty list, returns zero; callers must distinguish
// that case from a valid index. Modulo reduction can introduce a small bias.
u8 weighted_choice(const u8* weights, u8 count);
// Replace the generator seed so subsequent calls can reproduce a sequence.
void rng_seed(u16 seed);
// Alias the byte generator; this consumes one generator step.
u8 rng_next8();
// Alias the two-step 16-bit generator.
u16 rng_next16();
// Alias rand_range and return a value in [0,max), or zero when max is zero.
u8 rng_range(u8 max);
// Return false for zero and true for values at least 100. Intermediate values
// use the modulo-based range generator, so percentages are approximate.
u8 rng_chance(u8 percent);

// Set the tile-space window, reset its cursor and redraw it immediately.
// Opening does not reset the existing character speed or load font tiles.
void text_open(u8 x, u8 y, u8 w, u8 h);
// Erase the open window with the fill tile and disable windowed character output.
void text_close();
// Decode an END-terminated stream of tile bytes and newline/wait/page controls.
// WAIT consumes a following frame-count byte. The source must remain readable
// through blocking waits; the routine does not validate stream length.
void text_print(const u8* str);
// Decode the same text controls while fetching each byte from the specified
// ROM bank. The pointer advances within that bank; it does not roll into the next bank.
void text_print_far(u8 bank, const u8* str);
// Redraw choices and block for edge-triggered navigation: UP/DOWN wrap, A
// accepts, and B returns 0xFF. Zero choices also returns 0xFF. Choice strings
// use raw tile bytes, and the caller must fit them inside the available rows.
u8 text_choice(const u8* const* choices, u8 count);
// Set VBlank waits per windowed character; zero prints without character delays.
void text_set_speed(u8 speed);
// Open and redraw a window using the same tile-space arguments as text_open.
void text_window(u8 x, u8 y, u8 w, u8 h);
// Fill the supplied tile rectangle without changing the active text window or cursor.
void text_clear_rect(u8 x, u8 y, u8 w, u8 h);
// Draw a zero-terminated tile string at absolute tile coordinates, without
// window clipping, control codes or the windowed printing delay.
void text_print_xy(u8 x, u8 y, const u8* str);
// Print an unsigned byte in decimal using only the required number of cells.
void text_print_u8(u8 x, u8 y, u8 value);
// Print an unsigned word in decimal using only the required number of cells.
void text_print_u16(u8 x, u8 y, u16 value);
// Print a minus tile for negative values, followed by the unsigned magnitude.
// Positive values use the unsigned decimal path; no plus sign is emitted.
void text_print_s16(u8 x, u8 y, s16 value);

// Replace the active script and clear wait, choice and saved-return state.
void script_run(u8 bank, const u8* script);
// Execute commands until an output/choice yields (0), a wait yields (1), or
// execution ends (2). Control/flag commands continue within the same call, so
// a script loop without a yielding command can block the game loop indefinitely.
u8 script_step();
// Set the number of subsequent script_step calls to spend waiting. Frame-based
// timing requires the application to call script_step once per frame.
void script_wait_frames(u8 n);

// Run a blocking menu loop with wraparound up/down selection, A to accept
// and B to cancel. Return 0xFF for an empty menu or cancellation. Item strings
// and menu dimensions must fit the visible tile area.
u8 menu_run(const menu_t* menu);
// Open a two-choice dialog and return the text-choice result (YES first, NO second).
u8 menu_yesno();
// Run a blocking item menu, drawing names and two-digit quantities. Return
// the selected index or 0xFF on empty input/B; this does not consume an item.
u8 menu_inventory(const item_t* items, u8 count);
// Initialize a nonblocking menu state that borrows the item pointer table.
// Selection starts unset (0xFF), and the cancellation flag starts clear.
void menu_init_state(menu_state_t* state, u8 x, u8 y, u8 w, u8 h, const u8* const* items, u8 count);
// Draw the current menu and cursor without waiting or sampling input. The
// caller schedules suitable display timing and keeps item text within bounds.
void menu_draw(menu_state_t* state);
// Sample new button presses and update cursor/selection state without drawing.
// Selected and cancelled results remain latched; a B press in the same update
// as A clears selection and leaves cancellation set.
void menu_update(menu_state_t* state);
// Read the latched selection without clearing it; null state returns 0xFF.
u8 menu_get_selected(menu_state_t* state);
// Read the latched cancellation flag; null state returns false.
u8 menu_was_cancelled(menu_state_t* state);

// Load the nine-byte ordinary-map descriptor and draw up to 20 by 18 tiles
// from its top-left corner. Drawing does not upload tile graphics or clear
// background cells beyond smaller map dimensions.
void map_load(u8 bank, const map_t* map);
// Use metatile collision when that mode is active; otherwise read one packed
// collision bit. Missing maps/out-of-range cells block movement, but a valid
// ordinary map without a collision array is entirely passable.
u8 map_is_blocked(u8 x, u8 y);
// Report whether an event exists at the cell. Ordinary maps expose a Boolean
// byte-presence test; metatile maps reduce their event ID to a Boolean here.
u8 map_trigger_at(u8 x, u8 y);
// Center an ordinary-map tile coordinate within a 20-by-18 viewport and clamp
// the scroll origin to its edges. This adjusts scroll registers only; it does
// not stream newly exposed map rows into VRAM.
void camera_center(u8 x, u8 y);
// Select metatile mode, copy its descriptor and draw the initial viewport
// with the camera at cell (0,0).
void map_load_metatile(u8 bank, const metatile_map_t* map);
// Draw a 10-by-9 metatile viewport as 20-by-18 individual background tiles.
// Out-of-range cells use definition zero; palette attributes are not written.
// Remember the camera and clear the dirty flag after the full redraw.
void map_draw_visible(u8 camera_tx, u8 camera_ty);
// Read a row-major metatile ID, returning ID zero for inactive or out-of-range
// lookups. Callers must provide a usable definition for metatile zero.
u8 map_get_metatile(u8 tx, u8 ty);
// Return the selected definition's palette byte. An out-of-range coordinate
// uses the metatile-zero fallback; this function does not write CGB attributes.
u8 map_get_attr(u8 tx, u8 ty);
// Treat out-of-range metatile cells as solid; otherwise inspect the definition
// collision flag. In ordinary-map mode, delegate to its packed collision bits.
u8 map_is_solid(u8 tx, u8 ty);
// Return a metatile event ID, or the ordinary-map Boolean trigger result.
// Missing/out-of-range metatile cells have no event.
u8 map_get_event(u8 tx, u8 ty);
// Mark the viewport for a full redraw when a valid metatile cell changes.
// The coordinate is validated but no per-cell dirty list is retained.
void map_mark_dirty(u8 tx, u8 ty);
// Redraw the remembered metatile viewport only when the shared dirty flag is set.
void map_flush_dirty();

// Validate slot and payload length, write payload bytes, then write the header
// and checksum. Return one after completing the writes; interruption can leave
// a partially replaced slot, so this is not transactional save storage.
u8 save_write(u8 slot, const void* data, u16 len);
// Require matching magic/version, exact requested length and a valid checksum
// before copying data into the destination. Validation failure leaves the
// destination unchanged. An invalid slot returns before touching RAM control;
// validation failures after enabling RAM disable it before returning zero.
u8 save_read(u8 slot, void* data, u16 len);
// Validate a slot's header, payload bounds and checksum without copying the
// payload out. A nonzero result means the stored record passes these checks.
u8 save_exists(u8 slot);
// Initialize the expected RAM access state and leave cartridge RAM disabled.
// Existing slot contents are preserved.
void save_init();
// Alias the checked save_read operation.
u8 save_load(u8 slot, void* data, u16 len);
// Alias save_exists, including its header and checksum validation.
u8 save_check(u8 slot);
// Zero the complete selected slot, including header and payload; invalid slot
// IDs are ignored. Cartridge RAM is disabled when clearing finishes.
void save_clear(u8 slot);

// Build movement costs, then convert reachable cells to one and unreachable
// 0xFF cells to zero. The caller provides one output byte per current-map cell
// and a valid unit origin; path-search workspace limits also apply.
u8 unit_move_range(unit_t* u, u8* out_mask);
// Mark cells whose Manhattan distance falls within the inclusive attack range.
// This geometric mask does not test obstacles, line of sight or other units.
u8 unit_attack_range(unit_t* u, u8* out_mask);
// A unit can act only while HP is nonzero and its acted flag is clear.
// The unit pointer must refer to a valid record.
u8 unit_can_act(const unit_t* u);

// Find a shortest cardinal path with BFS and write direction codes 0=up,
// 1=right, 2=down, 3=left. Return its byte length, or zero for failure or an
// already-reached goal. The caller supplies max_len output bytes and respects
// the shared workspace/distance limits; excessive paths are not truncated.
u8 path_find_bfs(u8 sx, u8 sy, u8 gx, u8 gy, u8* out_path, u8 max_len);
// Flood cardinal neighbors at unit cost, stopping expansion at the movement
// limit and rejecting blocked destinations. Initialize output to 0xFF only
// after validating the map and origin; invalid input leaves output unchanged.
void range_fill_move(u8 sx, u8 sy, u8 move, u8* out_costmap);

// Read a bit from the flag array. Callers must keep id below 2048.
u8 flag_get(u16 id);
// Set a flag bit without disturbing adjacent flags; id must be below 2048.
void flag_set(u16 id);
// Clear a flag bit; id must be below 2048.
void flag_clear(u16 id);
// Read a quest-state byte; quest_id must be below 64.
u8 quest_state(u8 quest_id);
// Replace a quest-state byte without validating its game-specific meaning.
// The caller must keep quest_id below 64.
void quest_set_state(u8 quest_id, u8 state);

// Expand count/value byte pairs until a zero count terminates the stream.
// The caller must provide a valid terminator and sufficient destination storage;
// there are no source or destination bounds parameters. Return the 16-bit byte count.
u16 rle_decode(void* dst, const void* src);
// Decode the same count/value format using bank-qualified reads for every source
// byte. Keep the encoded stream within the supplied bank/address mapping and
// provide enough destination space; a zero count ends the stream.
u16 rle_decode_far(void* dst, u8 bank, const void* src);

// Return the active map width in its own cell units, or zero when no map is loaded.
u8 map_current_width();
// Return the active map height in its own cell units, or zero when no map is loaded.
u8 map_current_height();

kitaqgb/lib/rpg.h

scene.h — 장면 등록, 전환, 갱신
c
#pragma once

typedef void (*SceneFunc)();

// Callbacks may be null. Keep the table and non-null targets readable for its lifetime.
// These plain function pointers do not carry a ROM bank number.
typedef __packed struct {
    SceneFunc enter;
    SceneFunc update;
    SceneFunc draw;
    SceneFunc exit;
} SceneDef;

// Attach the caller-owned scene table and clear current-scene state without invoking callbacks.
void scene_init(const SceneDef* scenes, u8 count);
// Replace the table by resetting scene state; this does not call the old scene's exit handler.
void scene_set_table(const SceneDef* scenes, u8 count);
// Ignore invalid IDs; otherwise exit the current scene and enter the requested one.
// Selecting the current ID still performs exit/enter. Callbacks run synchronously.
void scene_change(u8 scene_id);
// Clear the change flag before calling the active scene's update handler, so a
// transition made during that handler is visible afterward.
void scene_update();
// Call the active scene's draw handler if one exists; no current scene is a no-op.
void scene_draw();
// Return the stored scene ID; zero is also returned before the first transition.
u8 scene_get_current();
// Read the transition flag, which is cleared at the start of an active scene update.
u8 scene_was_changed();

kitaqgb/lib/scene.h

scroll.h — 배경·윈도·분할 스크롤
c
#pragma once

// Flags select operations in a raster split; raw window X includes the hardware +7 offset.
#define KQ_SCROLL_SPLIT_USE_BG   0x01
#define KQ_SCROLL_SPLIT_USE_WIN  0x02
#define KQ_SCROLL_SPLIT_WIN_SHOW 0x04
#define KQ_SCROLL_SPLIT_WIN_HIDE 0x08
#define KQ_SCROLL_SPLIT_BG_COLOR0 0x10

void __scroll_bg_set(u8 scx, u8 scy);
void __scroll_bg_x_set(u8 scx);
void __scroll_bg_y_set(u8 scy);
u8 __scroll_bg_x_get();
u8 __scroll_bg_y_get();

void __scroll_win_set(u8 wx, u8 wy);
void __scroll_win_x_set(u8 wx);
void __scroll_win_y_set(u8 wy);
u8 __scroll_win_x_get();
u8 __scroll_win_y_get();

void __scroll_bg_set_buffered(u8 scx, u8 scy);
void __scroll_bg_x_set_buffered(u8 scx);
void __scroll_bg_y_set_buffered(u8 scy);
void __scroll_win_set_buffered(u8 wx, u8 wy);
void __scroll_win_x_set_buffered(u8 wx);
void __scroll_win_y_set_buffered(u8 wy);
void __scroll_flush();

void __scroll_split_reset();
void __scroll_split_push(u8 ly, u8 scx, u8 scy);
void __scroll_split_push_ex(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);
void __scroll_split_commit();

void __scroll_win_show();
void __scroll_win_hide();
void __scroll_bg_add(s8 dx, s8 dy);
void __scroll_win_add(s8 dx, s8 dy);

// Reset background scroll to zero and place the window at screen origin
// using hardware WX=7 and WY=0.
void Scroll_Init();
// Write both hardware background-scroll bytes immediately.
void Scroll_SetBg(u8 scx, u8 scy);
// Write horizontal background scroll while leaving vertical scroll unchanged.
void Scroll_SetBgX(u8 scx);
// Write vertical background scroll while leaving horizontal scroll unchanged.
void Scroll_SetBgY(u8 scy);
// Read the tracked current background X; this is not a direct SCX register read.
u8 Scroll_GetBgX();
// Read the tracked current background Y; pending and raster-only values are excluded.
u8 Scroll_GetBgY();

// Write raw hardware WX/WY values; callers add seven to a screen-space window X.
void Scroll_SetWindow(u8 wx, u8 wy);
// Write raw hardware WX without converting a screen-space X coordinate.
void Scroll_SetWindowX(u8 wx);
// Write the window Y coordinate through the intrinsic.
void Scroll_SetWindowY(u8 wy);
// Read tracked current WX, including its seven-pixel offset; not a live hardware read.
u8 Scroll_GetWindowX();
// Read tracked current WY; pending and raster-only values are excluded.
u8 Scroll_GetWindowY();

// Stage background-scroll values in the intrinsic buffer for a later flush.
void Scroll_SetBgBuffered(u8 scx, u8 scy);
// Stage raw window-coordinate values for a later flush.
void Scroll_SetWindowBuffered(u8 wx, u8 wy);
// Apply the buffered scroll/window state through the compiler runtime.
void Scroll_Flush();

// Apply signed deltas to the byte-sized background-scroll coordinates.
void Scroll_BgAdd(s8 dx, s8 dy);
// Apply signed deltas to the byte-sized hardware window coordinates.
void Scroll_WindowAdd(s8 dx, s8 dy);
// Request window visibility through the compiler intrinsic.
void Scroll_WindowShow();
// Request that the window be hidden through the compiler intrinsic.
void Scroll_WindowHide();

// Clear the pending split table before building a new raster configuration.
void Scroll_SplitReset();
// Append a background-scroll split directly. Use Raster_Push when caller-side
// scanline ordering and capacity validation are desired.
void Scroll_SplitPush(u8 ly, u8 scx, u8 scy);
// Append an extended split with raw background/window fields and operation flags.
void Scroll_SplitPushEx(u8 ly, u8 scx, u8 scy, u8 wx, u8 wy, u8 flags);
// Reuse the two background-scroll fields to carry the low/high RGB15 bytes
// for a split whose operation flag selects background color zero.
void Scroll_SplitPushBgColor0(u8 ly, u16 rgb15);
// Publish the pending split configuration through the compiler runtime.
void Scroll_SplitCommit();

kitaqgb/lib/scroll.h

slg.h — 보드, 수 목록, 되돌리기
c
#pragma once

// A row-major byte board. Storage is borrowed; cell values and coordinates have game-defined meaning.
typedef __packed struct {
    u8 width;
    u8 height;
    u8* cells;
} SLGBoard;

typedef __packed struct {
    u8 x;
    u8 y;
    u8 value;
} SLGMove;

typedef __packed struct {
    SLGMove* items;
    u8 count;
    u8 capacity;
} SLGMoveList;

// Undo records are retained cell values only; popping one does not apply it to a board.
typedef __packed struct {
    SLGMove* items;
    u8 count;
    u8 capacity;
} SLGUndoStack;

// Attach width * height bytes of caller-owned cell storage without clearing it.
void slg_board_init(SLGBoard* board, u8 width, u8 height, u8* cells);
// Fill every cell with value; a null board is ignored. A valid board must own
// enough accessible cell storage for its declared dimensions.
void slg_board_clear(SLGBoard* board, u8 value);
// Return zero for a null board or out-of-range coordinate; otherwise read the
// cell. Zero therefore cannot distinguish an invalid lookup from an empty cell.
u8 slg_board_get(const SLGBoard* board, u8 x, u8 y);
// Write a cell only when the board and coordinate are valid.
void slg_board_set(SLGBoard* board, u8 x, u8 y, u8 value);
// Attach caller-owned move storage and reset the list length.
void slg_move_list_init(SLGMoveList* list, SLGMove* items, u8 capacity);
// Forget the moves without erasing their storage; a null list is ignored.
void slg_move_list_clear(SLGMoveList* list);
// Append coordinates and a value to the bounded move list. Return zero on a
// null/full list without replacing any existing move.
u8 slg_move_list_push(SLGMoveList* list, u8 x, u8 y, u8 value);
// Attach caller-owned undo records and initialize an empty stack.
void slg_undo_init(SLGUndoStack* stack, SLGMove* items, u8 capacity);
// Record a cell's previous value for later undo. Return zero if the stack is
// null or full; this function does not change the board itself.
u8 slg_undo_push(SLGUndoStack* stack, u8 x, u8 y, u8 old_value);
// Remove the newest undo record and optionally copy it out. A null output
// still discards the record; a null or empty stack returns zero.
u8 slg_undo_pop(SLGUndoStack* stack, SLGMove* out_move);

kitaqgb/lib/slg.h

sprite.h — OBJ 할당·배치, 메타스프라이트, 애니메이션
c
#pragma once

// Keep the default 40 for the standard DMA path. Hardware always transfers 160 bytes,
// even if this array is shortened; a custom layout must provide valid bytes for that full transfer.
#ifndef SPRITE_MAX
#define SPRITE_MAX 40
#endif

#define SPRITE_FLAG_PAL1     ((u8)0x10)
#define SPRITE_FLAG_XFLIP    ((u8)0x20)
#define SPRITE_FLAG_YFLIP    ((u8)0x40)
#define SPRITE_FLAG_PRIORITY ((u8)0x80)

// Packed hardware order is Y, X, tile, flags; screen coordinates need the GB OAM offsets.
typedef __packed struct {
    u8 y;
    u8 x;
    u8 tile;
    u8 flags;
} SpriteOamEntry;

extern __wram __aligned(256) SpriteOamEntry kq_sprite_oam[SPRITE_MAX];
extern u8 kq_sprite_active[SPRITE_MAX];
extern u8 kq_sprite_used;
extern u8 kq_sprite_height;

// Signed pixel displacements from a common origin; final byte coordinates wrap rather than clip.
typedef __packed struct {
    s8 dx;
    s8 dy;
    u8 tile;
    u8 flags;
} MetaSpritePart;

// Initialize frame/ticks within their configured ranges. This animation selects consecutive tile IDs;
// it does not change sprite size or automatically step by two tiles in 8x16 mode.
typedef __packed struct {
    u8 first_tile;
    u8 frame_count;
    u8 frame;
    u8 ticks;
    u8 ticks_per_frame;
} SpriteAnim;

void __wait_vblank();
void __oam_dma(u16 src_ptr);

// Clear allocation and shadow OAM state and reset the DMA-stub installation flag.
// The default height is eight pixels; the hardware display mode is configured elsewhere.
void sprite_init();
// Claim the first free slot, hide it, and return its ID; return 0xFF when full.
// Previously stored tile/flag bytes are retained until the caller replaces them.
u8 sprite_alloc();
// Release an allocated valid slot and hide it. Repeated frees do not decrement the count.
void sprite_free(u8 id);
// Convert screen coordinates to OAM coordinates by adding X=8 and Y=16.
// The byte additions wrap; this updates shadow storage even for an unallocated slot.
void sprite_set_pos(u8 id, u8 x, u8 y);
// Set a valid shadow slot's tile byte; allocation and hardware transfer are separate.
void sprite_set_tile(u8 id, u8 tile);
// Replace a valid shadow slot's complete hardware attribute byte.
void sprite_set_flags(u8 id, u8 flags);
// Move a valid shadow slot off screen without freeing it.
void sprite_hide(u8 id);
// Install the HRAM stub lazily and execute OAM DMA with interrupts disabled.
// This routine does not wait for VBlank and always enables interrupts afterward;
// it does not restore the caller's previous interrupt-enable state.
void sprite_flush_oam_now();
// Wait for VBlank, then transfer shadow OAM using the immediate DMA routine.
void sprite_flush_oam();
// Return the number of active slots, including slots activated by metasprite_draw.
// Hidden allocated slots remain active until sprite_free releases them.
u8 sprite_count_used();
// Report whether the software overlap estimate exceeds ten sprites on a scanline.
u8 sprite_warn_scanline_overflow();
// Estimate the largest overlap of active, non-hidden shadow sprites across
// visible scanlines using the configured sprite height. This is a software
// overlap count, not a rendered-pixel or hardware-priority simulation.
u8 sprite_max_scanline_count();
// Place consecutive parts, counting each newly activated slot once. Existing
// active slots are overwritten without increasing the allocation count. Return
// the number written; an invalid first slot or zero count writes nothing.
u8 metasprite_draw(u8 first_id, u8 x, u8 y, const MetaSpritePart* parts, u8 count);
// Advance animation ticks/frame with wrapping frame selection and return the
// resulting tile. Zero ticks-per-frame freezes animation; null state returns zero.
u8 anim_update(SpriteAnim* anim);

kitaqgb/lib/sprite.h

sprite_order.h — 우선순위와 순환에 따른 스프라이트 선택
c
#pragma once
// Copyright (c) 2026 DAISUKE OBA. MIT License.

// Hardware-compatible layout without requiring the sprite allocator or its
// global storage. Cast a sprite.h shadow buffer to this type when combining
// the libraries; both layouts contain exactly Y, X, tile and flags bytes.
typedef __packed struct {
    u8 y;
    u8 x;
    u8 tile;
    u8 flags;
} SpriteOrderOamEntry;

#define SPRITE_ORDER_LEVELS 4
#define SPRITE_ORDER_OAM_COUNT 40

// One submitted, visible sprite. Attributes retain their hardware meaning;
// priority 0..3 controls OAM selection order, not the BG-over-OBJ flag.
typedef __packed struct {
    SpriteOrderOamEntry oam;
    u8 priority;
} SpriteOrderItem;

// Caller-owned foreground state. Capacity is 1..255 items; count includes only
// accepted submissions. Rebuild the same logical submission list each frame so
// phase rotation distributes selection among equal-priority sprites.
typedef struct {
    SpriteOrderItem* items;
    u8 capacity;
    u8 count;
    u8 height;
    u8 phase;
} SpriteOrder;

// Bind writable item storage and select the hardware sprite height (8 or 16).
// Return 1 on success. Invalid storage, zero capacity or another height returns
// 0 and leaves a non-null state disabled. A null state returns 0 without writes.
u8 sprite_order_init(SpriteOrder* order, SpriteOrderItem* items, u8 capacity, u8 height);

// Discard this frame's submissions while preserving storage, height and phase.
// A null state is ignored. Call once before submitting the next frame's sprites.
void sprite_order_begin(SpriteOrder* order);

// Submit one sprite at signed, top-left SCREEN pixel coordinates. Preserve the
// tile and attribute bytes; use priority 0 (first) through 3 (last). Fully
// off-screen sprites, invalid priorities, disabled state and full storage return
// 0 without consuming a slot. Partly visible sprites are accepted. Return 1 on
// acceptance. Hardware 8x16 mode still ignores the tile index's low bit.
u8 sprite_order_push(SpriteOrder* order, s16 x, s16 y, u8 tile, u8 flags, u8 priority);

// Write a complete 160-byte shadow OAM: ascending priority, then cyclic order
// within each priority. Clamp limit to 40, return the number emitted and zero
// all unused entries (including Y) so they cannot consume scanline slots.
// Advance phase once for a nonempty valid queue, even when limit is zero.
// Empty queues reset phase to zero. Null/disabled/corrupt state or null output
// returns 0 without modifying output or phase.
// Output must provide 40 entries and must not overlap item/state storage.
// This only writes RAM. Build in foreground, then transfer during VBlank.
// DMG overlap priority also depends on X: this cannot override that hardware
// rule. OAM order chooses the first ten sprites per scanline on both DMG/CGB.
// It neither updates sprite_alloc's bookkeeping nor performs OAM DMA.
u8 sprite_order_build(SpriteOrder* order, SpriteOrderOamEntry* output, u8 limit);

kitaqgb/lib/sprite_order.h

system.h — 시작, 프레임 수, 대기, 인터럽트
c
#pragma once

// This callback runs in the caller of system_wait_vblank, not as an installed ISR.
// Its plain pointer has no ROM bank component; keep the target callable in that mapping.
typedef void (*SystemCallback)();

extern u16 kq_system_frame;

void __wait_vblank();

// Reset the software frame counter and remove any registered callback.
void system_init();
// Wait for VBlank, count this wrapper call, then invoke the callback synchronously.
// The counter wraps at 16 bits and is not an independent hardware frame clock.
void system_wait_vblank();
// Replace the callback used by system_wait_vblank; null disables the callback.
void system_set_vblank_callback(SystemCallback callback);
// Read the software count of completed system_wait_vblank calls.
u16 system_get_frame();
// Return the low byte of the software frame counter for wrapping 8-bit timing.
u8 system_get_frame8();
// Enable CPU interrupts and return using the inline-assembly function body.
void system_enable_interrupts();
// Disable CPU interrupts and return; callers must explicitly re-enable them later.
void system_disable_interrupts();

#define gb_init system_init
#define gb_wait_vblank system_wait_vblank
#define gb_set_vblank_callback system_set_vblank_callback
#define gb_frame_count system_get_frame
#define gb_enable_interrupts system_enable_interrupts
#define gb_disable_interrupts system_disable_interrupts

kitaqgb/lib/system.h

vram.h — 큐를 통한 VRAM 갱신과 전송
c
#pragma once

// Keep this capacity in 1..255 in all units; counts and capacity/free return values are bytes.
#ifndef VRAM_QUEUE_MAX
#define VRAM_QUEUE_MAX 32
#endif

#define VRAM_CMD_BG_TILE   ((u8)1)
#define VRAM_CMD_BG_RECT   ((u8)2)
#define VRAM_CMD_BG_BLOCK  ((u8)3)
#define VRAM_CMD_MEMCPY    ((u8)4)
#define VRAM_CMD_MEMSET    ((u8)5)

// A command owns metadata only. src is a retained near pointer with no bank number or copied payload.
typedef __packed struct {
    u8 kind;
    u8 x;
    u8 y;
    u8 w;
    u8 h;
    u8 value;
    u16 dst;
    const u8* src;
    u16 len;
} VramCommand;

extern VramCommand kq_vram_queue[VRAM_QUEUE_MAX];
extern u8 kq_vram_queue_used;
extern u8 kq_vram_queue_overflowed;

void __wait_vblank();
void __settile_xy(u8 x, u8 y, u8 tile);
void __settile_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
void __settilemap_rect(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);
void __vram_copy(u16 dst, const void* src, u16 len);
void __vram_fill(u16 dst, u8 value, u16 len);

// Start with an empty command queue and a clear overflow flag.
void vram_init();
// Discard pending commands and clear the latched overflow flag without writing VRAM.
void vram_clear_queue();
// Queue a single background tile write; return zero if no command slot is available.
u8 vram_queue_bg_tile(u8 x, u8 y, u8 tile);
// Provide the short alias for a queued background tile write.
u8 vram_queue_tile(u8 x, u8 y, u8 tile);
// Queue a rectangle filled with one tile value; coordinates and dimensions are in tiles.
u8 vram_queue_bg_rect(u8 x, u8 y, u8 w, u8 h, u8 tile);
// Queue a tile-map rectangle while retaining src rather than copying its bytes.
// Keep the source data and its ROM bank accessible until the queue is flushed.
u8 vram_queue_bg_block(u16 base, u8 x, u8 y, u8 w, u8 h, const u8* src);
// Queue a byte transfer and retain the source pointer. The source must remain
// valid and visible until flush; len is measured in bytes, not tiles.
u8 vram_queue_memcpy(u16 dst, const void* src, u16 len);
// Alias the queued byte-copy operation; this does not convert a tile count to bytes.
u8 vram_queue_tiles(u16 dst, const void* src, u16 len);
// Queue a byte fill and return zero if the command queue is full.
u8 vram_queue_memset(u16 dst, u8 value, u16 len);
// Execute pending commands in insertion order without waiting for VBlank here.
// The caller must arrange suitable VRAM access timing and a sufficient transfer budget.
// Only the used count is cleared; overflow stays latched until an explicit reset.
void vram_flush_now();
// Wait for VBlank before executing the queue. Waiting once does not itself limit
// the queued workload to the available VBlank duration.
void vram_flush();
// Return the number of queued commands, not the number of transfer bytes.
u8 vram_get_queue_used();
// Return the total number of command slots, independent of queue usage.
// This is command-buffer capacity, not free space in hardware VRAM.
u8 vram_get_queue_capacity();
// Return the remaining command-slot capacity.
u8 vram_get_queue_free();
// Read the overflow latch without clearing it.
u8 vram_get_overflowed();

kitaqgb/lib/vram.h

wire3d.h — DMG용 와이어프레임
c
// Compatibility names for the shared wire3d_dmg renderer.
// Select the same profile in every translation unit; compile one renderer entry.
#pragma once
#ifndef WIRE3D_DMG_HEIGHT
#define WIRE3D_DMG_HEIGHT 96
#endif
#if WIRE3D_DMG_HEIGHT != 96
#error Incompatible wire3d_dmg profile
#endif
#include "wire3d_dmg.h"

#define W3D_BG_QUEUE_LIMIT WIRE3D_DMG_BG_QUEUE_LIMIT
#define W3D_CENTER_X WIRE3D_DMG_CENTER_X
#define W3D_CENTER_Y WIRE3D_DMG_CENTER_Y
#define W3D_FAR_Z WIRE3D_DMG_FAR_Z
#define W3D_HUD_TILE_BASE WIRE3D_DMG_HUD_TILE_BASE
#define W3D_HUD_TILE_BLANK WIRE3D_DMG_HUD_TILE_BLANK
#define W3D_HUD_TILE_COUNT WIRE3D_DMG_HUD_TILE_COUNT
#define W3D_NEAR_Z WIRE3D_DMG_NEAR_Z
#define W3D_PROJECT_LIMIT WIRE3D_DMG_PROJECT_LIMIT
#define W3D_ROW_BYTES WIRE3D_DMG_ROW_BYTES
#define W3D_TILE_H WIRE3D_DMG_TILE_H
#define W3D_TILE_W WIRE3D_DMG_TILE_W
#define W3D_TRANSFORM_LIMIT WIRE3D_DMG_TRANSFORM_LIMIT
#define WIRE3D_EDGE_MASK_BINS_16 WIRE3D_DMG_EDGE_MASK_BINS_16
#define WIRE3D_FACE_NONE WIRE3D_DMG_FACE_NONE
#define WIRE3D_MODEL_EDGE_LIMIT WIRE3D_DMG_MODEL_EDGE_LIMIT
#define WIRE3D_MODEL_FACE_LIMIT WIRE3D_DMG_MODEL_FACE_LIMIT
#define WIRE3D_MODEL_HIDDEN_LINES WIRE3D_DMG_MODEL_HIDDEN_LINES
#define WIRE3D_MODEL_VERTEX_LIMIT WIRE3D_DMG_MODEL_VERTEX_LIMIT
#define WIRE3D_SCENE_OBJECT_LIMIT WIRE3D_DMG_SCENE_OBJECT_LIMIT
#define WIRE3D_SCREEN_H WIRE3D_DMG_SCREEN_H
#define WIRE3D_SCREEN_W WIRE3D_DMG_SCREEN_W
#define Wire3D_BeginFrame Wire3DDMG_BeginFrame
#define Wire3D_DrawLine2D Wire3DDMG_DrawLine2D
#define Wire3D_DrawLine3D Wire3DDMG_DrawLine3D
#define Wire3D_DrawModel Wire3DDMG_DrawModel
#define Wire3D_DrawModelScaled Wire3DDMG_DrawModelScaled
#define Wire3D_DrawScene Wire3DDMG_DrawScene
#define Wire3D_Edge Wire3DDMG_Edge
#define Wire3D_EdgeFaces Wire3DDMG_EdgeFaces
#define Wire3D_EndFrame Wire3DDMG_EndFrame
#define Wire3D_EraseModelFaces Wire3DDMG_EraseModelFaces
#define Wire3D_EraseSpan2D Wire3DDMG_EraseSpan2D
#define Wire3D_EraseTriangle2D Wire3DDMG_EraseTriangle2D
#define Wire3D_Face Wire3DDMG_Face
#define Wire3D_Init Wire3DDMG_Init
#define Wire3D_Model Wire3DDMG_Model
#define Wire3D_Object Wire3DDMG_Object
#define Wire3D_ProjectPoint Wire3DDMG_ProjectPoint
#define Wire3D_PutBgTile Wire3DDMG_PutBgTile
#define Wire3D_SelectEdgeMask Wire3DDMG_SelectEdgeMask
#define Wire3D_SetCamera Wire3DDMG_SetCamera
#define Wire3D_SetPalette Wire3DDMG_SetPalette
#define Wire3D_Vec3 Wire3DDMG_Vec3
#define w3d_abs_i16 w3ddmg_abs_i16
#define w3d_bg_map_9800 w3ddmg_bg_map_9800
#define w3d_bgq_addr_hi w3ddmg_bgq_addr_hi
#define w3d_bgq_addr_lo w3ddmg_bgq_addr_lo
#define w3d_bgq_count w3ddmg_bgq_count
#define w3d_bgq_tile w3ddmg_bgq_tile
#define w3d_bgq_value w3ddmg_bgq_value
#define w3d_bgq_x w3ddmg_bgq_x
#define w3d_bgq_y w3ddmg_bgq_y
#define w3d_bit_mask w3ddmg_bit_mask
#define w3d_build_edge_flags w3ddmg_build_edge_flags
#define w3d_build_face_visibility w3ddmg_build_face_visibility
#define w3d_cam_pitch w3ddmg_cam_pitch
#define w3d_cam_roll w3ddmg_cam_roll
#define w3d_cam_x w3ddmg_cam_x
#define w3d_cam_y w3ddmg_cam_y
#define w3d_cam_yaw w3ddmg_cam_yaw
#define w3d_cam_z w3ddmg_cam_z
#define w3d_clamp_i16 w3ddmg_clamp_i16
#define w3d_clamp_screen w3ddmg_clamp_screen
#define w3d_clear_occlusion_mask w3ddmg_clear_occlusion_mask
#define w3d_clear_occlusion_mask_asm w3ddmg_clear_occlusion_mask_asm
#define w3d_clear_stage_asm w3ddmg_clear_stage_asm
#define w3d_clear_triangle w3ddmg_clear_triangle
#define w3d_clear_vram_asm w3ddmg_clear_vram_asm
#define w3d_cos_q6 w3ddmg_cos_q6
#define w3d_edge_area w3ddmg_edge_area
#define w3d_edge_flags w3ddmg_edge_flags
#define w3d_face_visible w3ddmg_face_visible
#define w3d_fill_bg_map_asm w3ddmg_fill_bg_map_asm
#define w3d_flush_bg_queue w3ddmg_flush_bg_queue
#define w3d_hud_tiles w3ddmg_hud_tiles
#define w3d_i16 w3ddmg_i16
#define w3d_i8 w3ddmg_i8
#define w3d_inv_depth w3ddmg_inv_depth
#define w3d_is_edge_visible w3ddmg_is_edge_visible
#define w3d_line_dx w3ddmg_line_dx
#define w3d_line_dy w3ddmg_line_dy
#define w3d_line_err w3ddmg_line_err
#define w3d_line_stage_asm w3ddmg_line_stage_asm
#define w3d_line_stage_masked_c w3ddmg_line_stage_masked_c
#define w3d_line_sx w3ddmg_line_sx
#define w3d_line_sy w3ddmg_line_sy
#define w3d_line_x w3ddmg_line_x
#define w3d_line_x0 w3ddmg_line_x0
#define w3d_line_x1 w3ddmg_line_x1
#define w3d_line_y w3ddmg_line_y
#define w3d_line_y0 w3ddmg_line_y0
#define w3d_line_y1 w3ddmg_line_y1
#define w3d_load_hud_tiles w3ddmg_load_hud_tiles
#define w3d_mark_model_occluder w3ddmg_mark_model_occluder
#define w3d_mark_triangle w3ddmg_mark_triangle
#define w3d_mask_get w3ddmg_mask_get
#define w3d_mask_offset w3ddmg_mask_offset
#define w3d_mask_set w3ddmg_mask_set
#define w3d_mask_set_span w3ddmg_mask_set_span
#define w3d_neg_angle w3ddmg_neg_angle
#define w3d_occlusion_active w3ddmg_occlusion_active
#define w3d_occlusion_mask w3ddmg_occlusion_mask
#define w3d_pair_block w3ddmg_pair_block
#define w3d_pair_wait_0 w3ddmg_pair_wait_0
#define w3d_pair_wait_1 w3ddmg_pair_wait_1
#define w3d_pair_wait_10 w3ddmg_pair_wait_10
#define w3d_pair_wait_11 w3ddmg_pair_wait_11
#define w3d_pair_wait_12 w3ddmg_pair_wait_12
#define w3d_pair_wait_13 w3ddmg_pair_wait_13
#define w3d_pair_wait_14 w3ddmg_pair_wait_14
#define w3d_pair_wait_15 w3ddmg_pair_wait_15
#define w3d_pair_wait_2 w3ddmg_pair_wait_2
#define w3d_pair_wait_3 w3ddmg_pair_wait_3
#define w3d_pair_wait_4 w3ddmg_pair_wait_4
#define w3d_pair_wait_5 w3ddmg_pair_wait_5
#define w3d_pair_wait_6 w3ddmg_pair_wait_6
#define w3d_pair_wait_7 w3ddmg_pair_wait_7
#define w3d_pair_wait_8 w3ddmg_pair_wait_8
#define w3d_pair_wait_9 w3ddmg_pair_wait_9
#define w3d_plot_stage_asm w3ddmg_plot_stage_asm
#define w3d_plot_tx w3ddmg_plot_tx
#define w3d_plot_x w3ddmg_plot_x
#define w3d_plot_y w3ddmg_plot_y
#define w3d_project_camera_space w3ddmg_project_camera_space
#define w3d_project_world w3ddmg_project_world
#define w3d_put_bg_tile_safe_asm w3ddmg_put_bg_tile_safe_asm
#define w3d_reg_bgp w3ddmg_reg_bgp
#define w3d_reg_lcdc w3ddmg_reg_lcdc
#define w3d_reg_ly w3ddmg_reg_ly
#define w3d_reg_scx w3ddmg_reg_scx
#define w3d_reg_scy w3ddmg_reg_scy
#define w3d_rotate_x w3ddmg_rotate_x
#define w3d_rotate_y w3ddmg_rotate_y
#define w3d_rotate_z w3ddmg_rotate_z
#define w3d_scene_depth w3ddmg_scene_depth
#define w3d_scene_object_depth w3ddmg_scene_object_depth
#define w3d_scene_order w3ddmg_scene_order
#define w3d_screen_delta w3ddmg_screen_delta
#define w3d_screen_visible w3ddmg_screen_visible
#define w3d_screen_x w3ddmg_screen_x
#define w3d_screen_y w3ddmg_screen_y
#define w3d_sin_q6 w3ddmg_sin_q6
#define w3d_stage w3ddmg_stage
#define w3d_stage_clear_pixel w3ddmg_stage_clear_pixel
#define w3d_stage_clear_span w3ddmg_stage_clear_span
#define w3d_transfer_stage_asm w3ddmg_transfer_stage_asm
#define w3d_u16 w3ddmg_u16
#define w3d_u8 w3ddmg_u8
#define w3d_vram_tiles w3ddmg_vram_tiles
#define w3d_wait_vblank_start w3ddmg_wait_vblank_start
#define w3dbg_enter w3ddmgbg_enter
#define w3dco_enter w3ddmgco_enter
#define w3dco_loop w3ddmgco_loop
#define w3dco_page w3ddmgco_page
#define w3dcs_enter w3ddmgcs_enter
#define w3dcs_inner w3ddmgcs_inner
#define w3dcs_outer w3ddmgcs_outer
#define w3dcv_enter w3ddmgcv_enter
#define w3dcv_loop w3ddmgcv_loop
#define w3dcv_page w3ddmgcv_page
#define w3dfb_enter w3ddmgfb_enter
#define w3dfb_loop w3ddmgfb_loop
#define w3dfb_page w3ddmgfb_page
#define w3dls_branch w3ddmgls_branch
#define w3dls_done w3ddmgls_done
#define w3dls_enter w3ddmgls_enter
#define w3dls_shallow w3ddmgls_shallow
#define w3dls_shallow_loop w3ddmgls_shallow_loop
#define w3dls_shallow_skip_bridge w3ddmgls_shallow_skip_bridge
#define w3dls_steep w3ddmgls_steep
#define w3dls_steep_loop w3ddmgls_steep_loop
#define w3dls_steep_skip_bridge w3ddmgls_steep_skip_bridge
#define w3dls_x_reverse w3ddmgls_x_reverse
#define w3dls_y_reverse w3ddmgls_y_reverse
#define w3dls_y_start w3ddmgls_y_start
#define w3dps_enter w3ddmgps_enter
#define w3dps_ret w3ddmgps_ret

kitaqgb/lib/wire3d.h

wire3d_cgb.h — CGB용 컬러 와이어프레임
c
#pragma once

#ifndef KITAQGB_WIRE3D_CGB_H
#define KITAQGB_WIRE3D_CGB_H

#define WIRE3DCGB_SCREEN_W 128
#ifndef WIRE3DCGB_HEIGHT
#define WIRE3DCGB_HEIGHT 96
#endif
#if WIRE3DCGB_HEIGHT != 88 && WIRE3DCGB_HEIGHT != 96
#error WIRE3DCGB_HEIGHT must be 88 or 96
#endif
#define WIRE3DCGB_SCREEN_H WIRE3DCGB_HEIGHT
#if WIRE3DCGB_HEIGHT == 88
#define WIRE3DCGB_TILE_ROWS 11
#define WIRE3DCGB_TILE_COUNT 176
#define WIRE3DCGB_COLUMN_BYTES 176
#define WIRE3DCGB_NEG_COLUMN_BYTES 0xFF50
#define WIRE3DCGB_STAGE_RIGHT 0xDD50
#define WIRE3DCGB_STAGE_BOTTOM 0xD3AE
#define WIRE3DCGB_SECOND_DMA 0xAF
#else
#define WIRE3DCGB_TILE_ROWS 12
#define WIRE3DCGB_TILE_COUNT 192
#define WIRE3DCGB_COLUMN_BYTES 192
#define WIRE3DCGB_NEG_COLUMN_BYTES 0xFF40
#define WIRE3DCGB_STAGE_RIGHT 0xDE40
#define WIRE3DCGB_STAGE_BOTTOM 0xD3BE
#define WIRE3DCGB_SECOND_DMA 0xBF
#endif
// Reserve 3072 bytes in either profile for full-screen compatibility.
#define WIRE3DCGB_UPLOAD_BYTES (WIRE3DCGB_TILE_COUNT * 16)
#define WIRE3DCGB_FULL_SCREEN_W 160
#define WIRE3DCGB_FULL_SCREEN_H 144
#define WIRE3DCGB_FULL_TILE_LIMIT 127
#define WIRE3DCGB_STAGE_BASE 0xD300
#define WIRE3DCGB_STAGE_WRAM_BANK 2
#define WIRE3DCGB_STAGE_BYTES 3072
#define WIRE3DCGB_MODEL_VERTEX_LIMIT 24
#define WIRE3DCGB_MODEL_FACE_LIMIT 16
#define WIRE3DCGB_MODEL_EDGE_LIMIT 64
#define WIRE3DCGB_SCENE_OBJECT_LIMIT 8
#define WIRE3DCGB_FACE_NONE 255
#define WIRE3DCGB_MODEL_HIDDEN_LINES 1
#define WIRE3DCGB_COLOR_LOW 1
#define WIRE3DCGB_COLOR_MAIN 2
#define WIRE3DCGB_COLOR_HIGH 3
#define WIRE3DCGB_COLOR_DEFAULT WIRE3DCGB_COLOR_MAIN

#define WIRE3DCGB_RGB15(r5, g5, b5) ((w3dcgb_u16)((w3dcgb_u16)((r5) & 31) | ((w3dcgb_u16)((g5) & 31) << 5) | ((w3dcgb_u16)((b5) & 31) << 10)))

typedef s8 w3dcgb_i8;
typedef s16 w3dcgb_i16;
typedef u8 w3dcgb_u8;
typedef u16 w3dcgb_u16;

typedef struct {
    w3dcgb_i16 x;
    w3dcgb_i16 y;
    w3dcgb_i16 z;
} Wire3DCGB_Vec3;

typedef struct {
    w3dcgb_u8 a;
    w3dcgb_u8 b;
} Wire3DCGB_Edge;

typedef struct {
    w3dcgb_u8 a;
    w3dcgb_u8 b;
    w3dcgb_u8 c;
} Wire3DCGB_Face;

typedef struct {
    w3dcgb_u8 f0;
    w3dcgb_u8 f1;
} Wire3DCGB_EdgeFaces;

typedef struct {
    const Wire3DCGB_Vec3* vertices;
    const Wire3DCGB_Edge* edges;
    const Wire3DCGB_Face* faces;
    const Wire3DCGB_EdgeFaces* edge_faces;
    w3dcgb_u8 vertex_count;
    w3dcgb_u8 edge_count;
    w3dcgb_u8 face_count;
    w3dcgb_u8 flags;
} Wire3DCGB_Model;

typedef struct {
    const Wire3DCGB_Model* model;
    w3dcgb_i16 x;
    w3dcgb_i16 y;
    w3dcgb_i16 z;
    w3dcgb_i8 rx;
    w3dcgb_i8 ry;
    w3dcgb_i8 rz;
    w3dcgb_i16 scale_q8;
    w3dcgb_u8 visible;
    w3dcgb_u8 color;
} Wire3DCGB_Object;

typedef struct {
    w3dcgb_i16 x;
    w3dcgb_i16 y;
    w3dcgb_i16 z;
    w3dcgb_i8 rx;
    w3dcgb_i8 ry;
    w3dcgb_i8 rz;
    w3dcgb_u8 color;
} Wire3DCGB_FastCube;

void Wire3DCGB_Init();
void Wire3DCGB_InitFullScreen();
void Wire3DCGB_InitFastMapLite();
void Wire3DCGB_EnableDoubleSpeed();
void Wire3DCGB_SetScreenOffset(w3dcgb_u8 scx, w3dcgb_u8 scy);
void Wire3DCGB_SetPaletteRGB15(w3dcgb_u16 color0, w3dcgb_u16 color1, w3dcgb_u16 color2, w3dcgb_u16 color3);
void Wire3DCGB_SetLineColor(w3dcgb_u8 color);
w3dcgb_u8 Wire3DCGB_GetLineColor();
void Wire3DCGB_ClearFrameTiles();
void Wire3DCGB_BeginFrame();
void Wire3DCGB_BeginFrameFast();
void Wire3DCGB_BeginFrameSparse();
void Wire3DCGB_ClearSparseStageFast();
void Wire3DCGB_MarkDirtyRect2D(w3dcgb_u8 min_x, w3dcgb_u8 min_y, w3dcgb_u8 max_x, w3dcgb_u8 max_y);
void Wire3DCGB_SetCamera(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 pitch, w3dcgb_i8 yaw, w3dcgb_i8 roll);
void Wire3DCGB_DrawModel(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz);
void Wire3DCGB_DrawModelScaled(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8);
void Wire3DCGB_DrawModelColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_u8 color);
void Wire3DCGB_DrawModelScaledColor(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8, w3dcgb_u8 color);
void Wire3DCGB_EraseModelFaces(const Wire3DCGB_Model* model, w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_i8 rx, w3dcgb_i8 ry, w3dcgb_i8 rz, w3dcgb_i16 scale_q8);
void Wire3DCGB_EraseTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);
void Wire3DCGB_EraseSpan2D(w3dcgb_u8 y, w3dcgb_u8 x0, w3dcgb_u8 x1);
/* Signed endpoints, clipped before conversion to the rasterizer's u8 ABI. */
void Wire3DCGB_DrawLineClipped2D(w3dcgb_i16 x0, w3dcgb_i16 y0,
                               w3dcgb_i16 x1, w3dcgb_i16 y1, w3dcgb_u8 color);
void Wire3DCGB_DrawEdgeListClipped2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count,
    const w3dcgb_i16* vx, const w3dcgb_i16* vy, w3dcgb_u8 vertex_count,
    w3dcgb_i16 cx, w3dcgb_i16 cy, w3dcgb_u8 color);
w3dcgb_i16 Wire3DCGB_ProjectAxis48(w3dcgb_i16 value, w3dcgb_i16 z);
void Wire3DCGB_InvalidateFrameHistory();
/* Startup-only: reserves both BG maps; queued HUD tiles are mirrored. */
void Wire3DCGB_EnableAtomicMaps();
void Wire3DCGB_EraseRect2D(w3dcgb_u8 x0, w3dcgb_u8 y0, w3dcgb_u8 x1, w3dcgb_u8 y1);
void Wire3DCGB_EraseLeftGuard24Fast();
void Wire3DCGB_DrawWhiteBorderFast();
void Wire3DCGB_ClearOcclusionMask();
void Wire3DCGB_SetOcclusionActive(w3dcgb_u8 active);
void Wire3DCGB_MarkTriangle2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 cx, w3dcgb_u8 cy);
void Wire3DCGB_MarkPackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count,
                                     w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);
void Wire3DCGB_ErasePackedSilhouette2D(const w3dcgb_u8* profile, w3dcgb_u8 count,
                                      w3dcgb_i8 y0, w3dcgb_u8 x, w3dcgb_u8 y);
void Wire3DCGB_DrawScene(Wire3DCGB_Object* objects, w3dcgb_u8 count);
void Wire3DCGB_DrawFastCubes(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);
void Wire3DCGB_DrawFastStatus(w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);
void Wire3DCGB_DrawFastCubeFrame(Wire3DCGB_FastCube* cubes, w3dcgb_u8 count, w3dcgb_u8 hidden_enabled, w3dcgb_u8 selected);
void Wire3DCGB_DrawFastProjectile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_i16 z, w3dcgb_u8 phase, w3dcgb_u8 color);
void Wire3DCGB_FastMapBegin();
void Wire3DCGB_FastMapBeginTilesOnly();
void Wire3DCGB_FastMapCell(w3dcgb_u8 tx, w3dcgb_u8 ty, w3dcgb_u8 color, w3dcgb_u8 mask);
void Wire3DCGB_FastMapRect(w3dcgb_u8 tx0, w3dcgb_u8 ty0, w3dcgb_u8 tx1, w3dcgb_u8 ty1, w3dcgb_u8 color, w3dcgb_u8 sides);
void Wire3DCGB_FastMapFlush();
void Wire3DCGB_FastMapFlushTilesOnly();
// Project camera-space coordinates without subtracting/rotating the camera.
// Depth 8..255; outputs unchanged on rejection. Shared scratch: no ISR calls.
w3dcgb_u8 Wire3DCGB_ProjectCameraPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);
w3dcgb_u8 Wire3DCGB_ProjectPoint(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);
/* Fast path for games whose camera pitch, yaw, and roll stay at zero. */
w3dcgb_u8 Wire3DCGB_ProjectPointNoRotation(w3dcgb_i16 x, w3dcgb_i16 y, w3dcgb_i16 z, w3dcgb_u8* sx, w3dcgb_u8* sy);
void Wire3DCGB_DrawLine3D(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz);
void Wire3DCGB_DrawLine3DColor(w3dcgb_i16 ax, w3dcgb_i16 ay, w3dcgb_i16 az, w3dcgb_i16 bx, w3dcgb_i16 by, w3dcgb_i16 bz, w3dcgb_u8 color);
void Wire3DCGB_DrawPoint2D(w3dcgb_u8 x, w3dcgb_u8 y);
void Wire3DCGB_DrawTinyModel2D(w3dcgb_u8 x, w3dcgb_u8 y,
                               w3dcgb_u8 turn, w3dcgb_u8 color);
void Wire3DCGB_DrawLine2D(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by);
void Wire3DCGB_DrawLine2DColor(w3dcgb_u8 ax, w3dcgb_u8 ay, w3dcgb_u8 bx, w3dcgb_u8 by, w3dcgb_u8 color);
void Wire3DCGB_DrawMaskedModel2D(const Wire3DCGB_Model* model,
                                 const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y,
                                 const w3dcgb_u8* edge_mask,
                                 w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color);
void Wire3DCGB_DrawEdgeList2D(const Wire3DCGB_Edge* edges, w3dcgb_u8 edge_count,
                              const w3dcgb_i8* vertex_x, const w3dcgb_i8* vertex_y,
                              w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 color);
void Wire3DCGB_DrawLineList2DColor(const w3dcgb_u8* line_xy,
                                  w3dcgb_u8 line_count, w3dcgb_u8 color);
void Wire3DCGB_PutBgTile(w3dcgb_u8 x, w3dcgb_u8 y, w3dcgb_u8 tile);
void Wire3DCGB_EndFrame();
void Wire3DCGB_EndFrameFast();
void Wire3DCGB_EndFrameSparse();
void Wire3DCGB_EndFrameSparseNow();
w3dcgb_u8 Wire3DCGB_GetFullScreenTileCount();
w3dcgb_u8 Wire3DCGB_GetFullScreenOverflow();

#endif

kitaqgb/lib/wire3d_cgb.h

wire3d_dmg.h — DMG용 와이어프레임
c
#pragma once

// Select the viewport at build time before including this header or source.
// Default: 128x120 with consuming uploads and optional dirty/auxiliary transfer.
// Heights 88 and 96 retain the HUD and yaw-mask profile with BeginFrame clearing.
#ifndef WIRE3D_DMG_HEIGHT
#define WIRE3D_DMG_HEIGHT 120
#endif
#if WIRE3D_DMG_HEIGHT != 88 && WIRE3D_DMG_HEIGHT != 96 && WIRE3D_DMG_HEIGHT != 120
#error WIRE3D_DMG_HEIGHT must be 88, 96 or 120
#endif


#ifndef KITAQGB_WIRE3D_DMG_H
#define KITAQGB_WIRE3D_DMG_H

#if WIRE3D_DMG_HEIGHT != 120
// Monochrome 128x88/96 wireframe renderer with global, non-reentrant state.
// It takes over LCD tile data/map and reserves WRAM 0xD000..0xDFFF for staging.
// Angles wrap every 16 steps; scale 256 is unity. Scene occlusion is a coarse
// face-bounding-box/five-line-sample heuristic, not per-pixel depth testing.
#else
// Monochrome 128x120 staged renderer with global non-reentrant state.
// Reserve WRAM 0xD000..0xDFFF and the renderer's tile/map VRAM regions.
// BeginFrame does not clear pixels: uploads consume the stage. Auxiliary source
// strips alias the main stage, and dirty transfer relies on current/previous flags.
#endif
#define WIRE3D_DMG_SCREEN_W 128
#if WIRE3D_DMG_HEIGHT != 120
#define WIRE3D_DMG_SCREEN_H WIRE3D_DMG_HEIGHT
#else
#define WIRE3D_DMG_SCREEN_H 120
#endif
#define WIRE3D_DMG_MODEL_VERTEX_LIMIT 24
#if WIRE3D_DMG_HEIGHT != 120
#define WIRE3D_DMG_MODEL_EDGE_LIMIT 16
#endif
#define WIRE3D_DMG_MODEL_FACE_LIMIT 16
#define WIRE3D_DMG_SCENE_OBJECT_LIMIT 8
#define WIRE3D_DMG_FACE_NONE 255
#define WIRE3D_DMG_MODEL_HIDDEN_LINES 1
#if WIRE3D_DMG_HEIGHT != 120
#define WIRE3D_DMG_EDGE_MASK_BINS_16 16
#else
#define WIRE3D_DMG_ANGLE_STEPS 16
#endif

typedef s8 w3ddmg_i8;
typedef s16 w3ddmg_i16;
typedef u8 w3ddmg_u8;
typedef u16 w3ddmg_u16;

typedef struct {
    w3ddmg_i16 x;
    w3ddmg_i16 y;
    w3ddmg_i16 z;
} Wire3DDMG_Vec3;

typedef struct {
    w3ddmg_u8 a;
    w3ddmg_u8 b;
} Wire3DDMG_Edge;

typedef struct {
    w3ddmg_u8 a;
    w3ddmg_u8 b;
    w3ddmg_u8 c;
} Wire3DDMG_Face;

typedef struct {
    w3ddmg_u8 f0;
    w3ddmg_u8 f1;
} Wire3DDMG_EdgeFaces;

#if WIRE3D_DMG_HEIGHT != 120
// Model tables are borrowed for drawing, never copied or bank-switched.
// Counts are capped at 24 vertices, 16 edges and 16 faces; each supplied table
// must contain the referenced entries. Triangle winding with positive projected
// area is front-facing. FACE_NONE denotes a missing adjacent face.
#else
// Model tables are borrowed and must remain readable in the active bank.
// At most 24 vertices and 16 faces are processed; the model edge count is not
// limited to 16. Supply all declared edge and adjacency entries. Positive
// projected triangle area is front-facing; FACE_NONE means missing adjacency.
#endif
typedef struct {
    const Wire3DDMG_Vec3* vertices;
    const Wire3DDMG_Edge* edges;
    const Wire3DDMG_Face* faces;
    const Wire3DDMG_EdgeFaces* edge_faces;
#if WIRE3D_DMG_HEIGHT != 120
    /* Keep edge mask tables in RAM for pointer-indirect access on current KITAQGB. */
    const w3ddmg_u16* edge_masks;
#endif
    w3ddmg_u8 vertex_count;
    w3ddmg_u8 edge_count;
    w3ddmg_u8 face_count;
#if WIRE3D_DMG_HEIGHT != 120
    w3ddmg_u8 edge_mask_count;
#endif
    w3ddmg_u8 flags;
} Wire3DDMG_Model;

typedef struct {
    const Wire3DDMG_Model* model;
    w3ddmg_i16 x;
    w3ddmg_i16 y;
    w3ddmg_i16 z;
#if WIRE3D_DMG_HEIGHT != 120
    w3ddmg_i8 rx;
    w3ddmg_i8 ry;
    w3ddmg_i8 rz;
#else
    w3ddmg_u8 rx;
    w3ddmg_u8 ry;
    w3ddmg_u8 rz;
#endif
    w3ddmg_i16 scale_q8;
    w3ddmg_u8 visible;
} Wire3DDMG_Object;

#if WIRE3D_DMG_HEIGHT != 120
// Take over the LCD: wait for VBlank, switch it off, clear 6144 tile bytes and
// the BG map, install HUD tiles and the 128x96 signed-tile viewport, then enable
// BG display with scroll zero and BGP=0xB4. Reset camera, BG queue and stage.
// Reserve 0xD000..0xDFFF for staging and retain its WRAM bank mapping.
// Call BeginFrame before drawing to initialize the occlusion state as well.
#else
// Take over LCD state, clear tile VRAM and the BG map, and install a 16x15
// viewport beginning at map tile (3,1). Set scroll (8,0), BGP=0xB4 and BG display.
// Reset camera, queues, transfer modes, both dirty tables and stage. Reserve
// 0xD000..0xDFFF and retain its WRAM mapping; auxiliary storage aliases it.
// Call BeginFrame before drawing to establish occlusion state.
#endif
void Wire3DDMG_Init();
#if WIRE3D_DMG_HEIGHT != 120
// Clear staged pixels and occlusion mask and disable occlusion filtering.
// This leaves the displayed VRAM frame and pending BG tile queue unchanged.
#else
// Disable occlusion filtering only. Stage clearing normally happens during
// transfer, and Init supplies the first clean stage. This does not discard an
// unsubmitted frame, clear the mask, or reset pending BG writes/dirty flags.
#endif
void Wire3DDMG_BeginFrame();
/* Validate depth and project coordinates already in camera space. */
w3ddmg_u8 Wire3DDMG_ProjectCameraPoint(w3ddmg_i16 x,w3ddmg_i16 y,w3ddmg_i16 z,w3ddmg_u8* sx,w3ddmg_u8* sy);
// Store camera position and angles for later draws; a full turn is 16 angle
// steps. No existing drawing is reprojected and no input range validation occurs.
#if WIRE3D_DMG_HEIGHT != 120
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 pitch, w3ddmg_i8 yaw, w3ddmg_i8 roll);
#else
void Wire3DDMG_SetCamera(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 pitch, w3ddmg_u8 yaw, w3ddmg_u8 roll);
#endif
// Draw an unscaled model by delegating to DrawModelScaled with scale 256.
#if WIRE3D_DMG_HEIGHT != 120
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);
// Scale, rotate in Y/X/Z order, translate and project at most 24 vertices;
// then draw up to 16 edges filtered by yaw masks and optional front-facing faces.
// Nonpositive scale becomes unity (256). Null model/vertex/edge pointers are
// ignored; referenced tables must remain readable. Keep scale products and
// translations in signed 16-bit range. Depth-crossing edges are dropped, not clipped.
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8);
#else
void Wire3DDMG_DrawModel(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);
// Scale up to 24 vertices, rotate Y/X/Z, translate and project, then traverse
// all edge_count entries (a byte count) with optional adjacent-face filtering.
// Face scratch is capped at 16; edge tables must contain all declared entries.
// Nonpositive scale means 256. Null model/vertex/edge pointers are ignored.
// Keep products/translations in signed 16-bit range; depth-crossing edges are dropped.
void Wire3DDMG_DrawModelScaled(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);
#endif
// Project up to 24 vertices and erase front-facing triangle interiors from
// the stage for a model with hidden-line flags and face data. Nonpositive scale
// means 256 (unity). Up to 16 faces are considered; depth-crossing faces are
// skipped. This also replaces shared projection caches, but does not update VRAM.
#if WIRE3D_DMG_HEIGHT != 120
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz, w3ddmg_i16 scale_q8);
#else
void Wire3DDMG_EraseModelFaces(const Wire3DDMG_Model* model, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz, w3ddmg_i16 scale_q8);
#endif
// Erase a triangle from staged pixels using integer scanline intersections.
// Supply viewport coordinates. Degenerate triangles are ignored; the occlusion
// mask and VRAM are unchanged.
void Wire3DDMG_EraseTriangle2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by, w3ddmg_u8 cx, w3ddmg_u8 cy);
// Order the X endpoints and erase the inclusive staged span. Both endpoints
// must be in 0..127; invalid Y is ignored. The routine does not clip X for you.
void Wire3DDMG_EraseSpan2D(w3ddmg_u8 y, w3ddmg_u8 x0, w3ddmg_u8 x1);
#if WIRE3D_DMG_HEIGHT != 120
// Process at most the first eight objects, sorted near to far by transformed
// origin depth. Draw visible valid models, then mark their front-face bounding
// rectangles to reject fully sampled later lines. This approximates inter-object
// occlusion, not a depth buffer. It clears its mask but retains existing staged
// pixels. Null arrays are ignored; objects and their data must remain readable.
#else
// Sort at most eight object origins by camera depth, near to far. Draw visible
// valid models and mark front-face bounding rectangles for later objects. The
// first sorted slot bypasses mask tests and the last needs no new occluder.
// This is coarse line rejection, not a depth buffer. Null/empty input is ignored;
// caller data and the current projection cache must remain valid during traversal.
#endif
void Wire3DDMG_DrawScene(Wire3DDMG_Object* objects, w3ddmg_u8 count);
#if WIRE3D_DMG_HEIGHT != 120
// Select a precomputed mask from the low four bits of object yaw; pitch,
// roll and camera orientation are ignored. Use 16, 8, 4 or 2 bins; other positive
// counts select entry zero (counts >=16 use the first 16). Missing data returns
// 0xFFFF. Keep the mask table readable through the current data-pointer mapping.
w3ddmg_u16 Wire3DDMG_SelectEdgeMask(const Wire3DDMG_Model* model, w3ddmg_i8 rx, w3ddmg_i8 ry, w3ddmg_i8 rz);
// Project a world point with the current camera. Return zero for rejected
// depth, leaving outputs unchanged; success writes clamped coordinates for the selected height.
// Output pointers must be valid. Screen clamping is not geometric clipping.
#else
// Project a world point with the current camera. Return zero for invalid
// depth without changing outputs; success writes clamped 128x120 coordinates.
// Both output pointers must be valid. Coordinate differences must fit s16.
#endif
w3ddmg_u8 Wire3DDMG_ProjectPoint(w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8* sx, w3ddmg_u8* sy);
#if WIRE3D_DMG_HEIGHT == 120
// Rotate in place in Y/X/Z order using 16 steps per full turn. A null
// component pointer makes the whole call a no-op; use distinct pointers.
// Each axis rotation clamps its inputs to +/-220.
void Wire3DDMG_RotatePoint(w3ddmg_i16* x, w3ddmg_i16* y, w3ddmg_i16* z, w3ddmg_u8 rx, w3ddmg_u8 ry, w3ddmg_u8 rz);
#endif
// Project both world endpoints and draw only when both pass the depth range.
// Do not intersect a crossing segment with near/far planes; projected endpoints
// are independently clamped to the screen edges.
void Wire3DDMG_DrawLine3D(w3ddmg_i16 ax, w3ddmg_i16 ay, w3ddmg_i16 az, w3ddmg_i16 bx, w3ddmg_i16 by, w3ddmg_i16 bz);
#if WIRE3D_DMG_HEIGHT != 120
// Draw a connected line into the 128x96 stage, including endpoints. During
// DrawScene, use the coarse five-sample occlusion rejection; otherwise draw directly.
// Supply viewport coordinates. VRAM is updated only by EndFrame.
#else
// Mark the bounding tile rectangle when dirty transfer is enabled, then draw
// a connected staged line. Scene drawing may reject it using five mask samples.
// Supply 128x120 viewport endpoints; low-level pixel bounds checks do not clip
// the segment geometrically.
#endif
void Wire3DDMG_DrawLine2D(w3ddmg_u8 ax, w3ddmg_u8 ay, w3ddmg_u8 bx, w3ddmg_u8 by);
#if WIRE3D_DMG_HEIGHT == 120
// Draw a wireframe rectangle directly into the staged bitplane. Endpoints are
// inclusive screen pixels in 0..127 x 0..119; both horizontal and vertical
// edges are written with byte masks and only touched tiles are uploaded.
void Wire3DDMG_DrawRect2D(w3ddmg_u8 x0, w3ddmg_u8 y0, w3ddmg_u8 x1, w3ddmg_u8 y1);
#endif
// Draw the canonical 12 edges of an 8-vertex projected box in one call.
// Vertex order is near-face corners 0..3, then far-face corners 4..7.
void Wire3DDMG_DrawBoxEdges2D(const w3ddmg_u8* sx, const w3ddmg_u8* sy);
#if WIRE3D_DMG_HEIGHT == 120
// Draw byte-pair edge indices after integer scaling and translation; scale
// zero means one, and there is no object rotation or face filtering. Project at
// most 24 vertices. Supply at most 128 edge pairs because byte offsets wrap
// after 255. Invalid vertex IDs/depth-rejected endpoints are skipped; null arrays
// are ignored. Keep coordinate products/sums representable as s16.
void Wire3DDMG_DrawIndexedEdges(const Wire3DDMG_Vec3* vertices, w3ddmg_u8 vertex_count, const w3ddmg_u8* edges, w3ddmg_u8 edge_count, w3ddmg_i16 x, w3ddmg_i16 y, w3ddmg_i16 z, w3ddmg_u8 scale);
#endif
// Queue a tile write to the 32x32 map at 0x9800 for EndFrame. Invalid map
// coordinates and submissions beyond 48 pending writes are silently ignored.
// This queue is separate from the general vram library queue.
void Wire3DDMG_PutBgTile(w3ddmg_u8 x, w3ddmg_u8 y, w3ddmg_u8 tile);
// Write the raw DMG BGP palette encoding immediately; no frame synchronization occurs.
void Wire3DDMG_SetPalette(w3ddmg_u8 bgp);
#if WIRE3D_DMG_HEIGHT != 120
// Wait for the next VBlank, flush pending BG map writes, then copy the stage
// to VRAM while polling access windows. Copying consumes the staged pixels.
// The transfer may extend beyond VBlank; this is not an atomic frame swap.
#else
// Store the EndFrame auxiliary-transfer gate; any nonzero value enables it.
// No data is copied or cleared here. Auxiliary source bytes alias the main stage.
void Wire3DDMG_SetAuxTransfer(w3ddmg_u8 flag);
// Store the dirty-transfer gate and clear both dirty histories and the main
// stage, even if the value is unchanged. VRAM is retained; enabling this over an
// old image can leave unmarked old tiles, so arrange a clean displayed baseline.
void Wire3DDMG_SetDirtyTransfer(w3ddmg_u8 flag);
// Upload and consume the full main stage immediately, polling STAT but not
// waiting for the next VBlank. Ignore transfer gates and leave dirty histories
// and BG tile queue unchanged; the caller coordinates the frame lifecycle.
void Wire3DDMG_TransferMainNow();
// Upload and consume auxiliary source strips immediately, independent of the
// auxiliary gate. No VBlank-start wait or dirty-history/BG-queue update occurs.
// The source overlaps the main stage and must be coordinated with its upload.
void Wire3DDMG_TransferAuxNow();
// Wait for the next VBlank and flush BG writes, then optionally consume the
// auxiliary strips before uploading either dirty tiles or the entire main stage.
// Auxiliary/main source overlap makes that ordering significant. STAT polling
// continues across access windows; the update need not fit one VBlank.
#endif
void Wire3DDMG_EndFrame();
// Same queue/gate/history lifecycle, without the initial fresh-VBlank wait.
// Synchronous STAT-safe upload; not an atomic swap. LCD must remain enabled.
void Wire3DDMG_EndFrameNow();

#endif
#if WIRE3D_DMG_HEIGHT == 120

#endif

kitaqgb/lib/wire3d_dmg.h

zx0.h —
c
#pragma once
// Copyright (c) 2026 DAISUKE OBA. MIT License.
// ZX0-compatible forward v2 streams; format designed by Einar Saukas.
#define ZX0_OK 0
#define ZX0_BAD_ARGUMENT 1
#define ZX0_TRUNCATED 2
#define ZX0_BAD_STREAM 3
#define ZX0_OUTPUT_FULL 4
#define ZX0_DISPLAY_ACTIVE 5
// Shared last-call status. These foreground routines are not reentrant.
extern u8 zx0_error;
// Return decoded bytes, or zero on error (possibly after partial writes).
// Source and output must not overlap or cross their current CPU bank windows.
// Capacity and packed_size are byte counts. No prefix/backward/v1 streams.
u16 zx0_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);
// Decode a KQA1 raw/RLE/ZX0 asset produced with --format=auto.
// Empty raw assets return zero with zx0_error==ZX0_OK.
u16 asset_decompress(void* dst, u16 capacity, const void* src, u16 packed_size);
// Decode directly into the selected GB VRAM bank ($8000..$9FFF), with LCD off.
// Preserve LCDC, VBK and interrupt state. Output must fit before $A000.
u16 zx0_decompress_vram(u16 vram_addr, const void* src, u16 packed_size);

kitaqgb/lib/zx0.h