Exemplo n.º 1
0
/* return path for restart */
static char *wm_main_playanim_intern(int argc, const char **argv)
{
	struct ImBuf *ibuf = NULL;
	static char filepath[FILE_MAX];	/* abused to return dropped file path */
	GHOST_TUns32 maxwinx, maxwiny;
	int i;
	/* This was done to disambiguate the name for use under c++. */
	struct anim *anim = NULL;
	int start_x = 0, start_y = 0;
	int sfra = -1;
	int efra = -1;
	int totblock;
	
	PlayState ps = {0};

	/* ps.doubleb   = TRUE;*/ /* UNUSED */
	ps.go        = TRUE;
	ps.direction = TRUE;
	ps.next_frame = 1;
	ps.once      = FALSE;
	ps.turbo     = FALSE;
	ps.pingpong  = FALSE;
	ps.noskip    = FALSE;
	ps.sstep     = FALSE;
	ps.wait2     = FALSE;
	ps.stopped   = FALSE;
	ps.picture   = NULL;
	ps.dropped_file[0] = 0;
	ps.zoom      = 1.0f;
	/* resetmap = FALSE */

	ps.fstep     = 1;

	ps.fontid = -1;

	while (argc > 1) {
		if (argv[1][0] == '-') {
			switch (argv[1][1]) {
				case 'm':
					fromdisk = TRUE;
					break;
				case 'p':
					if (argc > 3) {
						start_x = atoi(argv[2]);
						start_y = atoi(argv[3]);
						argc -= 2;
						argv += 2;
					}
					else {
						printf("too few arguments for -p (need 2): skipping\n");
					}
					break;
				case 'f':
					if (argc > 3) {
						double fps = atof(argv[2]);
						double fps_base = atof(argv[3]);
						if (fps == 0.0) {
							fps = 1;
							printf("invalid fps,"
							       "forcing 1\n");
						}
						swaptime = fps_base / fps;
						argc -= 2;
						argv += 2;
					}
					else {
						printf("too few arguments for -f (need 2): skipping\n");
					}
					break;
				case 's':
					sfra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
					argc--;
					argv++;
					break;
				case 'e':
					efra = MIN2(MAXFRAME, MAX2(1, atoi(argv[2]) ));
					argc--;
					argv++;
					break;
				case 'j':
					ps.fstep = MIN2(MAXFRAME, MAX2(1, atoi(argv[2])));
					swaptime *= ps.fstep;
					argc--;
					argv++;
					break;
				default:
					printf("unknown option '%c': skipping\n", argv[1][1]);
					break;
			}
			argc--;
			argv++;
		}
		else {
			break;
		}
	}

	if (argc > 1) {
		BLI_strncpy(filepath, argv[1], sizeof(filepath));
	}
	else {
		BLI_current_working_dir(filepath, sizeof(filepath));
		BLI_add_slash(filepath);
	}

	if (IMB_isanim(filepath)) {
		/* OCIO_TODO: support different input color spaces */
		anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
		if (anim) {
			ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
			IMB_close_anim(anim);
			anim = NULL;
		}
	}
	else if (!IMB_ispic(filepath)) {
		printf("%s: '%s' not an image file\n", __func__, filepath);
		exit(1);
	}

	if (ibuf == NULL) {
		/* OCIO_TODO: support different input color space */
		ibuf = IMB_loadiffname(filepath, IB_rect, NULL);
	}

	if (ibuf == NULL) {
		printf("%s: '%s' couldn't open\n", __func__, filepath);
		exit(1);
	}

#if 0 //XXX25
	#if !defined(WIN32) && !defined(__APPLE__)
	if (fork()) exit(0);
	#endif
#endif //XXX25

	{

		GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);

		g_WS.ghost_system = GHOST_CreateSystem();
		GHOST_AddEventConsumer(g_WS.ghost_system, consumer);

		playanim_window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y);

		/* unified matrix, note it affects offset for drawing */
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
		glMatrixMode(GL_MODELVIEW);
	}

	GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &maxwinx, &maxwiny);

	//GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);

	/* initialize the font */
	BLF_init(11, 72);
	ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
	BLF_size(ps.fontid, 11, 72);

	ps.ibufx = ibuf->x;
	ps.ibufy = ibuf->y;
	
	ps.win_x = ps.ibufx;
	ps.win_y = ps.ibufy;

	if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
	if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));

	
	glClearColor(0.1, 0.1, 0.1, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	GHOST_SwapWindowBuffers(g_WS.ghost_window);

	if (sfra == -1 || efra == -1) {
		/* one of the frames was invalid, just use all images */
		sfra = 1;
		efra = MAXFRAME;
	}

	build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);

	for (i = 2; i < argc; i++) {
		BLI_strncpy(filepath, argv[i], sizeof(filepath));
		build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid);
	}

	IMB_freeImBuf(ibuf);
	ibuf = NULL;

	pupdate_time();
	ptottime = 0;

	/* newly added in 2.6x, without this images never get freed */
#define USE_IMB_CACHE

	while (ps.go) {
		if (ps.pingpong)
			ps.direction = -ps.direction;

		if (ps.direction == 1) {
			ps.picture = picsbase.first;
		}
		else {
			ps.picture = picsbase.last;
		}

		if (ps.picture == NULL) {
			printf("couldn't find pictures\n");
			ps.go = FALSE;
		}
		if (ps.pingpong) {
			if (ps.direction == 1) {
				ps.picture = ps.picture->next;
			}
			else {
				ps.picture = ps.picture->prev;
			}
		}
		if (ptottime > 0.0) ptottime = 0.0;

		while (ps.picture) {
			int hasevent;
#ifndef USE_IMB_CACHE
			if (ibuf != NULL && ibuf->ftype == 0) IMB_freeImBuf(ibuf);
#endif
			if (ps.picture->ibuf) {
				ibuf = ps.picture->ibuf;
			}
			else if (ps.picture->anim) {
				ibuf = IMB_anim_absolute(ps.picture->anim, ps.picture->frame, IMB_TC_NONE, IMB_PROXY_NONE);
			}
			else if (ps.picture->mem) {
				/* use correct colorspace here */
				ibuf = IMB_ibImageFromMemory((unsigned char *) ps.picture->mem, ps.picture->size,
				                             ps.picture->IB_flags, NULL, ps.picture->name);
			}
			else {
				/* use correct colorspace here */
				ibuf = IMB_loadiffname(ps.picture->name, ps.picture->IB_flags, NULL);
			}

			if (ibuf) {

#ifdef USE_IMB_CACHE
				ps.picture->ibuf = ibuf;
#endif

				BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name));

				/* why only windows? (from 2.4x) - campbell */
#ifdef _WIN32
				GHOST_SetTitle(g_WS.ghost_window, ps.picture->name);
#endif

				while (pupdate_time()) PIL_sleep_ms(1);
				ptottime -= swaptime;
				playanim_toscreen(&ps, ps.picture, ibuf, ps.fontid, ps.fstep);
			} /* else delete */
			else {
				printf("error: can't play this image type\n");
				exit(0);
			}

			if (ps.once) {
				if (ps.picture->next == NULL) {
					ps.wait2 = TRUE;
				}
				else if (ps.picture->prev == NULL) {
					ps.wait2 = TRUE;
				}
			}

			ps.next_frame = ps.direction;


			while ( (hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0)) || ps.wait2 != 0) {
				if (hasevent) {
					GHOST_DispatchEvents(g_WS.ghost_system);
				}
				/* Note, this still draws for mousemoves on pause */
				if (ps.wait2) {
					if (hasevent) {
						if (ibuf) {
							while (pupdate_time()) PIL_sleep_ms(1);
							ptottime -= swaptime;
							playanim_toscreen(&ps, ps.picture, ibuf, ps.fontid, ps.fstep);
						}
					}
				}
				if (!ps.go) {
					break;
				}
			}

			ps.wait2 = ps.sstep;

			if (ps.wait2 == 0 && ps.stopped == 0) {
				ps.stopped = TRUE;
			}

			pupdate_time();

			if (ps.picture && ps.next_frame) {
				/* always at least set one step */
				while (ps.picture) {
					ps.picture = playanim_step(ps.picture, ps.next_frame);

					if (ps.once && ps.picture != NULL) {
						if (ps.picture->next == NULL) {
							ps.wait2 = TRUE;
						}
						else if (ps.picture->prev == NULL) {
							ps.wait2 = TRUE;
						}
					}

					if (ps.wait2 || ptottime < swaptime || ps.turbo || ps.noskip) break;
					ptottime -= swaptime;
				}
				if (ps.picture == NULL && ps.sstep) {
					ps.picture = playanim_step(ps.picture, ps.next_frame);
				}
			}
			if (ps.go == FALSE) {
				break;
			}
		}
	}
	ps.picture = picsbase.first;
	anim = NULL;
	while (ps.picture) {
		if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) {
			// to prevent divx crashes
			anim = ps.picture->anim;
			IMB_close_anim(anim);
		}

		if (ps.picture->ibuf) {
			IMB_freeImBuf(ps.picture->ibuf);
		}
		if (ps.picture->mem) {
			MEM_freeN(ps.picture->mem);
		}

		ps.picture = ps.picture->next;
	}

	/* cleanup */
#ifndef USE_IMB_CACHE
	if (ibuf) IMB_freeImBuf(ibuf);
#endif

	BLI_freelistN(&picsbase);
#if 0 // XXX25
	free_blender();
#else
	/* we still miss freeing a lot!,
	 * but many areas could skip initialization too for anim play */
	
	BLF_exit();
#endif
	GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);

	/* early exit, IMB and BKE should be exited only in end */
	if (ps.dropped_file[0]) {
		BLI_strncpy(filepath, ps.dropped_file, sizeof(filepath));
		return filepath;
	}
	
	IMB_exit();
	BKE_images_exit();

	totblock = MEM_get_memory_blocks_in_use();
	if (totblock != 0) {
		/* prints many bAKey, bArgument's which are tricky to fix */
#if 0
		printf("Error Totblock: %d\n", totblock);
		MEM_printmemlist();
#endif
	}
	
	return NULL;
}
Exemplo n.º 2
0
/**
 * \note doesn't run exit() call #WM_exit() for that.
 */
void WM_exit_ext(bContext *C, const bool do_python)
{
	wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;

	/* first wrap up running stuff, we assume only the active WM is running */
	/* modal handlers are on window level freed, others too? */
	/* note; same code copied in wm_files.c */
	if (C && wm) {
		wmWindow *win;

		if (!G.background) {
			struct MemFile *undo_memfile = wm->undo_stack ? ED_undosys_stack_memfile_get_active(wm->undo_stack) : NULL;
			if ((U.uiflag2 & USER_KEEP_SESSION) || (undo_memfile != NULL)) {
				/* save the undo state as quit.blend */
				char filename[FILE_MAX];
				bool has_edited;
				int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);

				BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE);

				has_edited = ED_editors_flush_edits(C, false);

				if ((has_edited && BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL)) ||
				    (undo_memfile && BLO_memfile_write_file(undo_memfile, filename)))
				{
					printf("Saved session recovery to '%s'\n", filename);
				}
			}
		}

		WM_jobs_kill_all(wm);

		for (win = wm->windows.first; win; win = win->next) {

			CTX_wm_window_set(C, win);  /* needed by operator close callbacks */
			WM_event_remove_handlers(C, &win->handlers);
			WM_event_remove_handlers(C, &win->modalhandlers);
			ED_screen_exit(C, win, win->screen);
		}
	}

	BKE_addon_pref_type_free();
	wm_operatortype_free();
	wm_dropbox_free();
	WM_menutype_free();
	WM_uilisttype_free();

	/* all non-screen and non-space stuff editors did, like editmode */
	if (C)
		ED_editors_exit(C);

	ED_undosys_type_free();

//	XXX
//	BIF_GlobalReebFree();
//	BIF_freeRetarget();
	BIF_freeTemplates(C);

	free_openrecent();

	BKE_mball_cubeTable_free();

	/* render code might still access databases */
	RE_FreeAllRender();
	RE_engines_exit();

	ED_preview_free_dbase();  /* frees a Main dbase, before BKE_blender_free! */

	if (C && wm)
		wm_free_reports(C);  /* before BKE_blender_free! - since the ListBases get freed there */

	BKE_sequencer_free_clipboard(); /* sequencer.c */
	BKE_tracking_clipboard_free();
	BKE_mask_clipboard_free();
	BKE_vfont_clipboard_free();

#ifdef WITH_COMPOSITOR
	COM_deinitialize();
#endif

	BKE_blender_free();  /* blender.c, does entire library and spacetypes */
//	free_matcopybuf();
	ANIM_fcurves_copybuf_free();
	ANIM_drivers_copybuf_free();
	ANIM_driver_vars_copybuf_free();
	ANIM_fmodifiers_copybuf_free();
	ED_gpencil_anim_copybuf_free();
	ED_gpencil_strokes_copybuf_free();
	BKE_node_clipboard_clear();

	BLF_exit();

#ifdef WITH_INTERNATIONAL
	BLF_free_unifont();
	BLF_free_unifont_mono();
	BLT_lang_free();
#endif

	ANIM_keyingset_infos_exit();

//	free_txt_data();


#ifdef WITH_PYTHON
	/* option not to close python so we can use 'atexit' */
	if (do_python && ((C == NULL) || CTX_py_init_get(C))) {
		/* XXX - old note */
		/* before BKE_blender_free so py's gc happens while library still exists */
		/* needed at least for a rare sigsegv that can happen in pydrivers */

		/* Update for blender 2.5, move after BKE_blender_free because blender now holds references to PyObject's
		 * so decref'ing them after python ends causes bad problems every time
		 * the pyDriver bug can be fixed if it happens again we can deal with it then */
		BPY_python_end();
	}
#else
	(void)do_python;
#endif

	if (!G.background) {
#ifdef WITH_OPENSUBDIV
		BKE_subsurf_osd_cleanup();
#endif

		GPU_global_buffer_pool_free();
		GPU_free_unused_buffers(G_MAIN);

		GPU_exit();
	}

	ED_file_exit(); /* for fsmenu */

	UI_exit();
	BKE_blender_userdef_data_free(&U, false);

	RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */

	wm_ghost_exit();

	CTX_free(C);
#ifdef WITH_GAMEENGINE
	SYS_DeleteSystem(SYS_GetSystem());
#endif

	GHOST_DisposeSystemPaths();

	DNA_sdna_current_free();

	BLI_threadapi_exit();

	/* No need to call this early, rather do it late so that other pieces of Blender using sound may exit cleanly,
	 * see also T50676. */
	BKE_sound_exit();

	CLG_exit();

	BKE_blender_atexit();

	if (MEM_get_memory_blocks_in_use() != 0) {
		size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use();
		printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n",
		       MEM_get_memory_blocks_in_use(),
		       (double)mem_in_use / 1024 / 1024);
		MEM_printmemlist();
	}
	wm_autosave_delete();

	BKE_tempdir_session_purge();
}
Exemplo n.º 3
0
int main(int argc, char** argv)
{
    int i;
    int argc_py_clamped= argc; /* use this so python args can be added after ' - ' */
    bool error = false;
    SYS_SystemHandle syshandle = SYS_GetSystem();
    bool fullScreen = false;
    bool fullScreenParFound = false;
    bool windowParFound = false;
#ifdef WIN32
    bool closeConsole = true;
#endif
    RAS_IRasterizer::StereoMode stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
    bool stereoWindow = false;
    bool stereoParFound = false;
    int stereoFlag = STEREO_NOSTEREO;
    int domeFov = -1;
    int domeTilt = -200;
    int domeMode = 0;
    char* domeWarp = NULL;
    Text *domeText  = NULL;
    int windowLeft = 100;
    int windowTop = 100;
    int windowWidth = 640;
    int windowHeight = 480;
    GHOST_TUns32 fullScreenWidth = 0;
    GHOST_TUns32 fullScreenHeight= 0;
    int fullScreenBpp = 32;
    int fullScreenFrequency = 60;
    GHOST_TEmbedderWindowID parentWindow = 0;
    bool isBlenderPlayer = false; //true when lauching from blender or command line. false for bundled player
    int validArguments=0;
    bool samplesParFound = false;
    GHOST_TUns16 aasamples = 0;

#ifdef __linux__
#ifdef __alpha__
    signal (SIGFPE, SIG_IGN);
#endif /* __alpha__ */
#endif /* __linux__ */

#ifdef WITH_SDL_DYNLOAD
    sdlewInit();
#endif

    BKE_appdir_program_path_init(argv[0]);
    BKE_tempdir_init(NULL);

    // We don't use threads directly in the BGE, but we need to call this so things like
    // freeing up GPU_Textures works correctly.
    BLI_threadapi_init();

    RNA_init();

    init_nodesystem();

    initglobals();

    U.gameflags |= USER_DISABLE_VBO;
    // We load our own G.main, so free the one that initglobals() gives us
    BKE_main_free(G.main);
    G.main = NULL;

    MEM_CacheLimiter_set_disabled(true);
    IMB_init();
    BKE_images_init();
    BKE_modifier_init();
    DAG_init();

#ifdef WITH_FFMPEG
    IMB_ffmpeg_init();
#endif

    // Setup builtin font for BLF (mostly copied from creator.c, wm_init_exit.c and interface_style.c)
    BLF_init(11, U.dpi);
    BLF_lang_init();
    BLF_lang_set("");

    BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
    if (blf_mono_font == -1)
        blf_mono_font = BLF_load_mem_unique("monospace", (unsigned char*)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);

    // Parse command line options
#if defined(DEBUG)
    printf("argv[0] = '%s'\n", argv[0]);
#endif

#ifdef WIN32
    if (scr_saver_init(argc, argv))
    {
        switch (scr_saver_mode)
        {
        case SCREEN_SAVER_MODE_CONFIGURATION:
            MessageBox(scr_saver_hwnd, "This screen saver has no options that you can set", "Screen Saver", MB_OK);
            break;
        case SCREEN_SAVER_MODE_PASSWORD:
        /* This is W95 only, which we currently do not support.
         * Fall-back to normal screen saver behavior in that case... */
        case SCREEN_SAVER_MODE_SAVER:
            fullScreen = true;
            fullScreenParFound = true;
            break;

        case SCREEN_SAVER_MODE_PREVIEW:
            /* This will actually be handled somewhere below... */
            break;
        }
    }
#endif
    // XXX add the ability to change this values to the command line parsing.
    U.mixbufsize = 2048;
    U.audiodevice = 2;
    U.audiorate = 44100;
    U.audioformat = 0x24;
    U.audiochannels = 2;

    // XXX this one too
    U.anisotropic_filter = 2;
    // enable fast mipmap generation
    U.use_gpu_mipmap = 1;

    sound_init_once();

    set_free_windowmanager_cb(wm_free);

    /* if running blenderplayer the last argument can't be parsed since it has to be the filename. else it is bundled */
    isBlenderPlayer = !BLO_is_a_runtime(argv[0]);
    if (isBlenderPlayer)
        validArguments = argc - 1;
    else
        validArguments = argc;


    /* Parsing command line arguments (can be set from WM_OT_blenderplayer_start) */
#if defined(DEBUG)
    printf("Parsing command line arguments...\n");
    printf("Num of arguments is: %i\n", validArguments-1); //-1 because i starts at 1
#endif

    for (i = 1; (i < validArguments) && !error
#ifdef WIN32
            && scr_saver_mode == SCREEN_SAVER_MODE_NONE
#endif
            ;)

    {
#if defined(DEBUG)
        printf("argv[%d] = '%s'\n", i, argv[i]);
#endif
        if (argv[i][0] == '-')
        {
            /* ignore all args after " - ", allow python to have own args */
            if (argv[i][1]=='\0') {
                argc_py_clamped= i;
                break;
            }

            switch (argv[i][1])
            {
            case 'g': //game engine options (show_framerate, fixedtime, etc)
            {
                i++;
                if (i <= validArguments)
                {
                    char* paramname = argv[i];
                    // Check for single value versus assignment
                    if (i+1 <= validArguments && (*(argv[i+1]) == '='))
                    {
                        i++;
                        if (i + 1 <= validArguments)
                        {
                            i++;
                            // Assignment
                            SYS_WriteCommandLineInt(syshandle, paramname, atoi(argv[i]));
                            SYS_WriteCommandLineFloat(syshandle, paramname, atof(argv[i]));
                            SYS_WriteCommandLineString(syshandle, paramname, argv[i]);
#if defined(DEBUG)
                            printf("%s = '%s'\n", paramname, argv[i]);
#endif
                            i++;
                        }
                        else
                        {
                            error = true;
                            printf("error: argument assignment %s without value.\n", paramname);
                        }
                    }
                    else
                    {
//						SYS_WriteCommandLineInt(syshandle, argv[i++], 1);
                    }
                }
                break;
            }
            case 'd': //debug on
            {
                i++;
                G.debug |= G_DEBUG;
                MEM_set_memory_debug();
#ifdef DEBUG
                BLI_mempool_set_memory_debug();
#endif
                break;
            }
            case 'f': //fullscreen mode
            {
                i++;
                fullScreen = true;
                fullScreenParFound = true;
                if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
                {
                    fullScreenWidth = atoi(argv[i++]);
                    fullScreenHeight = atoi(argv[i++]);
                    if ((i + 1) <= validArguments && argv[i][0] != '-')
                    {
                        fullScreenBpp = atoi(argv[i++]);
                        if ((i + 1) <= validArguments && argv[i][0] != '-')
                            fullScreenFrequency = atoi(argv[i++]);
                    }
                }
                else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
                {
                    error = true;
                    printf("error: to define fullscreen width or height, both options must be used.\n");
                }
                break;
            }
            case 'w': //display in a window
            {
                i++;
                fullScreen = false;
                windowParFound = true;

                // Parse window position and size options
                if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
                {
                    windowWidth = atoi(argv[i++]);
                    windowHeight = atoi(argv[i++]);

                    if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
                    {
                        windowLeft = atoi(argv[i++]);
                        windowTop = atoi(argv[i++]);
                    }
                    else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
                    {
                        error = true;
                        printf("error: to define the window left or right coordinates, both options must be used.\n");
                    }
                }
                else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-')
                {
                    error = true;
                    printf("error: to define the window's width or height, both options must be used.\n");
                }
                break;
            }
            case 'h': //display help
            {
                usage(argv[0], isBlenderPlayer);
                return 0;
                break;
            }
            case 'i': //parent window ID
            {
                i++;
                if ( (i + 1) <= validArguments )
                    parentWindow = atoi(argv[i++]);
                else {
                    error = true;
                    printf("error: too few options for parent window argument.\n");
                }
#if defined(DEBUG)
                printf("XWindows ID = %d\n", parentWindow);
#endif // defined(DEBUG)
                break;
            }
            case 'm': //maximum anti-aliasing (eg. 2,4,8,16)
            {
                i++;
                samplesParFound = true;
                if ((i+1) <= validArguments )
                    aasamples = atoi(argv[i++]);
                else
                {
                    error = true;
                    printf("error: No argument supplied for -m");
                }
                break;
            }
            case 'c': //keep console (windows only)
            {
                i++;
#ifdef WIN32
                closeConsole = false;
#endif
                break;
            }
            case 's': //stereo mode
            {
                i++;
                if ((i + 1) <= validArguments)
                {
                    stereoParFound = true;
                    stereoFlag = STEREO_ENABLED;

                    if (!strcmp(argv[i], "nostereo"))  // may not be redundant if the file has different setting
                    {
                        stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO;
                        stereoFlag = STEREO_NOSTEREO;
                    }

                    // only the hardware pageflip method needs a stereo window
                    else if (!strcmp(argv[i], "hwpageflip")) {
                        stereomode = RAS_IRasterizer::RAS_STEREO_QUADBUFFERED;
                        stereoWindow = true;
                    }
                    else if (!strcmp(argv[i], "syncdoubling"))
                        stereomode = RAS_IRasterizer::RAS_STEREO_ABOVEBELOW;

                    else if (!strcmp(argv[i], "3dtvtopbottom"))
                        stereomode = RAS_IRasterizer::RAS_STEREO_3DTVTOPBOTTOM;

                    else if (!strcmp(argv[i], "anaglyph"))
                        stereomode = RAS_IRasterizer::RAS_STEREO_ANAGLYPH;

                    else if (!strcmp(argv[i], "sidebyside"))
                        stereomode = RAS_IRasterizer::RAS_STEREO_SIDEBYSIDE;

                    else if (!strcmp(argv[i], "interlace"))
                        stereomode = RAS_IRasterizer::RAS_STEREO_INTERLACED;

                    else if (!strcmp(argv[i], "vinterlace"))
                        stereomode = RAS_IRasterizer::RAS_STEREO_VINTERLACE;

#if 0
//					// future stuff
//					else if (!strcmp(argv[i], "stencil")
//						stereomode = RAS_STEREO_STENCIL;
#endif
                    else
                    {
                        error = true;
                        printf("error: stereomode '%s' unrecognized.\n", argv[i]);
                    }

                    i++;
                }
                else
                {
                    error = true;
                    printf("error: too few options for stereo argument.\n");
                }
                break;
            }
            case 'D': //dome mode
            {
                stereoFlag = STEREO_DOME;
                stereomode = RAS_IRasterizer::RAS_STEREO_DOME;
                i++;
                if ((i + 1) <= validArguments)
                {
                    if (!strcmp(argv[i], "angle")) {
                        i++;
                        domeFov = atoi(argv[i++]);
                    }
                    if (!strcmp(argv[i], "tilt")) {
                        i++;
                        domeTilt = atoi(argv[i++]);
                    }
                    if (!strcmp(argv[i], "warpdata")) {
                        i++;
                        domeWarp = argv[i++];
                    }
                    if (!strcmp(argv[i], "mode")) {
                        i++;
                        if (!strcmp(argv[i], "fisheye"))
                            domeMode = DOME_FISHEYE;

                        else if (!strcmp(argv[i], "truncatedfront"))
                            domeMode = DOME_TRUNCATED_FRONT;

                        else if (!strcmp(argv[i], "truncatedrear"))
                            domeMode = DOME_TRUNCATED_REAR;

                        else if (!strcmp(argv[i], "cubemap"))
                            domeMode = DOME_ENVMAP;

                        else if (!strcmp(argv[i], "sphericalpanoramic"))
                            domeMode = DOME_PANORAM_SPH;

                        else
                            printf("error: %s is not a valid dome mode.\n", argv[i]);
                    }
                    i++;
                }
                break;
            }
            default:  //not recognized
            {
                printf("Unknown argument: %s\n", argv[i++]);
                break;
            }
            }
        }
        else
        {
            i++;
        }
    }

    if ((windowWidth < kMinWindowWidth) || (windowHeight < kMinWindowHeight))
    {
        error = true;
        printf("error: window size too small.\n");
    }

    if (error )
    {
        usage(argv[0], isBlenderPlayer);
        return 0;
    }

#ifdef WIN32
    if (scr_saver_mode != SCREEN_SAVER_MODE_CONFIGURATION)
#endif
    {
        // Create the system
        if (GHOST_ISystem::createSystem() == GHOST_kSuccess) {
            GHOST_ISystem* system = GHOST_ISystem::getSystem();
            assertd(system);

            if (!fullScreenWidth || !fullScreenHeight)
                system->getMainDisplayDimensions(fullScreenWidth, fullScreenHeight);
            // process first batch of events. If the user
            // drops a file on top off the blenderplayer icon, we
            // receive an event with the filename

            system->processEvents(0);

            // this bracket is needed for app (see below) to get out
            // of scope before GHOST_ISystem::disposeSystem() is called.
            {
                int exitcode = KX_EXIT_REQUEST_NO_REQUEST;
                STR_String exitstring = "";
                GPG_Application app(system);
                bool firstTimeRunning = true;
                char filename[FILE_MAX];
                char pathname[FILE_MAX];
                char *titlename;

                get_filename(argc_py_clamped, argv, filename);
                if (filename[0])
                    BLI_path_cwd(filename);


                // fill the GlobalSettings with the first scene files
                // those may change during the game and persist after using Game Actuator
                GlobalSettings gs;

                do {
                    // Read the Blender file
                    BlendFileData *bfd;

                    // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
                    if (exitcode == KX_EXIT_REQUEST_START_OTHER_GAME)
                    {
                        char basedpath[FILE_MAX];

                        // base the actuator filename relative to the last file
                        BLI_strncpy(basedpath, exitstring.Ptr(), sizeof(basedpath));
                        BLI_path_abs(basedpath, pathname);

                        bfd = load_game_data(basedpath);

                        if (!bfd) {
                            // just add "//" in front of it
                            char temppath[FILE_MAX] = "//";
                            BLI_strncpy(temppath + 2, basedpath, FILE_MAX - 2);

                            BLI_path_abs(temppath, pathname);
                            bfd = load_game_data(temppath);
                        }
                    }
                    else {
                        bfd = load_game_data(BKE_appdir_program_path(), filename[0]? filename: NULL);
                    }

#if defined(DEBUG)
                    printf("Game data loaded from %s\n", filename);
#endif

                    if (!bfd) {
                        usage(argv[0], isBlenderPlayer);
                        error = true;
                        exitcode = KX_EXIT_REQUEST_QUIT_GAME;
                    }
                    else {
                        /* Setting options according to the blend file if not overriden in the command line */
#ifdef WIN32
#if !defined(DEBUG)
                        if (closeConsole) {
                            system->toggleConsole(0); // Close a console window
                        }
#endif // !defined(DEBUG)
#endif // WIN32
                        Main *maggie = bfd->main;
                        Scene *scene = bfd->curscene;
                        G.main = maggie;

                        if (firstTimeRunning) {
                            G.fileflags  = bfd->fileflags;

                            gs.matmode= scene->gm.matmode;
                            gs.glslflag= scene->gm.flag;
                        }

                        //Seg Fault; icon.c gIcons == 0
                        BKE_icons_init(1);

                        titlename = maggie->name;

                        // Check whether the game should be displayed full-screen
                        if ((!fullScreenParFound) && (!windowParFound)) {
                            // Only use file settings when command line did not override
                            if ((scene->gm.playerflag & GAME_PLAYER_FULLSCREEN)) {
                                //printf("fullscreen option found in Blender file\n");
                                fullScreen = true;
                                fullScreenWidth= scene->gm.xplay;
                                fullScreenHeight= scene->gm.yplay;
                                fullScreenFrequency= scene->gm.freqplay;
                                fullScreenBpp = scene->gm.depth;
                            }
                            else
                            {
                                fullScreen = false;
                                windowWidth = scene->gm.xplay;
                                windowHeight = scene->gm.yplay;
                            }
                        }


                        // Check whether the game should be displayed in stereo (dome included)
                        if (!stereoParFound) {
                            // Only use file settings when command line did not override
                            if (scene->gm.stereoflag == STEREO_ENABLED) {
                                stereomode = (RAS_IRasterizer::StereoMode) scene->gm.stereomode;
                                if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
                                    stereoWindow = true;
                            }
                        }
                        else {
                            scene->gm.stereoflag = STEREO_ENABLED;
                        }

                        if (!samplesParFound)
                            aasamples = scene->gm.aasamples;

                        // Dome specific settings
                        if (stereoFlag == STEREO_DOME) {
                            stereomode = RAS_IRasterizer::RAS_STEREO_DOME;
                            scene->gm.stereoflag = STEREO_DOME;
                            if (domeFov > 89)
                                scene->gm.dome.angle = domeFov;
                            if (domeTilt > -180)
                                scene->gm.dome.tilt = domeTilt;
                            if (domeMode > 0)
                                scene->gm.dome.mode = domeMode;
                            if (domeWarp) {
                                //XXX to do: convert relative to absolute path
                                domeText= BKE_text_load(G.main, domeWarp, "");
                                if (!domeText)
                                    printf("error: invalid warpdata text file - %s\n", domeWarp);
                                else
                                    scene->gm.dome.warptext = domeText;
                            }
                        }

                        //					GPG_Application app (system, maggie, startscenename);
                        app.SetGameEngineData(maggie, scene, &gs, argc, argv); /* this argc cant be argc_py_clamped, since python uses it */
                        BLI_strncpy(pathname, maggie->name, sizeof(pathname));
                        if (G.main != maggie) {
                            BLI_strncpy(G.main->name, maggie->name, sizeof(G.main->name));
                        }
#ifdef WITH_PYTHON
                        setGamePythonPath(G.main->name);
#endif
                        if (firstTimeRunning) {
                            firstTimeRunning = false;

                            if (fullScreen) {
#ifdef WIN32
                                if (scr_saver_mode == SCREEN_SAVER_MODE_SAVER)
                                {
                                    app.startScreenSaverFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
                                                                   stereoWindow, stereomode, aasamples);
                                }
                                else
#endif
                                {
                                    app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
                                                        stereoWindow, stereomode, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION));
                                }
                            }
                            else
                            {
#ifdef __APPLE__
                                // on Mac's we'll show the executable name instead of the 'game.blend' name
                                char tempname[1024], *appstring;
                                ::strcpy(tempname, titlename);

                                appstring = strstr(tempname, ".app/");
                                if (appstring) {
                                    appstring[2] = 0;
                                    titlename = &tempname[0];
                                }
#endif
                                // Strip the path so that we have the name of the game file
                                STR_String path = titlename;
#ifndef WIN32
                                vector<STR_String> parts = path.Explode('/');
#else  // WIN32
                                vector<STR_String> parts = path.Explode('\\');
#endif // WIN32                        
                                STR_String title;
                                if (parts.size()) {
                                    title = parts[parts.size()-1];
                                    parts = title.Explode('.');
                                    if (parts.size() > 1)
                                    {
                                        title = parts[0];
                                    }
                                }
                                else {
                                    title = "blenderplayer";
                                }
#ifdef WIN32
                                if (scr_saver_mode == SCREEN_SAVER_MODE_PREVIEW)
                                {
                                    app.startScreenSaverPreview(scr_saver_hwnd, stereoWindow, stereomode, aasamples);
                                }
                                else
#endif
                                {
                                    if (parentWindow != 0)
                                        app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode, aasamples);
                                    else
                                        app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
                                                        stereoWindow, stereomode, aasamples);

                                    if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) {
                                        GPU_set_mipmap(0);
                                    }

                                    GPU_set_anisotropic(U.anisotropic_filter);
                                    GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
                                }
                            }
                        }
                        else {
                            app.StartGameEngine(stereomode);
                            exitcode = KX_EXIT_REQUEST_NO_REQUEST;
                        }

                        // Add the application as event consumer
                        system->addEventConsumer(&app);

                        // Enter main loop
                        bool run = true;
                        char *python_main = NULL;
                        pynextframestate.state = NULL;
                        pynextframestate.func = NULL;
#ifdef WITH_PYTHON
                        python_main = KX_GetPythonMain(scene);
#endif // WITH_PYTHON
                        if (python_main) {
                            char *python_code = KX_GetPythonCode(maggie, python_main);
                            if (python_code) {
#ifdef WITH_PYTHON
                                gpg_nextframestate.system = system;
                                gpg_nextframestate.app = &app;
                                gpg_nextframestate.gs = &gs;
                                pynextframestate.state = &gpg_nextframestate;
                                pynextframestate.func = &GPG_PyNextFrame;

                                printf("Yielding control to Python script '%s'...\n", python_main);
                                PyRun_SimpleString(python_code);
                                printf("Exit Python script '%s'\n", python_main);
#endif // WITH_PYTHON
                                MEM_freeN(python_code);
                            }
                            else {
                                fprintf(stderr, "ERROR: cannot yield control to Python: no Python text data block named '%s'\n", python_main);
                            }
                        }
                        else {
                            while (run) {
                                run = GPG_NextFrame(system, &app, exitcode, exitstring, &gs);
                            }
                        }
                        app.StopGameEngine();

                        /* 'app' is freed automatic when out of scope.
                         * removal is needed else the system will free an already freed value */
                        system->removeEventConsumer(&app);

                        BLO_blendfiledata_free(bfd);
                        /* G.main == bfd->main, it gets referenced in free_nodesystem so we can't have a dangling pointer */
                        G.main = NULL;
                        if (python_main) MEM_freeN(python_main);
                    }
                } while (exitcode == KX_EXIT_REQUEST_RESTART_GAME || exitcode == KX_EXIT_REQUEST_START_OTHER_GAME);
            }

            // Seg Fault; icon.c gIcons == 0
            BKE_icons_free();

            // Dispose the system
            GHOST_ISystem::disposeSystem();
        }
        else {
            error = true;
            printf("error: couldn't create a system.\n");
        }
    }

    /* refer to WM_exit_ext() and free_blender(),
     * these are not called in the player but we need to match some of there behavior here,
     * if the order of function calls or blenders state isn't matching that of blender proper,
     * we may get troubles later on */

    free_nodesystem();

    // Cleanup
    RNA_exit();
    BLF_exit();

#ifdef WITH_INTERNATIONAL
    BLF_free_unifont();
    BLF_free_unifont_mono();
    BLF_lang_free();
#endif

    IMB_exit();
    BKE_images_exit();
    DAG_exit();
    IMB_moviecache_destruct();

    SYS_DeleteSystem(syshandle);

    int totblock= MEM_get_memory_blocks_in_use();
    if (totblock!=0) {
        printf("Error Totblock: %d\n",totblock);
        MEM_set_error_callback(mem_error_cb);
        MEM_printmemlist();
    }

    BKE_tempdir_session_purge();

    return error ? -1 : 0;
}
Exemplo n.º 4
0
int main(int argc, char *argv[])
{
	int verbose       = 0;
	int error_status  = 0;
	int retval        = 0;
	int *ip;

	void *p[NUM_BLOCKS];
	int i = 0;

	/* ----------------------------------------------------------------- */
	switch (argc) {
	case 2:		
		verbose = atoi(argv[1]);
		if (verbose < 0) verbose = 0;
		break;		
	case 1:
	default:
		verbose = 0;
	}
	if (verbose) {
		fprintf(stderr,"\n*** Simple memory test\n|\n");
	}

	/* ----------------------------------------------------------------- */
	/* Round one, do a normal allocation, and free the blocks again.     */
	/* ----------------------------------------------------------------- */
	/* flush mem lib output to stderr */
	MEM_set_error_callback(mem_error_cb);
	
	for (i = 0; i < NUM_BLOCKS; i++) {
		int blocksize = 10000;
		char tagstring[1000];
		if (verbose > 1) printf("|--* Allocating block %d\n", i);
		sprintf(tagstring,"Memblock no. %d : ", i);
		p[i]= MEM_callocN(blocksize, strdup(tagstring));
	}

	/* report on that */
	if (verbose > 1) MEM_printmemlist();

	/* memory is there: test it */
	error_status = MEM_check_memory_integrity();

	if (verbose) {
		if (error_status) {
			fprintf(stderr, "|--* Memory test FAILED\n|\n");
		}
		else {
			fprintf(stderr, "|--* Memory tested as good (as it should be)\n|\n");
		}
	} 

	for (i = 0; i < NUM_BLOCKS; i++) {
		MEM_freeN(p[i]);
	}

	/* ----------------------------------------------------------------- */
	/* Round two, do a normal allocation, and corrupt some blocks.       */
	/* ----------------------------------------------------------------- */
	/* switch off, because it will complain about some things.           */
	MEM_set_error_callback(NULL);

	for (i = 0; i < NUM_BLOCKS; i++) {
		int blocksize = 10000;
		char tagstring[1000];
		if (verbose > 1) printf("|--* Allocating block %d\n", i);
		sprintf(tagstring,"Memblock no. %d : ", i);
		p[i]= MEM_callocN(blocksize, strdup(tagstring));
	}

	/* now corrupt a few blocks...*/
	ip = (int*) p[5] - 50;
	for (i = 0; i< 1000; i++,ip++) *ip = i+1;
	ip = (int*) p[6];
	*(ip+10005) = 0;
	
	retval = MEM_check_memory_integrity();

	/* the test should have failed */
	error_status |= !retval;		
	if (verbose) {
		if (retval) {
			fprintf(stderr, "|--* Memory test failed (as it should be)\n");
		}
		else {
			fprintf(stderr, "|--* Memory test FAILED to find corrupted blocks \n");
		}
	} 
	
	for (i = 0; i < NUM_BLOCKS; i++) {
		MEM_freeN(p[i]);
	}


	if (verbose && error_status) {
		fprintf(stderr,"|--* Memory was corrupted\n");
	}
	/* ----------------------------------------------------------------- */	
	if (verbose) {
		if (error_status) {
			fprintf(stderr,"|\n|--* Errors were detected\n");
		}
		else {
			fprintf(stderr,"|\n|--* Test exited succesfully\n");
		}
		
		fprintf(stderr,"|\n*** Finished test\n\n");
	}
	return error_status;
}
Exemplo n.º 5
0
/* called in creator.c even... tsk, split this! */
void WM_exit(bContext *C)
{
	wmWindow *win;

	sound_exit();

	/* first wrap up running stuff, we assume only the active WM is running */
	/* modal handlers are on window level freed, others too? */
	/* note; same code copied in wm_files.c */
	if(C && CTX_wm_manager(C)) {
		
		WM_jobs_stop_all(CTX_wm_manager(C));
		
		for(win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
			
			CTX_wm_window_set(C, win);	/* needed by operator close callbacks */
			WM_event_remove_handlers(C, &win->handlers);
			WM_event_remove_handlers(C, &win->modalhandlers);
			ED_screen_exit(C, win, win->screen);
		}
	}
	wm_operatortype_free();
	WM_menutype_free();
	
	/* all non-screen and non-space stuff editors did, like editmode */
	if(C)
		ED_editors_exit(C);

//	XXX	
//	BIF_GlobalReebFree();
//	BIF_freeRetarget();
	BIF_freeTemplates(C);
	
	free_ttfont(); /* bke_font.h */
	
	free_openrecent();
	
	BKE_freecubetable();
	
	fastshade_free_render();	/* shaded view */
	ED_preview_free_dbase();	/* frees a Main dbase, before free_blender! */

	if(C && CTX_wm_manager(C))
		wm_free_reports(C);			/* before free_blender! - since the ListBases get freed there */
		
	free_blender();				/* blender.c, does entire library and spacetypes */
//	free_matcopybuf();
	free_anim_copybuf();
	free_anim_drivers_copybuf();
	free_posebuf();
//	free_vertexpaint();
//	free_imagepaint();
	
//	fsmenu_free();

	BLF_exit();

	RE_FreeAllRender();
	RE_engines_exit();
	
//	free_txt_data();
	

#ifndef DISABLE_PYTHON
	/* XXX - old note */
	/* before free_blender so py's gc happens while library still exists */
	/* needed at least for a rare sigsegv that can happen in pydrivers */

	/* Update for blender 2.5, move after free_blender because blender now holds references to PyObject's
	 * so decref'ing them after python ends causes bad problems every time
	 * the pyDriver bug can be fixed if it happens again we can deal with it then */
	BPY_end_python();
#endif

	libtiff_exit();
	
#ifdef WITH_QUICKTIME
	quicktime_exit();
#endif
	
	if (!G.background) {
// XXX		UI_filelist_free_icons();
	}
	
	GPU_buffer_pool_free(0);
	GPU_extensions_exit();
	
//	if (copybuf) MEM_freeN(copybuf);
//	if (copybufinfo) MEM_freeN(copybufinfo);
	
	BKE_undo_save_quit();	// saves quit.blend if global undo is on
	BKE_reset_undo(); 
	
	ED_file_exit(); /* for fsmenu */

	UI_exit();
	BKE_userdef_free();

	RNA_exit(); /* should be after BPY_end_python so struct python slots are cleared */
	
	wm_ghost_exit();

	CTX_free(C);
	
	SYS_DeleteSystem(SYS_GetSystem());

	if(MEM_get_memory_blocks_in_use()!=0) {
		printf("Error Totblock: %d\n", MEM_get_memory_blocks_in_use());
		MEM_printmemlist();
	}
	wm_autosave_delete();
	
	printf("\nBlender quit\n");
	
#ifdef WIN32   
	/* ask user to press enter when in debug mode */
	if(G.f & G_DEBUG) {
		printf("press enter key to exit...\n\n");
		getchar();
	}
#endif 
	
	exit(G.afbreek==1);
}
Exemplo n.º 6
0
/* note, doesnt run exit() call WM_exit() for that */
void WM_exit_ext(bContext *C, const short do_python)
{
	wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;

	sound_exit();

	/* first wrap up running stuff, we assume only the active WM is running */
	/* modal handlers are on window level freed, others too? */
	/* note; same code copied in wm_files.c */
	if (C && wm) {
		wmWindow *win;

		if (!G.background) {
			if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_valid(NULL)) {
				/* save the undo state as quit.blend */
				char filename[FILE_MAX];
				
				BLI_make_file_string("/", filename, BLI_temporary_dir(), BLENDER_QUIT_FILE);

				if (BKE_undo_save_file(filename))
					printf("Saved session recovery to '%s'\n", filename);
			}
		}
		
		WM_jobs_kill_all(wm);

		for (win = wm->windows.first; win; win = win->next) {
			
			CTX_wm_window_set(C, win);  /* needed by operator close callbacks */
			WM_event_remove_handlers(C, &win->handlers);
			WM_event_remove_handlers(C, &win->modalhandlers);
			ED_screen_exit(C, win, win->screen);
		}
	}

	BKE_addon_pref_type_free();
	wm_operatortype_free();
	wm_dropbox_free();
	WM_menutype_free();
	WM_uilisttype_free();
	
	/* all non-screen and non-space stuff editors did, like editmode */
	if (C)
		ED_editors_exit(C);

//	XXX	
//	BIF_GlobalReebFree();
//	BIF_freeRetarget();
	BIF_freeTemplates(C);

	free_openrecent();
	
	BKE_mball_cubeTable_free();
	
	/* render code might still access databases */
	RE_FreeAllRender();
	RE_engines_exit();
	
	ED_preview_free_dbase();  /* frees a Main dbase, before free_blender! */

	if (C && wm)
		wm_free_reports(C);  /* before free_blender! - since the ListBases get freed there */

	BKE_sequencer_free_clipboard(); /* sequencer.c */
	BKE_tracking_clipboard_free();
		
#ifdef WITH_COMPOSITOR
	COM_deinitialize();
#endif
	
	free_blender();  /* blender.c, does entire library and spacetypes */
//	free_matcopybuf();
	free_anim_copybuf();
	free_anim_drivers_copybuf();
	free_fmodifiers_copybuf();
	ED_clipboard_posebuf_free();
	BKE_node_clipboard_clear();

	BLF_exit();

#ifdef WITH_INTERNATIONAL
	BLF_free_unifont();
	BLF_free_unifont_mono();
	BLF_lang_free();
#endif
	
	ANIM_keyingset_infos_exit();
	
//	free_txt_data();
	

#ifdef WITH_PYTHON
	/* option not to close python so we can use 'atexit' */
	if (do_python) {
		/* XXX - old note */
		/* before free_blender so py's gc happens while library still exists */
		/* needed at least for a rare sigsegv that can happen in pydrivers */

		/* Update for blender 2.5, move after free_blender because blender now holds references to PyObject's
		 * so decref'ing them after python ends causes bad problems every time
		 * the pyDriver bug can be fixed if it happens again we can deal with it then */
		BPY_python_end();
	}
#else
	(void)do_python;
#endif

	GPU_global_buffer_pool_free();
	GPU_free_unused_buffers();
	GPU_extensions_exit();

	BKE_reset_undo(); 
	
	ED_file_exit(); /* for fsmenu */

	UI_exit();
	BKE_userdef_free();

	RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */
	
	wm_ghost_exit();

	CTX_free(C);
#ifdef WITH_GAMEENGINE
	SYS_DeleteSystem(SYS_GetSystem());
#endif
	
	GHOST_DisposeSystemPaths();

	if (MEM_get_memory_blocks_in_use() != 0) {
		printf("Error: Not freed memory blocks: %d\n", MEM_get_memory_blocks_in_use());
		MEM_printmemlist();
	}
	wm_autosave_delete();
	
	printf("\nBlender quit\n");
	
#ifdef WIN32   
	/* ask user to press a key when in debug mode */
	if (G.debug & G_DEBUG) {
		printf("Press any key to exit . . .\n\n");
		wait_for_console_key();
	}
#endif 
}