context by c
必要な情報はだいたい掘り終わったので、ここは一旦止めて、こっちで整理していく
Code Doc. にある、context の要素のセットの例
実際のコード
const char *image_context_dir[] = {"edit_image", "edit_mask", NULL};
static int /*eContextResult*/ image_context(const bContext *C,
const char *member,
bContextDataResult *result)
{
SpaceImage *sima = CTX_wm_space_image(C);
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, image_context_dir);
}
else if (CTX_data_equals(member, "edit_image")) {
CTX_data_id_pointer_set(result, (ID *)ED_space_image(sima));
return CTX_RESULT_OK;
}
else if (CTX_data_equals(member, "edit_mask")) {
Mask *mask = ED_space_image_get_mask(sima);
if (mask) {
CTX_data_id_pointer_set(result, &mask->id);
}
return CTX_RESULT_OK;
}
return CTX_RESULT_MEMBER_NOT_FOUND;
}
CTX_data_dir の定義
空文字列の判定らしい 添字の変換ルールで間接参照になる
bool CTX_data_dir(const char *member)
{
return member[0] == '\0';
}
CTX_data_dir_set の定義
void CTX_data_dir_set(bContextDataResult *result, const char **dir)
{
result->dir = dir;
}
CTX_data_equals の定義
STREQ
は文字列比較らしい
bool CTX_data_equals(const char *member, const char *str)
{
return (STREQ(member, str));
}
CTX_data_id_pointer_set の定義
void CTX_data_id_pointer_set(bContextDataResult *result, ID *id)
{
RNA_id_pointer_create(id, &result->ptr);
}
ED_space_image の定義
Image *ED_space_image(SpaceImage *sima)
{
return sima->image;
}
ED_space_image_get_mask の定義
Mask *ED_space_image_get_mask(SpaceImage *sima)
{
return sima->mask_info.mask;
}
RNA_id_pointer_create の定義
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
{
StructRNA *type, *idtype = NULL;
if (id) {
PointerRNA tmp = {NULL};
tmp.data = id;
idtype = rna_ID_refine(&tmp);
while (idtype->refine) {
type = idtype->refine(&tmp);
if (type == idtype) {
break;
}
idtype = type;
}
}
r_ptr->owner_id = id;
r_ptr->type = idtype;
r_ptr->data = id;
}
rna_ID_refine の定義
StructRNA *rna_ID_refine(PointerRNA *ptr)
{
ID *id = (ID *)ptr->data;
return ID_code_to_RNA_type(GS(id->name));
}
ID_code_to_RNA_typeの定義
StructRNA *ID_code_to_RNA_type(short idcode)
{
switch ((ID_Type)idcode) {
case ID_AC:
return &RNA_Action;
...
}
return &RNA_ID;
}
GS() の定義 たぶん
#define GS(a) \
(CHECK_TYPE_ANY(a, char *, const char *, char[66], const char[66]), \
(ID_Type)(*((const short *)(a))))
ID_Type
の定義:GS()がしてるっぽい引数のキャスト先
GS() に関する記述とコメント
ID_Type
のところにあるコメント
and the first 2 bytes of #ID.name (for runtime checks, see #GS macro).
Code Doc. の ID のところ
The name of the datablock (pointer->id.name) encodes the type of the datablock. For example, a mesh that is presented in the Blender user interface with the name "Suzanne" is actually named "MESuzanne" in the datablock. This can be used to cast an ID *id to the correct type. A function GS(name) is available to take such a name and return a constant that indicates the ID data type: if (GS(id->name) == ID_SC) … can be used to test whether the ID datablock is a Scene.
書いてあるとおりで、GD() で謎の処理を行ったあと、name
を ID_type にキャストすることで、(なぜなのかわからないが) "ME" を取り出している、という感じ?
CTX_wm_space_image の定義
struct SpaceImage *CTX_wm_space_image(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
if (area && area->spacetype == SPACE_IMAGE) {
return area->spacedata.first;
}
return NULL;
}
SPACE_IMAGE の定義
/* space types, moved from DNA_screen_types.h */
/* Do NOT change order, append on end. types are hardcoded needed */
typedef enum eSpace_Type {
SPACE_EMPTY = 0,
...
SPACE_IMAGE = 6,
...
} eSpace_Type;
CTX_wm_area の定義
ScrArea *CTX_wm_area(const bContext *C)
{
return ctx_wm_python_context_get(C, "area", &RNA_Area, C->wm.area);
}
RNA_Area の定義
extern StructRNA RNA_Area;
ctx_wm_python_context_get の定義
static void *ctx_wm_python_context_get(const bContext *C,
const char *member,
const StructRNA *member_type,
void *fall_through)
{
#ifdef WITH_PYTHON
if (UNLIKELY(C && CTX_py_dict_get(C))) {
bContextDataResult result;
memset(&result, 0, sizeof(bContextDataResult));
BPY_context_member_get((bContext *)C, member, &result);
if (result.ptr.data) {
if (RNA_struct_is_a(result.ptr.type, member_type)) {
return result.ptr.data;
}
CLOG_WARN(&LOG,
"PyContext '%s' is a '%s', expected a '%s'",
member,
RNA_struct_identifier(result.ptr.type),
RNA_struct_identifier(member_type));
}
}
#else
UNUSED_VARS(C, member, member_type);
#endif
/* don't allow UI context access from non-main threads */
if (!BLI_thread_is_main()) {
return NULL;
}
return fall_through;
}
RNA_struct_is_a の定義
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
{
const StructRNA *base;
if (srna == &RNA_AnyType) {
return true;
}
if (!type) {
return false;
}
/* ptr->type is always maximally refined */
for (base = type; base; base = base->base) {
if (base == srna) {
return true;
}
}
return false;
}
CTX_py_dict_get の定義
void *CTX_py_dict_get(const bContext *C)
{
return C->data.py_context;
}
bContextDataResult の定義
struct bContextDataResult {
PointerRNA ptr;
ListBase list;
const char **dir;
short type; /* 0: normal, 1: seq */
};
memset:初期化
BPY_context_member_get の定義 一部省略
int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result)
{
PyObject *pyctx;
PyObject *item;
PointerRNA *ptr = NULL;
bool done = false;
pyctx = (PyObject *)CTX_py_dict_get(C);
item = PyDict_GetItemString(pyctx, member);
if (item == NULL) {
/* pass */
}
else if (item == Py_None) {
done = true;
}
else if (BPy_StructRNA_Check(item)) {
ptr = &(((BPy_StructRNA *)item)->ptr);
CTX_data_pointer_set(result, ptr->owner_id, ptr->type, ptr->data);
CTX_data_type_set(result, CTX_DATA_TYPE_POINTER);
done = true;
}
else if (PySequence_Check(item)) {
PyObject *seq_fast = PySequence_Fast(item, "bpy_context_get sequence conversion");
if (seq_fast == NULL) {
PyErr_Print();
PyErr_Clear();
}
else {
const int len = PySequence_Fast_GET_SIZE(seq_fast);
PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
int i;
for (i = 0; i < len; i++) {
PyObject *list_item = seq_fast_items[i];
if (BPy_StructRNA_Check(list_item)) {
ptr = &(((BPy_StructRNA *)list_item)->ptr);
CTX_data_list_add(result, ptr->owner_id, ptr->type, ptr->data);
}
else {
CLOG_INFO(BPY_LOG_CONTEXT,
1,
"'%s' list item not a valid type in sequence type '%s'",
member,
Py_TYPE(item)->tp_name);
}
}
Py_DECREF(seq_fast);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
done = true;
}
}
-
PyObject
:Python の type -
PyDict_GetItemString
:Python の関数、辞書内で キーconst char
に対応する value を返す -
PySequence_Check
:Python の関数、こことかによると、__getitem__
と__len__
を持ちx[i]
が可能な dict ではないオブジェクトならTrue
となるらしい -
PyObject_TypeCheck
:Python の関数、v
が第2引数の type/subtype ならTrue
を返す pyrna_struct_Type
の定義-
BPy_StructRNA_Check
の定義
#define BPy_StructRNA_Check(v) (PyObject_TypeCheck(v, &pyrna_struct_Type))
CTX_data_pointer_set の定義
void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data)
{
RNA_pointer_create(id, type, data, &result->ptr);
}
RNA_pointer_createの定義 コメント省略
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
{
r_ptr->owner_id = id;
r_ptr->type = type;
r_ptr->data = data;
if (data) {
while (r_ptr->type && r_ptr->type->refine) {
StructRNA *rtype = r_ptr->type->refine(r_ptr);
if (rtype == r_ptr->type) {
break;
}
r_ptr->type = rtype;
}
}
}
refine の定義 (抜粋)
struct StructRNA *nested;
/* function to give the more specific type */
StructRefineFunc refine;
StructRefineFunc の定義
typedef struct StructRNA *(*StructRefineFunc)(struct PointerRNA *ptr);
ポインタ値 ptr
を引数にとって構造体StructRNA
へのポインタへのポインタを返すもの?
PointerRNA -> type -> refine
に何が入っているのか、が重要っぽい
PointerRNA の定義
typedef struct PointerRNA {
struct ID *owner_id;
struct StructRNA *type;
void *data;
} PointerRNA;
CTX_data_type_set の定義
void CTX_data_type_set(bContextDataResult *result, short type)
{
result->type = type;
}
PySequence_Fast
:Python の関数、他のPySequence_Fast
系の関数で利用できるような sequence or iterable な item へのポインタ値を返す (文字列はエラーメッセージ)
CTX_data_list_add の定義
void CTX_data_list_add(bContextDataResult *result, ID *id, StructRNA *type, void *data)
{
CollectionPointerLink *link = MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_list_add");
RNA_pointer_create(id, type, data, &link->ptr);
BLI_addtail(&result->list, link);
}
BLI_addtail の定義
/**
* Appends \a vlink (assumed to begin with a Link) onto listbase.
*/
void BLI_addtail(ListBase *listbase, void *vlink)
{
Link *link = vlink;
if (link == NULL) {
return;
}
link->next = NULL;
link->prev = listbase->last;
if (listbase->last) {
((Link *)listbase->last)->next = link;
}
if (listbase->first == NULL) {
listbase->first = link;
}
listbase->last = link;
}
MEM_callocN の定義 たぶん
define MEM_callocN(size, str) ((void)str, calloc(size, 1))
CTX_RESULT_xxx の定義
/typedef enum eContextResult {
/* The context member was found, and its data is available. */
CTX_RESULT_OK = 1,
/* The context member was not found. */
CTX_RESULT_MEMBER_NOT_FOUND = 0,
/* The context member was found, but its data is not available.
* For example, "active_bone" is a valid context member, but has not data in Object mode. */
CTX_RESULT_NO_DATA = -1,
} eContextResult;
ListBase の定義
typedef struct ListBase {
void *first, *last;
} ListBase;
bContext の定義
struct bContext {
int thread;
/* windowmanager context */
struct {
struct wmWindowManager *manager;
struct wmWindow *window;
struct WorkSpace *workspace;
struct bScreen *screen;
struct ScrArea *area;
struct ARegion *region;
struct ARegion *menu;
struct wmGizmoGroup *gizmo_group;
struct bContextStore *store;
const char *operator_poll_msg; /* reason for poll failing */
} wm;
/* data context */
struct {
struct Main *main;
struct Scene *scene;
int recursion;
/** True if python is initialized. */
bool py_init;
void *py_context;
/**
* If we need to remove members, do so in a copy
* (keep this to check if the copy needs freeing).
*/
void *py_context_orig;
} data;
};
C (C++?) 関連
C とポインタ
-
s型 x
変数の定義:メモリ上に、s型の変数x
用の領域を確保 -
&
アドレス演算子:変数の左に付加すると、変数のポインタ値(アドレス値)を取得 -
*
間接参照演算子:ポインタ値の左に付加すると、ポインタ値が指す領域にある実体を取得 -
s型 *x
ポインタ型変数の定義:メモリ上に「s型へのポインタ値」型の変数x
用の領域を確保
→&s型 x
と(たぶん)解釈できる 定義しているのは*x
ではなくあくまでもx
参考
コンパイラによる変換のルールと、ポインタと配列の性質-
ary → &(ary[0])
:配列変数が式に現れると、先頭要素のポインタ値に変換 -
p[n] → *(p+n)
:ポインタに index がつくと、ポインタに対する加算命令+間接参照に変換
配列[index]
ではこの2つの変換が連続して行われ、以下の流れで配列の要素にアクセスできる
配列変数 →(変換+&
)→ 先頭ポインタ →(変換+加算)→ index 部のポインタ →(*
)→ 実体
-
const
は再代入不可 -
struct
は構造体の型宣言 not 定義 - 列挙型の中身はそのまま呼び出せる 「列挙型」を定義というより、定義を列挙している
- 文字列を扱うには、char 型の配列を利用する他に、char 型のポインターを利用することもできる
- 汎用ポインタ
void *
:ポインタ型であればどのような型でも代入できる
ほぼ倉庫なので閉じ
こんなのを見つけた
ただ、実際には C++ を通して python スクリプトを Blender に投げているという感じなので、Blender の C++ 部分をあれこれしているわけでなさそう
Blender の C に関する日本語情報は、2012~2014あたりには出されていたものの、2015以降は話題に上がらなくなった感じがある