487271ea1f725cfc61936fab5976954c6f5a4ec3
[blender-staging.git] / source / blender / render / intern / source / external_engine.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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. 
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2006 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/render/intern/source/external_engine.c
29  *  \ingroup render
30  */
31
32 #include <stddef.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLF_translation.h"
39
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42 #include "BLI_utildefines.h"
43
44 #include "BKE_global.h"
45 #include "BKE_report.h"
46 #include "BKE_scene.h"
47
48 #include "IMB_imbuf.h"
49 #include "IMB_imbuf_types.h"
50
51 #ifdef WITH_PYTHON
52 #include "BPY_extern.h"
53 #endif
54
55 #include "RE_engine.h"
56 #include "RE_pipeline.h"
57
58 #include "render_types.h"
59 #include "render_result.h"
60
61 /* Render Engine Types */
62
63 static RenderEngineType internal_render_type = {
64         NULL, NULL,
65         "BLENDER_RENDER", N_("Blender Render"), RE_INTERNAL,
66         NULL, NULL, NULL, NULL,
67         {NULL, NULL, NULL}
68 };
69
70 #ifdef WITH_GAMEENGINE
71
72 static RenderEngineType internal_game_type = {
73         NULL, NULL,
74         "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME,
75         NULL, NULL, NULL, NULL,
76         {NULL, NULL, NULL}
77 };
78
79 #endif
80
81 ListBase R_engines = {NULL, NULL};
82
83 void RE_engines_init(void)
84 {
85         BLI_addtail(&R_engines, &internal_render_type);
86 #ifdef WITH_GAMEENGINE
87         BLI_addtail(&R_engines, &internal_game_type);
88 #endif
89 }
90
91 void RE_engines_exit(void)
92 {
93         RenderEngineType *type, *next;
94
95         for (type = R_engines.first; type; type = next) {
96                 next = type->next;
97
98                 BLI_remlink(&R_engines, type);
99
100                 if (!(type->flag & RE_INTERNAL)) {
101                         if (type->ext.free)
102                                 type->ext.free(type->ext.data);
103
104                         MEM_freeN(type);
105                 }
106         }
107 }
108
109 RenderEngineType *RE_engines_find(const char *idname)
110 {
111         RenderEngineType *type;
112         
113         type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
114         if (!type)
115                 type = &internal_render_type;
116
117         return type;
118 }
119
120 int RE_engine_is_external(Render *re)
121 {
122         RenderEngineType *type = RE_engines_find(re->r.engine);
123         return (type && type->render);
124 }
125
126 /* Create, Free */
127
128 RenderEngine *RE_engine_create(RenderEngineType *type)
129 {
130         RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine");
131         engine->type = type;
132
133         return engine;
134 }
135
136 void RE_engine_free(RenderEngine *engine)
137 {
138 #ifdef WITH_PYTHON
139         if (engine->py_instance) {
140                 BPY_DECREF(engine->py_instance);
141         }
142 #endif
143
144         if (engine->text)
145                 MEM_freeN(engine->text);
146
147         MEM_freeN(engine);
148 }
149
150 /* Render Results */
151
152 RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h)
153 {
154         Render *re = engine->re;
155         RenderResult *result;
156         rcti disprect;
157
158         /* ensure the coordinates are within the right limits */
159         CLAMP(x, 0, re->result->rectx);
160         CLAMP(y, 0, re->result->recty);
161         CLAMP(w, 0, re->result->rectx);
162         CLAMP(h, 0, re->result->recty);
163
164         if (x + w > re->result->rectx)
165                 w = re->result->rectx - x;
166         if (y + h > re->result->recty)
167                 h = re->result->recty - y;
168
169         /* allocate a render result */
170         disprect.xmin = x;
171         disprect.xmax = x + w;
172         disprect.ymin = y;
173         disprect.ymax = y + h;
174
175         result = render_result_new(re, &disprect, 0, RR_USE_MEM);
176
177         /* can be NULL if we CLAMP the width or height to 0 */
178         if (result) {
179                 BLI_addtail(&engine->fullresult, result);
180
181                 result->tilerect.xmin += re->disprect.xmin;
182                 result->tilerect.xmax += re->disprect.xmin;
183                 result->tilerect.ymin += re->disprect.ymin;
184                 result->tilerect.ymax += re->disprect.ymin;
185         }
186
187         return result;
188 }
189
190 void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
191 {
192         Render *re = engine->re;
193
194         if (result) {
195                 result->renlay = result->layers.first; /* weak, draws first layer always */
196                 re->display_draw(re->ddh, result, NULL);
197         }
198 }
199
200 void RE_engine_end_result(RenderEngine *engine, RenderResult *result)
201 {
202         Render *re = engine->re;
203
204         if (!result)
205                 return;
206
207         /* merge. on break, don't merge in result for preview renders, looks nicer */
208         if (!(re->test_break(re->tbh) && (re->r.scemode & R_PREVIEWBUTS)))
209                 render_result_merge(re->result, result);
210
211         /* draw */
212         if (!re->test_break(re->tbh)) {
213                 result->renlay = result->layers.first; /* weak, draws first layer always */
214                 re->display_draw(re->ddh, result, NULL);
215         }
216
217         /* free */
218         render_result_free_list(&engine->fullresult, result);
219 }
220
221 /* Cancel */
222
223 int RE_engine_test_break(RenderEngine *engine)
224 {
225         Render *re = engine->re;
226
227         if (re)
228                 return re->test_break(re->tbh);
229         
230         return 0;
231 }
232
233 /* Statistics */
234
235 void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info)
236 {
237         Render *re = engine->re;
238
239         /* stats draw callback */
240         if (re) {
241                 re->i.statstr = stats;
242                 re->i.infostr = info;
243                 re->stats_draw(re->sdh, &re->i);
244                 re->i.infostr = NULL;
245                 re->i.statstr = NULL;
246         }
247
248         /* set engine text */
249         if (engine->text) {
250                 MEM_freeN(engine->text);
251                 engine->text = NULL;
252         }
253
254         if (stats && stats[0] && info && info[0])
255                 engine->text = BLI_sprintfN("%s | %s", stats, info);
256         else if (info && info[0])
257                 engine->text = BLI_strdup(info);
258         else if (stats && stats[0])
259                 engine->text = BLI_strdup(stats);
260 }
261
262 void RE_engine_update_progress(RenderEngine *engine, float progress)
263 {
264         Render *re = engine->re;
265
266         if (re) {
267                 CLAMP(progress, 0.0f, 1.0f);
268                 re->progress(re->prh, progress);
269         }
270 }
271
272 void RE_engine_report(RenderEngine *engine, int type, const char *msg)
273 {
274         BKE_report(engine->re->reports, type, msg);
275 }
276
277 /* Render */
278
279 int RE_engine_render(Render *re, int do_all)
280 {
281         RenderEngineType *type = RE_engines_find(re->r.engine);
282         RenderEngine *engine;
283
284         /* verify if we can render */
285         if (!type->render)
286                 return 0;
287         if ((re->r.scemode & R_PREVIEWBUTS) && !(type->flag & RE_USE_PREVIEW))
288                 return 0;
289         if (do_all && !(type->flag & RE_USE_POSTPROCESS))
290                 return 0;
291         if (!do_all && (type->flag & RE_USE_POSTPROCESS))
292                 return 0;
293
294         /* create render result */
295         BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
296         if (re->result == NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
297                 if (re->result)
298                         render_result_free(re->result);
299                 re->result = render_result_new(re, &re->disprect, 0, 0);
300         }
301         BLI_rw_mutex_unlock(&re->resultmutex);
302         
303         if (re->result == NULL)
304                 return 1;
305
306         /* set render info */
307         re->i.cfra = re->scene->r.cfra;
308         BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name));
309         re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
310
311         /* render */
312         engine = RE_engine_create(type);
313         engine->re = re;
314
315         if (re->flag & R_ANIMATION)
316                 engine->flag |= RE_ENGINE_ANIMATION;
317         if (re->r.scemode & R_PREVIEWBUTS)
318                 engine->flag |= RE_ENGINE_PREVIEW;
319         engine->camera_override = re->camera_override;
320
321         if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_PREVIEWBUTS)) == 0)
322                 BKE_scene_update_for_newframe(re->main, re->scene, re->lay);
323
324         if (type->update)
325                 type->update(engine, re->main, re->scene);
326         if (type->render)
327                 type->render(engine, re->scene);
328
329         render_result_free_list(&engine->fullresult, engine->fullresult.first);
330
331         RE_engine_free(engine);
332
333         if (BKE_reports_contain(re->reports, RPT_ERROR))
334                 G.is_break = TRUE;
335         
336         return 1;
337 }
338