1// @configure_input@ 2 3/**************************************************************************\ 4 * Copyright (c) Kongsberg Oil & Gas Technologies AS 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 14 * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * Neither the name of the copyright holder nor the names of its 19 * contributors may be used to endorse or promote products derived from 20 * this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33\**************************************************************************/ 34 35/* 36 * TODO 37 * - field "SoSFFloat delay" for making node wait a certain time after 38 * last scene change before re-rendering the texture 39 * - field "SoSFBool dirty" for making texture show itself as dirty 40 * (stippled?) until it has been rerendered (in case it takes time to 41 * rerender scene). 42 */ 43 44#include <assert.h> 45#include <string.h> 46 47#include <Inventor/errors/SoDebugError.h> 48#include <Inventor/sensors/SoFieldSensor.h> 49#include <Inventor/sensors/SoOneShotSensor.h> 50#include <Inventor/actions/SoGLRenderAction.h> 51#include <Inventor/SoOffscreenRenderer.h> 52#include <Inventor/misc/SoNotification.h> 53 54#include <Inventor/@Gui@/nodes/SoGuiSceneTexture2.h> 55 56// ************************************************************************* 57 58class SceneTexture2 { 59public: 60 SceneTexture2(void); 61 62 SoGuiSceneTexture2 * api; 63 64 SbVec2s prevsize; 65 SoOffscreenRenderer * renderer; 66 67 SoFieldSensor * size_sensor; 68 static void size_updated_cb(void * closure, SoSensor * sensor); 69 70 SoOneShotSensor * render_sensor; 71 static void render_cb(void * closure, SoSensor * sensor); 72}; 73 74// ************************************************************************* 75 76#define PRIVATE(obj) ((SceneTexture2 *) obj->internals) 77 78void 79SoGuiSceneTexture2::initClass(void) 80{ 81 SO_NODE_INIT_CLASS(SoGuiSceneTexture2, SoTexture2, "Texture2"); 82} 83 84SO_NODE_SOURCE(SoGuiSceneTexture2); 85 86SoGuiSceneTexture2::SoGuiSceneTexture2(void) 87{ 88 this->internals = new SceneTexture2; 89 PRIVATE(this)->api = this; 90 91 SO_NODE_CONSTRUCTOR(SoGuiSceneTexture2); 92 SO_NODE_ADD_FIELD(size, (SbVec2f(256.0f, 256.0f))); 93 SO_NODE_ADD_FIELD(scene, (NULL)); 94 95 PRIVATE(this)->size_sensor = new SoFieldSensor(SceneTexture2::size_updated_cb, PRIVATE(this)); 96 PRIVATE(this)->size_sensor->attach(&(this->size)); 97 PRIVATE(this)->render_sensor = new SoOneShotSensor(SceneTexture2::render_cb, PRIVATE(this)); 98} 99 100SoGuiSceneTexture2::~SoGuiSceneTexture2(void) 101{ 102 delete PRIVATE(this)->size_sensor; 103 delete PRIVATE(this)->render_sensor; 104 if ( PRIVATE(this)->renderer != NULL ) { 105 delete PRIVATE(this)->renderer; 106 } 107} 108 109// We overload notify() because we need to know when the scene graph has 110// been updated, but want to stop that notification from propagating 111// through the external scene graph. We only want the texture update to 112// trigger re-rendering. 113void 114SoGuiSceneTexture2::notify(SoNotList * list) 115{ 116 if ( list->getLastField() == &(this->scene) ) { 117 PRIVATE(this)->render_sensor->schedule(); 118 return; 119 } 120 inherited::notify(list); 121} 122 123// 124// we don't want to write out the image and filename fields. 125// 126void 127SoGuiSceneTexture2::write(SoWriteAction * action) 128{ 129 this->image.setDefault(TRUE); 130 this->filename.setDefault(TRUE); 131 inherited::write(action); 132} 133 134 135#undef PRIVATE 136 137// ************************************************************************* 138 139#define PUBLIC(obj) (((SceneTexture2 *) obj)->api) 140 141SceneTexture2::SceneTexture2(void) 142{ 143 this->api = NULL; 144 this->prevsize = SbVec2s(-1, -1); 145 this->renderer = NULL; 146 this->size_sensor = NULL; 147 this->render_sensor = NULL; 148} 149 150void 151SceneTexture2::size_updated_cb(void * closure, SoSensor * sensor) 152{ 153 assert(closure); 154 SceneTexture2 * me = (SceneTexture2 *) closure; 155 SbVec2f tempsize = PUBLIC(me)->size.getValue(); 156 SbVec2s size; 157 size[0] = (short) tempsize[0]; 158 size[1] = (short) tempsize[1]; 159 if ( size != me->prevsize ) { 160 if ( me->renderer != NULL ) { 161 me->renderer->setViewportRegion(SbViewportRegion(size)); 162 PUBLIC(me)->image.setValue(size, 3, NULL); 163 me->render_sensor->schedule(); 164 } 165 me->prevsize = size; 166 } 167} 168 169void 170SceneTexture2::render_cb(void * closure, SoSensor * sensor) 171{ 172 assert(closure); 173 SceneTexture2 * me = (SceneTexture2 *) closure; 174 SbVec2f tempsize = PUBLIC(me)->size.getValue(); 175 SbVec2s size; 176 size[0] = (short) tempsize[0]; 177 size[1] = (short) tempsize[1]; 178 int nc = 3; 179 SoNode * scene = PUBLIC(me)->scene.getValue(); 180 SbBool save = PUBLIC(me)->image.enableNotify(FALSE); 181 if ( scene != NULL ) { 182 if ( me->renderer == NULL ) { 183 me->renderer = new SoOffscreenRenderer(SbViewportRegion(size)); 184 me->renderer->setComponents(SoOffscreenRenderer::RGB); 185 me->renderer->getGLRenderAction()->setTransparencyType(SoGLRenderAction::BLEND); 186 me->prevsize = size; 187 PUBLIC(me)->image.setValue(size, nc, NULL); 188 } 189 me->renderer->render(scene); 190 unsigned char * renderbuffer = me->renderer->getBuffer(); 191 unsigned char * imagebytes = PUBLIC(me)->image.startEditing(size, nc); 192 memcpy(imagebytes, renderbuffer, size[0] * size[1] * nc); 193 PUBLIC(me)->image.finishEditing(); 194 } else { 195 unsigned char * imagebytes = PUBLIC(me)->image.startEditing(size, nc); 196 memset(imagebytes, 0, size[0] * size[1] * nc); 197 PUBLIC(me)->image.finishEditing(); 198 } 199 PUBLIC(me)->image.enableNotify(save); 200 if ( save ) PUBLIC(me)->image.touch(); 201} 202 203#undef PUBLIC 204 205// ************************************************************************* 206