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