2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2006 Blender Foundation.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/render/intern/source/external_engine.c
36 #include "MEM_guardedalloc.h"
38 #include "BLF_translation.h"
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42 #include "BLI_utildefines.h"
44 #include "BKE_global.h"
45 #include "BKE_report.h"
46 #include "BKE_scene.h"
48 #include "IMB_imbuf.h"
49 #include "IMB_imbuf_types.h"
52 #include "BPY_extern.h"
55 #include "RE_engine.h"
56 #include "RE_pipeline.h"
58 #include "initrender.h"
59 #include "render_types.h"
60 #include "render_result.h"
62 /* Render Engine Types */
64 static RenderEngineType internal_render_type = {
66 "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
67 NULL, NULL, NULL, NULL,
71 #ifdef WITH_GAMEENGINE
73 static RenderEngineType internal_game_type = {
75 "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
76 NULL, NULL, NULL, NULL,
82 ListBase R_engines = {NULL, NULL};
84 void RE_engines_init(void)
86 BLI_addtail(&R_engines, &internal_render_type);
87 #ifdef WITH_GAMEENGINE
88 BLI_addtail(&R_engines, &internal_game_type);
92 void RE_engines_exit(void)
94 RenderEngineType *type, *next;
96 for (type = R_engines.first; type; type = next) {
99 BLI_remlink(&R_engines, type);
101 if (!(type->flag & RE_INTERNAL)) {
103 type->ext.free(type->ext.data);
110 RenderEngineType *RE_engines_find(const char *idname)
112 RenderEngineType *type;
114 type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
116 type = &internal_render_type;
121 int RE_engine_is_external(Render *re)
123 RenderEngineType *type = RE_engines_find(re->r.engine);
124 return (type && type->render);
129 RenderEngine *RE_engine_create(RenderEngineType *type)
131 RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine");
137 void RE_engine_free(RenderEngine *engine)
140 if (engine->py_instance) {
141 BPY_DECREF_RNA_INVALIDATE(engine->py_instance);
146 MEM_freeN(engine->text);
153 RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername)
155 Render *re = engine->re;
156 RenderResult *result;
159 /* ensure the coordinates are within the right limits */
160 CLAMP(x, 0, re->result->rectx);
161 CLAMP(y, 0, re->result->recty);
162 CLAMP(w, 0, re->result->rectx);
163 CLAMP(h, 0, re->result->recty);
165 if (x + w > re->result->rectx)
166 w = re->result->rectx - x;
167 if (y + h > re->result->recty)
168 h = re->result->recty - y;
170 /* allocate a render result */
172 disprect.xmax = x + w;
174 disprect.ymax = y + h;
176 result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername);
178 /* todo: make this thread safe */
180 /* can be NULL if we CLAMP the width or height to 0 */
182 BLI_addtail(&engine->fullresult, result);
184 result->tilerect.xmin += re->disprect.xmin;
185 result->tilerect.xmax += re->disprect.xmin;
186 result->tilerect.ymin += re->disprect.ymin;
187 result->tilerect.ymax += re->disprect.ymin;
193 void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
195 Render *re = engine->re;
198 result->renlay = result->layers.first; /* weak, draws first layer always */
199 re->display_draw(re->ddh, result, NULL);
203 void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel)
205 Render *re = engine->re;
212 /* merge. on break, don't merge in result for preview renders, looks nicer */
214 /* for exr tile render, detect tiles that are done */
215 for (pa = re->parts.first; pa; pa = pa->next) {
216 if (result->tilerect.xmin == pa->disprect.xmin &&
217 result->tilerect.ymin == pa->disprect.ymin &&
218 result->tilerect.xmax == pa->disprect.xmax &&
219 result->tilerect.ymax == pa->disprect.ymax)
225 if (re->result->do_exr_tile)
226 render_result_exr_file_merge(re->result, result);
227 else if (!(re->test_break(re->tbh) && (re->r.scemode & R_PREVIEWBUTS)))
228 render_result_merge(re->result, result);
231 if (!re->test_break(re->tbh)) {
232 result->renlay = result->layers.first; /* weak, draws first layer always */
233 re->display_draw(re->ddh, result, NULL);
238 BLI_remlink(&engine->fullresult, result);
239 render_result_free(result);
244 int RE_engine_test_break(RenderEngine *engine)
246 Render *re = engine->re;
249 return re->test_break(re->tbh);
256 void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
258 Render *re = engine->re;
260 /* stats draw callback */
262 re->i.statstr = stats;
263 re->i.infostr = info;
264 re->stats_draw(re->sdh, &re->i);
265 re->i.infostr = NULL;
266 re->i.statstr = NULL;
269 /* set engine text */
271 MEM_freeN(engine->text);
275 if (stats && stats[0] && info && info[0])
276 engine->text = BLI_sprintfN("%s | %s", stats, info);
277 else if (info && info[0])
278 engine->text = BLI_strdup(info);
279 else if (stats && stats[0])
280 engine->text = BLI_strdup(stats);
283 void RE_engine_update_progress(RenderEngine *engine, float progress)
285 Render *re = engine->re;
288 CLAMP(progress, 0.0f, 1.0f);
289 re->progress(re->prh, progress);
293 void RE_engine_report(RenderEngine *engine, int type, const char *msg)
295 BKE_report(engine->re->reports, type, msg);
300 int RE_engine_render(Render *re, int do_all)
302 RenderEngineType *type = RE_engines_find(re->r.engine);
303 RenderEngine *engine;
305 /* verify if we can render */
308 if ((re->r.scemode & R_PREVIEWBUTS) && !(type->flag & RE_USE_PREVIEW))
310 if (do_all && !(type->flag & RE_USE_POSTPROCESS))
312 if (!do_all && (type->flag & RE_USE_POSTPROCESS))
315 /* create render result */
316 BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
317 if (re->result == NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
321 render_result_free(re->result);
323 savebuffers = (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM;
324 re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS);
326 BLI_rw_mutex_unlock(&re->resultmutex);
328 if (re->result == NULL)
331 /* set render info */
332 re->i.cfra = re->scene->r.cfra;
333 BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name));
334 re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
337 engine = RE_engine_create(type);
340 if (re->flag & R_ANIMATION)
341 engine->flag |= RE_ENGINE_ANIMATION;
342 if (re->r.scemode & R_PREVIEWBUTS)
343 engine->flag |= RE_ENGINE_PREVIEW;
344 engine->camera_override = re->camera_override;
346 engine->resolution_x = re->winx;
347 engine->resolution_y = re->winy;
349 if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_PREVIEWBUTS)) == 0)
350 BKE_scene_update_for_newframe(re->main, re->scene, re->lay);
352 initparts(re, FALSE);
353 engine->tile_x = re->partx;
354 engine->tile_y = re->party;
356 if (re->result->do_exr_tile)
357 render_result_exr_file_begin(re);
360 type->update(engine, re->main, re->scene);
363 type->render(engine, re->scene);
365 if (re->result->do_exr_tile) {
366 BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
367 render_result_exr_file_end(re);
368 BLI_rw_mutex_unlock(&re->resultmutex);
375 render_result_free_list(&engine->fullresult, engine->fullresult.first);
377 RE_engine_free(engine);
379 if (BKE_reports_contain(re->reports, RPT_ERROR))