blender/intern/ghost/test/multitest/MultiTest.c
Thomas Dinges 697b447c20 Metal: MTLContext implementation and immediate mode rendering support.
MTLContext provides functionality for command encoding, binding management and graphics device management. MTLImmediate provides simple draw enablement with dynamically encoded data. These draws utilise temporary scratch buffer memory to provide minimal bandwidth overhead during workload submission.

This patch also contains empty placeholders for MTLBatch and MTLDrawList to enable testing of first pixels on-screen without failure.

The Metal API also requires access to the GHOST_Context to ensure the same pre-initialized Metal GPU device is used by the viewport. Given the explicit nature of Metal, explicit control is also needed over presentation, to ensure correct work scheduling and rendering pipeline state.

Authored by Apple: Michael Parkin-White

Ref T96261

(The diff is based on 043f59cb3b5835ba1a0bbf6f1cbad080b527f7f6)

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D15953
2022-09-22 17:32:43 +02:00

949 lines
22 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/* Developers Note:
*
* This test currently only creates windows and draws a 'dot' under the cursor on LMB,
* quits when Q is pressed.
*
* More work is needed for logging drawing to work properly.
*
* - Use GPU_matrix API.
* - Replace old OpenGL calls to glColor, etc with 'imm' API.
* - Investigate BLF font flushing (UI_widgetbase_draw_cache_flush) which is currently disabled.
*/
#ifdef _MSC_VER
# pragma warning(disable : 4244 4305)
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "GL.h"
#include <GL/glew.h>
#include "MEM_guardedalloc.h"
#include "GHOST_C-api.h"
#include "BLF_api.h"
#include "Basic.h"
#include "EventToBuf.h"
#include "ScrollBar.h"
#include "Util.h"
#include "WindowData.h"
/* GPU API. */
#include "GPU_context.h"
#include "GPU_immediate.h"
#include "GPU_init_exit.h"
extern int datatoc_bfont_ttf_size;
extern char const datatoc_bfont_ttf[];
typedef struct _LoggerWindow LoggerWindow;
typedef struct _MultiTestApp MultiTestApp;
void loggerwindow_log(LoggerWindow *lw, char *line);
void multitestapp_toggle_extra_window(MultiTestApp *app);
void multitestapp_free_extrawindow(MultiTestApp *app);
LoggerWindow *multitestapp_get_logger(MultiTestApp *app);
GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app);
void multitestapp_exit(MultiTestApp *app);
/**/
void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, const float col[3], int width)
{
int ltidx = (side / 2) % 4;
int dkidx = (ltidx + 1 + (side & 1)) % 4;
int i, corner;
glBegin(GL_LINES);
for (i = 0; i < width; i++) {
float ltf = pow(lt[i], 1.0 / 2.2), dkf = pow(dk[i], 1.0 / 2.2);
float stf = (dkidx > ltidx) ? dkf : ltf;
int lx = rect[1][0] - i - 1;
int ly = rect[0][1] + i;
glColor3f(col[0] * stf, col[1] * stf, col[2] * stf);
for (corner = 0; corner < 4; corner++) {
int x = (corner == 0 || corner == 1) ? (rect[0][0] + i) : (rect[1][0] - i - 1);
int y = (corner == 0 || corner == 3) ? (rect[0][1] + i) : (rect[1][1] - i - 1);
if (ltidx == corner)
glColor3f(col[0] * ltf, col[1] * ltf, col[2] * ltf);
if (dkidx == corner)
glColor3f(col[0] * dkf, col[1] * dkf, col[2] * dkf);
glVertex2i(lx, ly);
glVertex2i(lx = x, ly = y);
}
}
glEnd();
glColor3fv(col);
glRecti(rect[0][0] + width, rect[0][1] + width, rect[1][0] - width, rect[1][1] - width);
}
void rect_bevel_smooth(int rect[2][2], int width)
{
float *lt = malloc(sizeof(*lt) * width);
float *dk = malloc(sizeof(*dk) * width);
float col[4];
int i;
for (i = 0; i < width; i++) {
float v = width - 1 ? ((float)i / (width - 1)) : 0;
lt[i] = 1.2 + (1.0 - 1.2) * v;
dk[i] = 0.2 + (1.0 - 0.2) * v;
}
glGetFloatv(GL_CURRENT_COLOR, col);
rect_bevel_side(rect, 3, lt, dk, col, width);
free(lt);
free(dk);
}
/*
* MainWindow
*/
typedef struct {
MultiTestApp *app;
GHOST_WindowHandle win;
GPUContext *gpu_context;
int size[2];
int lmouse[2], lmbut[3];
int tmouse[2];
} MainWindow;
static void mainwindow_log(MainWindow *mw, char *str)
{
loggerwindow_log(multitestapp_get_logger(mw->app), str);
}
static void mainwindow_do_draw(MainWindow *mw)
{
GHOST_ActivateWindowDrawingContext(mw->win);
GPU_context_active_set(mw->gpu_context);
if (mw->lmbut[0]) {
glClearColor(0.5, 0.5, 0.5, 1);
}
else {
glClearColor(1, 1, 1, 1);
}
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.5, 0.6, 0.8);
glRecti(mw->tmouse[0] - 5, mw->tmouse[1] - 5, mw->tmouse[0] + 5, mw->tmouse[1] + 5);
GHOST_SwapWindowBuffers(mw->win);
}
static void mainwindow_do_reshape(MainWindow *mw)
{
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(mw->win);
GHOST_ActivateWindowDrawingContext(mw->win);
GPU_context_active_set(mw->gpu_context);
mw->size[0] = GHOST_GetWidthRectangle(bounds);
mw->size[1] = GHOST_GetHeightRectangle(bounds);
glViewport(0, 0, mw->size[0], mw->size[1]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, mw->size[0], 0, mw->size[1], -1, 1);
glTranslatef(0.375, 0.375, 0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
static void mainwindow_do_key(MainWindow *mw, GHOST_TKey key, int press)
{
switch (key) {
case GHOST_kKeyC:
if (press) {
GHOST_SetCursorShape(mw->win,
(GHOST_TStandardCursor)(rand() % (GHOST_kStandardCursorNumCursors)));
}
break;
case GHOST_kKeyLeftBracket:
if (press) {
GHOST_SetCursorVisibility(mw->win, 0);
}
break;
case GHOST_kKeyRightBracket:
if (press) {
GHOST_SetCursorVisibility(mw->win, 1);
}
break;
case GHOST_kKeyE:
if (press) {
multitestapp_toggle_extra_window(mw->app);
}
break;
case GHOST_kKeyQ:
if (press) {
multitestapp_exit(mw->app);
}
break;
case GHOST_kKeyT:
if (press) {
mainwindow_log(mw, "TextTest~|`hello`\"world\",<>/");
}
break;
case GHOST_kKeyR:
if (press) {
int i;
mainwindow_log(mw, "Invalidating window 10 times");
for (i = 0; i < 10; i++) {
GHOST_InvalidateWindow(mw->win);
}
}
break;
case GHOST_kKeyF11:
if (press) {
GHOST_SetWindowOrder(mw->win, GHOST_kWindowOrderBottom);
}
break;
}
}
static void mainwindow_do_move(MainWindow *mw, int x, int y)
{
mw->lmouse[0] = x, mw->lmouse[1] = y;
if (mw->lmbut[0]) {
mw->tmouse[0] = x, mw->tmouse[1] = y;
GHOST_InvalidateWindow(mw->win);
}
}
static void mainwindow_do_button(MainWindow *mw, int which, int press)
{
if (which == GHOST_kButtonMaskLeft) {
mw->lmbut[0] = press;
mw->tmouse[0] = mw->lmouse[0], mw->tmouse[1] = mw->lmouse[1];
GHOST_InvalidateWindow(mw->win);
}
else if (which == GHOST_kButtonMaskLeft) {
mw->lmbut[1] = press;
}
else if (which == GHOST_kButtonMaskLeft) {
mw->lmbut[2] = press;
}
}
static void mainwindow_handle(void *priv, GHOST_EventHandle evt)
{
MainWindow *mw = priv;
GHOST_TEventType type = GHOST_GetEventType(evt);
char buf[256];
event_to_buf(evt, buf);
mainwindow_log(mw, buf);
switch (type) {
case GHOST_kEventCursorMove: {
GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
int x, y;
GHOST_ScreenToClient(mw->win, cd->x, cd->y, &x, &y);
mainwindow_do_move(mw, x, mw->size[1] - y - 1);
break;
}
case GHOST_kEventButtonDown:
case GHOST_kEventButtonUp: {
GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
mainwindow_do_button(mw, bd->button, (type == GHOST_kEventButtonDown));
break;
}
case GHOST_kEventKeyDown:
case GHOST_kEventKeyUp: {
GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
mainwindow_do_key(mw, kd->key, (type == GHOST_kEventKeyDown));
break;
}
case GHOST_kEventWindowUpdate:
mainwindow_do_draw(mw);
break;
case GHOST_kEventWindowSize:
mainwindow_do_reshape(mw);
break;
}
}
/**/
static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, uint64_t time)
{
MainWindow *mw = GHOST_GetTimerTaskUserData(task);
char buf[64];
sprintf(buf, "timer: %6.2f", (double)((int64_t)time) / 1000);
mainwindow_log(mw, buf);
}
MainWindow *mainwindow_new(MultiTestApp *app)
{
GHOST_SystemHandle sys = multitestapp_get_system(app);
GHOST_WindowHandle win;
GHOST_GLSettings glSettings = {0};
win = GHOST_CreateWindow(sys,
NULL,
"MultiTest:Main",
40,
40,
400,
400,
GHOST_kWindowStateNormal,
false,
GHOST_kDrawingContextTypeOpenGL,
glSettings);
if (win) {
MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
mw->gpu_context = GPU_context_create(win, NULL);
GPU_init();
mw->app = app;
mw->win = win;
GHOST_SetWindowUserData(mw->win, windowdata_new(mw, mainwindow_handle));
GHOST_InstallTimer(sys, 1000, 10000, mainwindow_timer_proc, mw);
return mw;
}
return NULL;
}
void mainwindow_free(MainWindow *mw)
{
GHOST_SystemHandle sys = multitestapp_get_system(mw->app);
windowdata_free(GHOST_GetWindowUserData(mw->win));
GHOST_DisposeWindow(sys, mw->win);
MEM_freeN(mw);
}
/*
* LoggerWindow
*/
struct _LoggerWindow {
MultiTestApp *app;
GHOST_WindowHandle win;
GPUContext *gpu_context;
int font;
int fontheight;
int size[2];
int ndisplines;
int textarea[2][2];
ScrollBar *scroll;
char **loglines;
int nloglines, logsize;
int lmbut[3];
int lmouse[2];
};
#define SCROLLBAR_PAD 2
#define SCROLLBAR_WIDTH 14
#define TEXTAREA_PAD 2
static void loggerwindow_recalc_regions(LoggerWindow *lw)
{
int nscroll[2][2];
nscroll[0][0] = SCROLLBAR_PAD;
nscroll[0][1] = SCROLLBAR_PAD;
nscroll[1][0] = nscroll[0][0] + SCROLLBAR_WIDTH;
nscroll[1][1] = lw->size[1] - SCROLLBAR_PAD - 1;
lw->textarea[0][0] = nscroll[1][0] + TEXTAREA_PAD;
lw->textarea[0][1] = TEXTAREA_PAD;
lw->textarea[1][0] = lw->size[0] - TEXTAREA_PAD - 1;
lw->textarea[1][1] = lw->size[1] - TEXTAREA_PAD - 1;
lw->ndisplines = (lw->textarea[1][1] - lw->textarea[0][1]) / lw->fontheight;
scrollbar_set_thumbpct(lw->scroll, (float)lw->ndisplines / lw->nloglines);
scrollbar_set_rect(lw->scroll, nscroll);
}
static void loggerwindow_setup_window_gl(LoggerWindow *lw)
{
glViewport(0, 0, lw->size[0], lw->size[1]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, lw->size[0], 0, lw->size[1], -1, 1);
glTranslatef(0.375, 0.375, 0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
static void loggerwindow_do_reshape(LoggerWindow *lw)
{
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(lw->win);
GHOST_ActivateWindowDrawingContext(lw->win);
GPU_context_active_set(lw->gpu_context);
lw->size[0] = GHOST_GetWidthRectangle(bounds);
lw->size[1] = GHOST_GetHeightRectangle(bounds);
loggerwindow_recalc_regions(lw);
loggerwindow_setup_window_gl(lw);
}
static void loggerwindow_do_draw(LoggerWindow *lw)
{
int i, ndisplines, startline;
int sb_rect[2][2], sb_thumb[2][2];
GHOST_ActivateWindowDrawingContext(lw->win);
GPU_context_active_set(lw->gpu_context);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.8, 0.8, 0.8);
rect_bevel_smooth(lw->textarea, 4);
scrollbar_get_rect(lw->scroll, sb_rect);
scrollbar_get_thumb(lw->scroll, sb_thumb);
glColor3f(0.6, 0.6, 0.6);
rect_bevel_smooth(sb_rect, 1);
if (scrollbar_is_scrolling(lw->scroll)) {
glColor3f(0.6, 0.7, 0.5);
}
else {
glColor3f(0.9, 0.9, 0.92);
}
rect_bevel_smooth(sb_thumb, 1);
startline = scrollbar_get_thumbpos(lw->scroll) * (lw->nloglines - 1);
ndisplines = min_i(lw->ndisplines, lw->nloglines - startline);
glColor3f(0, 0, 0);
for (i = 0; i < ndisplines; i++) {
/* stored in reverse order */
char *line = lw->loglines[(lw->nloglines - 1) - (i + startline)];
int x_pos = lw->textarea[0][0] + 4;
int y_pos = lw->textarea[0][1] + 4 + i * lw->fontheight;
BLF_position(lw->font, x_pos, y_pos, 0.0);
BLF_draw(lw->font, line, 256); // XXX
}
GHOST_SwapWindowBuffers(lw->win);
immDeactivate();
}
static void loggerwindow_do_move(LoggerWindow *lw, int x, int y)
{
lw->lmouse[0] = x, lw->lmouse[1] = y;
if (scrollbar_is_scrolling(lw->scroll)) {
scrollbar_keep_scrolling(lw->scroll, y);
GHOST_InvalidateWindow(lw->win);
}
}
static void loggerwindow_do_button(LoggerWindow *lw, int which, int press)
{
if (which == GHOST_kButtonMaskLeft) {
lw->lmbut[0] = press;
if (press) {
if (scrollbar_contains_pt(lw->scroll, lw->lmouse)) {
scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]);
GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorUpDown);
GHOST_InvalidateWindow(lw->win);
}
}
else {
if (scrollbar_is_scrolling(lw->scroll)) {
scrollbar_stop_scrolling(lw->scroll);
GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorDefault);
GHOST_InvalidateWindow(lw->win);
}
}
}
else if (which == GHOST_kButtonMaskMiddle) {
lw->lmbut[1] = press;
}
else if (which == GHOST_kButtonMaskRight) {
lw->lmbut[2] = press;
}
}
static void loggerwindow_do_key(LoggerWindow *lw, GHOST_TKey key, int press)
{
switch (key) {
case GHOST_kKeyQ:
if (press)
multitestapp_exit(lw->app);
break;
}
}
static void loggerwindow_handle(void *priv, GHOST_EventHandle evt)
{
LoggerWindow *lw = priv;
GHOST_TEventType type = GHOST_GetEventType(evt);
switch (type) {
case GHOST_kEventCursorMove: {
GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
int x, y;
GHOST_ScreenToClient(lw->win, cd->x, cd->y, &x, &y);
loggerwindow_do_move(lw, x, lw->size[1] - y - 1);
break;
}
case GHOST_kEventButtonDown:
case GHOST_kEventButtonUp: {
GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
loggerwindow_do_button(lw, bd->button, (type == GHOST_kEventButtonDown));
break;
}
case GHOST_kEventKeyDown:
case GHOST_kEventKeyUp: {
GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
loggerwindow_do_key(lw, kd->key, (type == GHOST_kEventKeyDown));
break;
}
case GHOST_kEventWindowUpdate:
loggerwindow_do_draw(lw);
break;
case GHOST_kEventWindowSize:
loggerwindow_do_reshape(lw);
break;
}
}
/**/
LoggerWindow *loggerwindow_new(MultiTestApp *app)
{
GHOST_GLSettings glSettings = {0};
GHOST_SystemHandle sys = multitestapp_get_system(app);
uint32_t screensize[2];
GHOST_WindowHandle win;
GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]);
win = GHOST_CreateWindow(sys,
NULL,
"MultiTest:Logger",
40,
screensize[1] - 432,
800,
300,
GHOST_kWindowStateNormal,
false,
GHOST_kDrawingContextTypeOpenGL,
glSettings);
if (win) {
LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
lw->gpu_context = GPU_context_create(win, NULL);
GPU_init();
int bbox[2][2];
lw->app = app;
lw->win = win;
lw->font = BLF_load_default(false);
BLF_size(lw->font, 11, 72);
lw->fontheight = BLF_height(lw->font, "A_", 2);
lw->nloglines = lw->logsize = 0;
lw->loglines = MEM_mallocN(sizeof(*lw->loglines) * lw->nloglines, "loglines");
lw->scroll = scrollbar_new(2, 40);
GHOST_SetWindowUserData(lw->win, windowdata_new(lw, loggerwindow_handle));
loggerwindow_do_reshape(lw);
return lw;
}
else {
return NULL;
}
}
void loggerwindow_log(LoggerWindow *lw, char *line)
{
if (lw->nloglines == lw->logsize) {
lw->loglines = memdbl(lw->loglines, &lw->logsize, sizeof(*lw->loglines));
}
lw->loglines[lw->nloglines++] = string_dup(line);
scrollbar_set_thumbpct(lw->scroll, (float)lw->ndisplines / lw->nloglines);
GHOST_InvalidateWindow(lw->win);
}
void loggerwindow_free(LoggerWindow *lw)
{
GHOST_SystemHandle sys = multitestapp_get_system(lw->app);
int i;
for (i = 0; i < lw->nloglines; i++) {
MEM_freeN(lw->loglines[i]);
}
MEM_freeN(lw->loglines);
windowdata_free(GHOST_GetWindowUserData(lw->win));
GHOST_DisposeWindow(sys, lw->win);
MEM_freeN(lw);
}
/*
* ExtraWindow
*/
typedef struct {
MultiTestApp *app;
GHOST_WindowHandle win;
GPUContext *gpu_context;
int size[2];
} ExtraWindow;
static void extrawindow_do_draw(ExtraWindow *ew)
{
GHOST_ActivateWindowDrawingContext(ew->win);
GPU_context_active_set(ew->gpu_context);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.8, 0.8, 0.8);
glRecti(10, 10, ew->size[0] - 10, ew->size[1] - 10);
GHOST_SwapWindowBuffers(ew->win);
}
static void extrawindow_do_reshape(ExtraWindow *ew)
{
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(ew->win);
GHOST_ActivateWindowDrawingContext(ew->win);
GPU_context_active_set(ew->gpu_context);
ew->size[0] = GHOST_GetWidthRectangle(bounds);
ew->size[1] = GHOST_GetHeightRectangle(bounds);
glViewport(0, 0, ew->size[0], ew->size[1]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, ew->size[0], 0, ew->size[1], -1, 1);
glTranslatef(0.375, 0.375, 0.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
static void extrawindow_do_key(ExtraWindow *ew, GHOST_TKey key, int press)
{
switch (key) {
case GHOST_kKeyE:
if (press)
multitestapp_toggle_extra_window(ew->app);
break;
}
}
static void extrawindow_spin_cursor(ExtraWindow *ew, uint64_t time)
{
uint8_t bitmap[16][2];
uint8_t mask[16][2];
double ftime = (double)((int64_t)time) / 1000;
float angle = fmod(ftime, 1.0) * 3.1415 * 2;
int i;
memset(&bitmap, 0, sizeof(bitmap));
memset(&mask, 0, sizeof(mask));
bitmap[0][0] |= mask[0][0] |= 0xF;
bitmap[1][0] |= mask[1][0] |= 0xF;
bitmap[2][0] |= mask[2][0] |= 0xF;
bitmap[3][0] |= mask[3][0] |= 0xF;
for (i = 0; i < 7; i++) {
int x = 7 + cos(angle) * i;
int y = 7 + sin(angle) * i;
mask[y][x / 8] |= (1 << (x % 8));
}
for (i = 0; i < 64; i++) {
float v = (i / 63.0) * 3.1415 * 2;
int x = 7 + cos(v) * 7;
int y = 7 + sin(v) * 7;
mask[y][x / 8] |= (1 << (x % 8));
}
GHOST_SetCustomCursorShape(ew->win, &bitmap[0][0], &mask[0][0], 16, 16, 0, 0, true);
}
static void extrawindow_handle(void *priv, GHOST_EventHandle evt)
{
ExtraWindow *ew = priv;
GHOST_TEventType type = GHOST_GetEventType(evt);
char buf[256];
event_to_buf(evt, buf);
loggerwindow_log(multitestapp_get_logger(ew->app), buf);
switch (type) {
case GHOST_kEventKeyDown:
case GHOST_kEventKeyUp: {
GHOST_TEventKeyData *kd = GHOST_GetEventData(evt);
extrawindow_do_key(ew, kd->key, (type == GHOST_kEventKeyDown));
break;
}
case GHOST_kEventCursorMove: {
extrawindow_spin_cursor(ew, GHOST_GetEventTime(evt));
break;
}
case GHOST_kEventWindowClose:
multitestapp_free_extrawindow(ew->app);
break;
case GHOST_kEventWindowUpdate:
extrawindow_do_draw(ew);
break;
case GHOST_kEventWindowSize:
extrawindow_do_reshape(ew);
break;
}
}
/**/
ExtraWindow *extrawindow_new(MultiTestApp *app)
{
GHOST_GLSettings glSettings = {0};
GHOST_SystemHandle sys = multitestapp_get_system(app);
GHOST_WindowHandle win;
win = GHOST_CreateWindow(sys,
NULL,
"MultiTest:Extra",
500,
40,
400,
400,
GHOST_kWindowStateNormal,
false,
GHOST_kDrawingContextTypeOpenGL,
glSettings);
if (win) {
ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
ew->gpu_context = GPU_context_create(win, NULL);
GPU_init();
ew->app = app;
ew->win = win;
GHOST_SetWindowUserData(ew->win, windowdata_new(ew, extrawindow_handle));
return ew;
}
else {
return NULL;
}
}
void extrawindow_free(ExtraWindow *ew)
{
GHOST_SystemHandle sys = multitestapp_get_system(ew->app);
windowdata_free(GHOST_GetWindowUserData(ew->win));
GHOST_DisposeWindow(sys, ew->win);
MEM_freeN(ew);
}
/*
* MultiTestApp
*/
struct _MultiTestApp {
GHOST_SystemHandle sys;
MainWindow *main;
LoggerWindow *logger;
ExtraWindow *extra;
int exit;
};
static bool multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data)
{
MultiTestApp *app = data;
GHOST_WindowHandle win;
win = GHOST_GetEventWindow(evt);
if (win && !GHOST_ValidWindow(app->sys, win)) {
loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n");
return true;
}
if (win) {
WindowData *wb = GHOST_GetWindowUserData(win);
windowdata_handle(wb, evt);
}
else {
GHOST_TEventType type = GHOST_GetEventType(evt);
/* GHOST_kEventQuit are the only 'system' events,
* that is, events without a window.
*/
switch (type) {
case GHOST_kEventQuitRequest:
app->exit = 1;
break;
default:
fatal("Unhandled system event: %d (%s)\n", type, eventtype_to_string(type));
break;
}
}
return true;
}
/**/
MultiTestApp *multitestapp_new(void)
{
MultiTestApp *app = MEM_mallocN(sizeof(*app), "multitestapp_new");
GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(multitest_event_handler, app);
app->sys = GHOST_CreateSystem();
if (!app->sys)
fatal("Unable to create ghost system");
if (!GHOST_AddEventConsumer(app->sys, consumer))
fatal("Unable to add multitest event consumer ");
app->main = mainwindow_new(app);
if (!app->main)
fatal("Unable to create main window");
app->logger = loggerwindow_new(app);
if (!app->logger)
fatal("Unable to create logger window");
app->extra = NULL;
app->exit = 0;
return app;
}
LoggerWindow *multitestapp_get_logger(MultiTestApp *app)
{
return app->logger;
}
GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app)
{
return app->sys;
}
void multitestapp_free_extrawindow(MultiTestApp *app)
{
extrawindow_free(app->extra);
app->extra = NULL;
}
void multitestapp_toggle_extra_window(MultiTestApp *app)
{
if (app->extra) {
multitestapp_free_extrawindow(app);
}
else {
app->extra = extrawindow_new(app);
}
}
void multitestapp_exit(MultiTestApp *app)
{
app->exit = 1;
}
void multitestapp_run(MultiTestApp *app)
{
while (!app->exit) {
GHOST_ProcessEvents(app->sys, true);
GHOST_DispatchEvents(app->sys);
}
}
void multitestapp_free(MultiTestApp *app)
{
BLF_exit();
GPU_exit();
mainwindow_free(app->main);
loggerwindow_free(app->logger);
GHOST_DisposeSystem(app->sys);
MEM_freeN(app);
}
/***/
int main(int argc, char **argv)
{
MultiTestApp *app;
BLF_init();
app = multitestapp_new();
multitestapp_run(app);
multitestapp_free(app);
return 0;
}