1
1

Compare commits

...

4 Commits

Author SHA1 Message Date
4ef064d4c2 BGE: bge.render.offScreenCreate() takes one more parameter, reflect this in the argument format string. 2017-05-04 13:07:50 +02:00
9bf3c96376 BGE: Fix 1-pixel bug with viewport and aspect ratio.
The canvas viewport is initially set as (0,0,width,height) but treated at
OGL level as (left,bottom,right,top), which differs by 1 pixel.
This was causing a wrong aspect ratio in the render.
2017-04-03 08:46:55 +02:00
9847537979 BGE: new bge.logic.Render() to perform render w/o logic step.
This function works only if python has control:
1. add scene custom property, call it __main__
2. give it string value as the name of a text block
3. code game loop in python in text block. Example:

import bge

bge.logic.setUseExternalClock(True)
t = 0.0;
scene = bge.logic.getCurrentScene()
cam = scene.cameras["Camera"]
cam.setViewport(120,120,370,370)
while not bge.logic.NextFrame():
    cam.useViewport = True
    # second render with viewport enable, clock time unchanged
    bge.logic.Render()
    # advance animation for next frame
    t += 0.02
    bge.logic.setClockTime(t)
    cam.useViewport = False
2017-04-01 00:57:38 +02:00
e4ea5e5810 BGE: 2D filter additions.
gpu_draw: skip color management for textures declared as 'non-color'.

New reserved names in 2D filters: bgl_ObjectTextureX (X=0 to 4) to
access texture channels 0 to 4 of the object on which the 2D filter
is defined.

Force U.use_16bit_textures to 1 in the blender player to give access to
floating point textures in the 2D fitlers shaders.

bge.logic.setOffScreen(True) to define and use a floating point offscreen
render buffer of the same size than the framebuffer in the main BGE loop.
Useful to get floating point results from 2D filters. The offscreen render
buffer will automatically be used by bge.texture.ImageViewport if it's enabled.
It is legal to call bge.logic.setOffScreen(True/False) to disable and reenable
the framebuffer on a frame by frame basis.

New refresh mode for bge.texture.ImageViewport and bge.texture.ImageRender
objects:
iv.refresh(buffer, mode)
  mode = "DEPTH" to retrieve floating point depth buffer
       = "RG32F" to retrieve red and green channels as floating point.
       = "RGB32F" to retrieve red, green and blue channels as floating point
       = "RGBA32F" to retrieve red, green, blue and alpha channels as floating point.
For ImageViewport and ImageRender, refresh() bypasses all filters and object
options and retrieve directly from the frame buffer or render buffer.
2017-03-21 00:26:52 +01:00
32 changed files with 387 additions and 108 deletions

View File

@@ -641,7 +641,7 @@ int GPU_verify_image(
}
/* TODO unneeded when float images are correctly treated as linear always */
if (!is_data) {
if (!is_data && !(ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) {
do_color_management = true;
}
}

View File

@@ -122,6 +122,23 @@ static BlendFileData *load_game_data(const char *filename)
return bfd;
}
static void BL_KetsjiRender(KX_KetsjiEngine *ketsjiengine, ARegion *ar, Scene *scene, int draw_letterbox)
{
if (draw_letterbox) {
// Clear screen to border color
// We do this here since we set the canvas to be within the frames. This means the engine
// itself is unaware of the extra space, so we clear the whole region for it.
glClearColor(scene->gm.framing.col[0], scene->gm.framing.col[1], scene->gm.framing.col[2], 1.0f);
glViewport(ar->winrct.xmin, ar->winrct.ymin,
BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
glClear(GL_COLOR_BUFFER_BIT);
}
// render the frame
ketsjiengine->Render();
}
static int BL_KetsjiNextFrame(KX_KetsjiEngine *ketsjiengine, bContext *C, wmWindow *win, Scene *scene, ARegion *ar,
KX_BlenderKeyboardDevice* keyboarddevice, KX_BlenderMouseDevice* mousedevice, int draw_letterbox)
{
@@ -134,18 +151,7 @@ static int BL_KetsjiNextFrame(KX_KetsjiEngine *ketsjiengine, bContext *C, wmWind
bool render = ketsjiengine->NextFrame();
if (render) {
if (draw_letterbox) {
// Clear screen to border color
// We do this here since we set the canvas to be within the frames. This means the engine
// itself is unaware of the extra space, so we clear the whole region for it.
glClearColor(scene->gm.framing.col[0], scene->gm.framing.col[1], scene->gm.framing.col[2], 1.0f);
glViewport(ar->winrct.xmin, ar->winrct.ymin,
BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
glClear(GL_COLOR_BUFFER_BIT);
}
// render the frame
ketsjiengine->Render();
BL_KetsjiRender(ketsjiengine, ar, scene, draw_letterbox);
}
wm_window_process_events_nosleep();
@@ -211,6 +217,13 @@ static int BL_KetsjiPyNextFrame(void *state0)
state->mousedevice,
state->draw_letterbox);
}
static void BL_KetsjiPyRender(void *state0)
{
BL_KetsjiNextFrameState *state = (BL_KetsjiNextFrameState *) state0;
BL_KetsjiRender(state->ketsjiengine, state->ar, state->scene, state->draw_letterbox);
}
#endif
@@ -526,6 +539,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
char *python_main = NULL;
pynextframestate.state = NULL;
pynextframestate.func = NULL;
pynextframestate.render = NULL;
python_main = KX_GetPythonMain(scene);
// the mainloop
@@ -548,6 +562,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
pynextframestate.state = &ketsjinextframestate;
pynextframestate.func = &BL_KetsjiPyNextFrame;
pynextframestate.render = &BL_KetsjiPyRender;
printf("Yielding control to Python script '%s'...\n", python_main);
PyRun_SimpleString(python_code);
printf("Exit Python script '%s'\n", python_main);

View File

@@ -210,8 +210,8 @@ SetViewPort(
* the width,height is calculated including both pixels
* therefore: max - min + 1
*/
int vp_width = (x2 - x1) + 1;
int vp_height = (y2 - y1) + 1;
int vp_width = (x2 - x1);
int vp_height = (y2 - y1);
int minx = m_frame_rect.GetLeft();
int miny = m_frame_rect.GetBottom();

View File

@@ -69,6 +69,7 @@
#include "KX_SCA_DynamicActuator.h"
#include "KX_SteeringActuator.h"
#include "KX_MouseActuator.h"
#include "KX_BlenderMaterial.h"
#include "KX_Scene.h"
#include "KX_KetsjiEngine.h"
@@ -911,6 +912,7 @@ void BL_ConvertActuators(const char* maggiename,
{
bTwoDFilterActuator *_2dfilter = (bTwoDFilterActuator*) bact->data;
SCA_2DFilterActuator *tmp = NULL;
BL_Material *mat = NULL;
RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode;
switch (_2dfilter->type) {
@@ -949,6 +951,16 @@ void BL_ConvertActuators(const char* maggiename,
break;
case ACT_2DFILTER_CUSTOMFILTER:
filtermode = RAS_2DFilterManager::RAS_2DFILTER_CUSTOMFILTER;
if (gameobj->GetMeshCount() > 0) {
unsigned int matid = 0;
RAS_MeshMaterial *meshMat = gameobj->GetMesh(0)->GetMeshMaterial(matid);
if (meshMat != NULL && meshMat->m_bucket != NULL) {
RAS_IPolyMaterial *polymat = meshMat->m_bucket->GetPolyMaterial();
if (polymat->GetFlag() & RAS_BLENDERGLSL) {
mat = ((KX_BlenderMaterial *)polymat)->GetBLMaterial();
}
}
}
break;
case ACT_2DFILTER_NOFILTER:
filtermode = RAS_2DFilterManager::RAS_2DFILTER_NOFILTER;
@@ -964,7 +976,7 @@ void BL_ConvertActuators(const char* maggiename,
break;
}
tmp = new SCA_2DFilterActuator(gameobj, filtermode, _2dfilter->flag,
tmp = new SCA_2DFilterActuator(gameobj, mat, filtermode, _2dfilter->flag,
_2dfilter->float_arg, _2dfilter->int_arg,
ketsjiEngine->GetRasterizer(), scene);

View File

@@ -40,6 +40,7 @@ SCA_2DFilterActuator::~SCA_2DFilterActuator()
SCA_2DFilterActuator::SCA_2DFilterActuator(
SCA_IObject *gameobj,
BL_Material *mat,
RAS_2DFilterManager::RAS_2DFILTER_MODE type,
short flag,
float float_arg,
@@ -55,9 +56,11 @@ SCA_2DFilterActuator::SCA_2DFilterActuator(
m_scene(scene)
{
m_gameobj = NULL;
m_mat = NULL;
if (gameobj) {
m_propNames = gameobj->GetPropertyNames();
m_gameobj = gameobj;
m_mat = mat;
}
}
@@ -90,7 +93,7 @@ bool SCA_2DFilterActuator::Update()
}
else if (m_type < RAS_2DFilterManager::RAS_2DFILTER_NUMBER_OF_FILTERS)
{
m_scene->Update2DFilter(m_propNames, m_gameobj, m_type, m_int_arg, m_shaderText);
m_scene->Update2DFilter(m_propNames, m_gameobj, m_mat, m_type, m_int_arg, m_shaderText);
}
// once the filter is in place, no need to update it again => disable the actuator
return false;

View File

@@ -35,6 +35,8 @@
#include "SCA_IActuator.h"
#include "SCA_IScene.h"
class BL_Material;
class SCA_2DFilterActuator : public SCA_IActuator
{
Py_Header
@@ -48,11 +50,13 @@ private:
STR_String m_shaderText;
RAS_IRasterizer* m_rasterizer;
SCA_IScene* m_scene;
BL_Material* m_mat;
public:
SCA_2DFilterActuator(
class SCA_IObject* gameobj,
BL_Material *mat,
RAS_2DFilterManager::RAS_2DFILTER_MODE type,
short flag,
float float_arg,

View File

@@ -74,7 +74,8 @@ public:
void RemoveDebugProperty(class CValue *gameobj, const STR_String &name);
void RemoveObjectDebugProperties(class CValue* gameobj);
virtual void Update2DFilter(std::vector<STR_String>& propNames, void* gameObj,
virtual void Update2DFilter(std::vector<STR_String>& propNames, void* gameObj,
void *mat,
RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode,
int pass, STR_String& text) {}

View File

@@ -97,11 +97,11 @@ void GPC_Canvas::SetViewPort(int x1, int y1, int x2, int y2)
m_viewport[0] = x1;
m_viewport[1] = y1;
m_viewport[2] = x2-x1 + 1;
m_viewport[3] = y2-y1 + 1;
m_viewport[2] = x2-x1;
m_viewport[3] = y2-y1;
glViewport(x1,y1,x2-x1 + 1,y2-y1 + 1);
glScissor(x1,y1,x2-x1 + 1,y2-y1 + 1);
glViewport(x1,y1,x2-x1,y2-y1);
glScissor(x1,y1,x2-x1,y2-y1);
}
void GPC_Canvas::UpdateViewPort(int x1, int y1, int x2, int y2)

View File

@@ -848,6 +848,12 @@ void GPG_Application::EngineNextFrame()
m_exitString = m_ketsjiengine->GetExitString();
}
void GPG_Application::EngineRender()
{
// render the frame
m_ketsjiengine->Render();
}
void GPG_Application::exitEngine()
{
// We only want to kill the engine if it has been initialized

View File

@@ -93,6 +93,7 @@ public:
bool StartGameEngine(int stereoMode);
void StopGameEngine();
void EngineNextFrame();
void EngineRender();
protected:
bool handleWheel(GHOST_IEvent* event);

View File

@@ -385,6 +385,11 @@ static bool GPG_NextFrame(GHOST_ISystem* system, GPG_Application *app, int &exit
return run;
}
static void GPG_Render(GPG_Application *app)
{
app->EngineRender();
}
struct GPG_NextFrameState {
GHOST_ISystem* system;
GPG_Application *app;
@@ -405,6 +410,12 @@ static int GPG_PyNextFrame(void *state0)
}
}
static void GPG_PyRender(void *state0)
{
GPG_NextFrameState *state = (GPG_NextFrameState *) state0;
GPG_Render(state->app);
}
int main(
int argc,
#ifdef WIN32
@@ -562,6 +573,7 @@ int main(
U.anisotropic_filter = 2;
// enable fast mipmap generation
U.use_gpu_mipmap = 1;
U.use_16bit_textures = 1;
BKE_sound_init_once();
@@ -1123,6 +1135,7 @@ int main(
char *python_main = NULL;
pynextframestate.state = NULL;
pynextframestate.func = NULL;
pynextframestate.render = NULL;
#ifdef WITH_PYTHON
python_main = KX_GetPythonMain(scene);
#endif // WITH_PYTHON
@@ -1140,6 +1153,7 @@ int main(
gpg_nextframestate.gs = &gs;
pynextframestate.state = &gpg_nextframestate;
pynextframestate.func = &GPG_PyNextFrame;
pynextframestate.render = &GPG_PyRender;
printf("Yielding control to Python script '%s'...\n", python_main);
PyRun_SimpleString(python_code);

View File

@@ -2018,7 +2018,7 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i)
if (!cam)
return;
m_canvas->SetViewPort(0,0,m_buffersize-1,m_buffersize-1);
m_canvas->SetViewPort(0,0,m_buffersize,m_buffersize);
// m_rasterizer->SetAmbient();
m_rasterizer->DisplayFog();

View File

@@ -52,6 +52,7 @@
#include "RAS_IRasterizer.h"
#include "RAS_ICanvas.h"
#include "RAS_ILightObject.h"
#include "RAS_IOffScreen.h"
#include "MT_Vector3.h"
#include "MT_Transform.h"
#include "SCA_IInputDevice.h"
@@ -109,6 +110,7 @@ double KX_KetsjiEngine::m_average_framerate = 0.0;
bool KX_KetsjiEngine::m_restrict_anim_fps = false;
short KX_KetsjiEngine::m_exitkey = 130; // ESC Key
bool KX_KetsjiEngine::m_doRender = true;
bool KX_KetsjiEngine::m_doOffScreen = false;
/**
* Constructor of the Ketsji Engine
@@ -116,6 +118,7 @@ bool KX_KetsjiEngine::m_doRender = true;
KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
: m_canvas(NULL),
m_rasterizer(NULL),
m_offScreenRender(NULL),
m_kxsystem(system),
m_sceneconverter(NULL),
m_networkdevice(NULL),
@@ -778,6 +781,16 @@ bool KX_KetsjiEngine::NextFrame()
return doRender && m_doRender;
}
void KX_KetsjiEngine::BindOffScreen(bool bind)
{
if (m_doOffScreen && m_offScreenRender)
{
if (bind)
m_offScreenRender->Bind(RAS_IOffScreen::RAS_OFS_BIND_READ);
else
m_offScreenRender->Unbind();
}
}
void KX_KetsjiEngine::Render()
@@ -797,9 +810,12 @@ void KX_KetsjiEngine::Render()
if (m_hideCursor)
m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
m_canvas->BeginDraw();
// redirect render if requested
if (m_doOffScreen && m_offScreenRender)
m_offScreenRender->Bind(RAS_IOffScreen::RAS_OFS_BIND_RENDER);
// clear the entire game screen with the border color
// only once per frame
m_canvas->BeginDraw();
if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
if (m_overrideFrameColor)
@@ -845,7 +861,10 @@ void KX_KetsjiEngine::Render()
//scene->UpdateMeshTransformations();
// shadow buffers
RenderShadowBuffers(scene);
if (RenderShadowBuffers(scene) && m_doOffScreen && m_offScreenRender)
// shadow render restore the frame buffer, must restore it if we have a customer render buffer
m_offScreenRender->Bind(RAS_IOffScreen::RAS_OFS_BIND_RENDER);
// Avoid drawing the scene with the active camera twice when its viewport is enabled
if (cam && !cam->GetViewport())
@@ -929,6 +948,8 @@ void KX_KetsjiEngine::Render()
PostRenderScene(scene);
}
} // if (m_rasterizer->Stereo())
if (m_doOffScreen && m_offScreenRender)
m_offScreenRender->Unbind();
EndFrame();
}
@@ -1085,10 +1106,11 @@ void KX_KetsjiEngine::UpdateAnimations(KX_Scene *scene)
scene->UpdateAnimations(m_frameTime);
}
void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
bool KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
{
CListValue *lightlist = scene->GetLightList();
int i, drawmode;
bool hasShadow = false;
m_rasterizer->SetAuxilaryClientInfo(scene);
@@ -1135,10 +1157,12 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
raslight->UnbindShadowBuffer();
m_rasterizer->SetDrawingMode(drawmode);
cam->Release();
hasShadow = true;
}
}
/* remember that we have a valid shadow buffer for that scene */
scene->SetShadowDone(true);
return hasShadow;
}
// update graphics
@@ -1335,6 +1359,11 @@ void KX_KetsjiEngine::StopEngine()
}
m_scenes.clear();
if (m_offScreenRender)
{
delete m_offScreenRender;
m_offScreenRender = NULL;
}
// cleanup all the stuff
m_rasterizer->Exit();
}
@@ -1941,6 +1970,17 @@ bool KX_KetsjiEngine::GetRender()
return m_doRender;
}
void KX_KetsjiEngine::SetOffScreen(bool offScreen)
{
m_doOffScreen = offScreen;
if (offScreen && !m_offScreenRender)
{
// offscreen render requested, create the offscreen render buffer
m_offScreenRender = m_rasterizer->CreateOffScreen(m_canvas->GetWidth(), m_canvas->GetHeight(), 0, RAS_IOffScreen::RAS_OFS_RENDER_BUFFER, RAS_IOffScreen::RAS_OFS_COLOR_FLOAT);
}
}
void KX_KetsjiEngine::SetShowFramerate(bool frameRate)
{
m_show_framerate = frameRate;

View File

@@ -74,6 +74,7 @@ class KX_KetsjiEngine
private:
class RAS_ICanvas* m_canvas; // 2D Canvas (2D Rendering Device Context)
class RAS_IRasterizer* m_rasterizer; // 3D Rasterizer (3D Rendering)
class RAS_IOffScreen* m_offScreenRender; // render in render buffer instead of frame buffer
class KX_ISystem* m_kxsystem;
class KX_ISceneConverter* m_sceneconverter;
class NG_NetworkDeviceInterface* m_networkdevice;
@@ -130,6 +131,7 @@ private:
static short m_exitkey; /* Key used to exit the BGE */
static bool m_doRender; /* whether or not the scene should be rendered after the logic frame */
static bool m_doOffScreen; /* whether normal render should be sent to an offscreen render buffer or to the frame buffer */
int m_exitcode;
STR_String m_exitstring;
@@ -252,7 +254,8 @@ public:
///returns true if an update happened to indicate -> Render
bool NextFrame();
void Render();
void RenderShadowBuffers(KX_Scene *scene);
bool RenderShadowBuffers(KX_Scene *scene);
void BindOffScreen(bool bind);
void StartEngine(bool clearIpo);
void StopEngine();
@@ -413,6 +416,11 @@ public:
* Get the current render flag value
*/
static bool GetRender();
/**
* Activate or deactivates the offscreen render of the scene after the logic frame
* \param offScreen true (render to offScreen) or false (render to frame buffer)
*/
void SetOffScreen(bool offScreen);
/**
* \Sets the display for frame rate on or off.

View File

@@ -484,6 +484,14 @@ static PyObject *gPyGetRender(PyObject *)
return PyBool_FromLong(KX_KetsjiEngine::GetRender());
}
static PyObject *gPySetOffScreen(PyObject *, PyObject *args)
{
int offScreen;
if (!PyArg_ParseTuple(args, "i:setOffScreen", &offScreen))
return NULL;
gp_KetsjiEngine->SetOffScreen(offScreen);
Py_RETURN_NONE;
}
static PyObject *gPySetMaxLogicFrame(PyObject *, PyObject *args)
{
@@ -897,6 +905,15 @@ static PyObject *gPyNextFrame(PyObject *)
}
}
static PyObject *gPyRender(PyObject *)
{
if (pynextframestate.render == NULL) Py_RETURN_NONE;
if (pynextframestate.state == NULL) Py_RETURN_NONE; //should never happen; raise exception instead?
pynextframestate.render(pynextframestate.state);
Py_RETURN_NONE;
}
static struct PyMethodDef game_methods[] = {
{"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, (const char *)gPyExpandPath_doc},
@@ -927,6 +944,7 @@ static struct PyMethodDef game_methods[] = {
{"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"},
{"setRender", (PyCFunction) gPySetRender, METH_VARARGS, (const char *)"Set the global render flag"},
{"getRender", (PyCFunction) gPyGetRender, METH_NOARGS, (const char *)"get the global render flag value"},
{"setOffScreen", (PyCFunction) gPySetOffScreen, METH_VARARGS, (const char *)"Set the global offscreen flag"},
{"getUseExternalClock", (PyCFunction) gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"},
{"setUseExternalClock", (PyCFunction) gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"},
{"getClockTime", (PyCFunction) gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. "
@@ -944,6 +962,7 @@ static struct PyMethodDef game_methods[] = {
{"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (const char *)"Prints GL Extension Info"},
{"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine statistics"},
{"NextFrame", (PyCFunction)gPyNextFrame, METH_NOARGS, (const char *)"Render next frame (if Python has control)"},
{"Render", (PyCFunction)gPyRender, METH_NOARGS, (const char *)"Do only render (skip logic), if Python has control"},
{"getProfileInfo", (PyCFunction)gPyGetProfileInfo, METH_NOARGS, gPyGetProfileInfo_doc},
/* library functions */
{"LibLoad", (PyCFunction)gLibLoad, METH_VARARGS|METH_KEYWORDS, (const char *)""},
@@ -1520,12 +1539,13 @@ static PyGetSetDef RASOffScreen_getseters[] = {
static int PyRASOffScreen__tp_init(PyRASOffScreen *self, PyObject *args, PyObject *kwargs)
{
int width, height, samples, target;
const char *keywords[] = {"width", "height", "samples", "target", NULL};
int width, height, samples, target, bits;
const char *keywords[] = {"width", "height", "samples", "target", "bits", NULL};
samples = 0;
target = RAS_IOffScreen::RAS_OFS_RENDER_BUFFER;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:RASOffscreen", (char **)keywords, &width, &height, &samples, &target)) {
bits = RAS_IOffScreen::RAS_OFS_COLOR_8BITS;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|iii:RASOffscreen", (char **)keywords, &width, &height, &samples, &target, &bits)) {
return -1;
}
@@ -1549,12 +1569,17 @@ static int PyRASOffScreen__tp_init(PyRASOffScreen *self, PyObject *args, PyObjec
PyErr_SetString(PyExc_ValueError, "invalid 'target' given, can only be RAS_OFS_RENDER_BUFFER or RAS_OFS_RENDER_TEXTURE");
return -1;
}
if (bits != RAS_IOffScreen::RAS_OFS_COLOR_8BITS && bits != RAS_IOffScreen::RAS_OFS_COLOR_FLOAT)
{
PyErr_SetString(PyExc_ValueError, "invalid 'bits' given, can only be RAS_OFS_COLOR_8BITS or RAS_OFS_COLOR_FLOAT");
return -1;
}
if (!gp_Rasterizer)
{
PyErr_SetString(PyExc_SystemError, "no rasterizer");
return -1;
}
self->ofs = gp_Rasterizer->CreateOffScreen(width, height, samples, target);
self->ofs = gp_Rasterizer->CreateOffScreen(width, height, samples, target, bits);
if (!self->ofs) {
PyErr_SetString(PyExc_SystemError, "creation failed");
return -1;
@@ -1619,9 +1644,10 @@ static PyObject *gPyOffScreenCreate(PyObject *UNUSED(self), PyObject *args)
int height;
int samples;
int target;
int bits
samples = 0;
if (!PyArg_ParseTuple(args, "ii|ii:offScreenCreate", &width, &height, &samples, &target))
if (!PyArg_ParseTuple(args, "ii|iii:offScreenCreate", &width, &height, &samples, &target, &bits))
return NULL;
return PyObject_CallObject((PyObject *) &PyRASOffScreen_Type, args);

View File

@@ -78,12 +78,15 @@ KX_Scene *KX_GetActiveScene();
KX_KetsjiEngine *KX_GetActiveEngine();
typedef int (*PyNextFrameFunc)(void *);
typedef void (*PyRenderFunc)(void *);
struct PyNextFrameState {
/** can be either a GPG_NextFrameState or a BL_KetsjiNextFrameState */
void *state;
/** can be either GPG_PyNextFrame or BL_KetsjiPyNextFrame */
PyNextFrameFunc func;
/** can be either GPG_PyRender or BL_KetsjiPyRender */
PyRenderFunc render;
};
extern struct PyNextFrameState pynextframestate;

View File

@@ -2152,9 +2152,9 @@ bool KX_Scene::MergeScene(KX_Scene *other)
return true;
}
void KX_Scene::Update2DFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text)
void KX_Scene::Update2DFilter(vector<STR_String>& propNames, void* gameObj, void *mat, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text)
{
m_filtermanager.EnableFilter(propNames, gameObj, filtermode, pass, text);
m_filtermanager.EnableFilter(propNames, gameObj, mat, filtermode, pass, text);
}
void KX_Scene::Render2DFilters(RAS_ICanvas* canvas)

View File

@@ -82,6 +82,7 @@ class RAS_MaterialBucket;
class RAS_IPolyMaterial;
class RAS_IRasterizer;
class RAS_IRenderTools;
class RAS_MeshObject;
class SCA_JoystickManager;
class btCollisionShape;
class KX_BlenderSceneConverter;
@@ -607,7 +608,7 @@ public:
/**
* 2D Filters
*/
void Update2DFilter(std::vector<STR_String>& propNames, void* gameObj, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text);
void Update2DFilter(std::vector<STR_String>& propNames, void* gameObj, void *mat, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text);
void Render2DFilters(RAS_ICanvas* canvas);
KX_ObstacleSimulation* GetObstacleSimulation() { return m_obstacleSimulation; }

View File

@@ -41,14 +41,27 @@
#include "RAS_ICanvas.h"
#include "RAS_Rect.h"
#include "RAS_2DFilterManager.h"
#include "RAS_MaterialBucket.h"
#include "BL_Material.h"
#include <iostream>
#include "DNA_image_types.h"
#include "DNA_meshdata_types.h"
#include "glew-mx.h"
#include <stdio.h>
#include "EXP_Value.h"
#define MAX_OBJ_TEXTURE 5
static const char *objTextureName[MAX_OBJ_TEXTURE] = {
"bgl_ObjectTexture0",
"bgl_ObjectTexture1",
"bgl_ObjectTexture2",
"bgl_ObjectTexture3",
"bgl_ObjectTexture4"
};
RAS_2DFilterManager::RAS_2DFilterManager():
texturewidth(-1), textureheight(-1),
/* numberoffilters(0), */ /* UNUSED */ need_tex_update(true)
@@ -67,6 +80,7 @@ texturewidth(-1), textureheight(-1),
m_enabled[passindex] = 0;
texflag[passindex] = 0;
m_gameObjects[passindex] = NULL;
m_blmat[passindex] = NULL;
}
texname[0] = texname[1] = texname[2] = -1;
errorprinted= false;
@@ -217,6 +231,19 @@ void RAS_2DFilterManager::AnalyseShader(int passindex, vector<STR_String>& propN
if (glGetUniformLocationARB(m_filters[passindex], propNames[i]) != -1)
m_properties[passindex].push_back(propNames[i]);
}
if (m_blmat[passindex])
{
BL_Material *mat = (BL_Material *)m_blmat[passindex];
m_textures[passindex].resize(MAX_OBJ_TEXTURE);
for (int i=0; i<MAX_OBJ_TEXTURE; i++)
{
m_textures[passindex][i] = NULL;
if (i < MAXTEX && glGetUniformLocationARB(m_filters[passindex], objTextureName[i]) != -1)
{
m_textures[passindex][i] = mat->img[i];
}
}
}
}
void RAS_2DFilterManager::StartShaderProgram(int passindex)
@@ -224,35 +251,35 @@ void RAS_2DFilterManager::StartShaderProgram(int passindex)
GLint uniformLoc;
glUseProgramObjectARB(m_filters[passindex]);
uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_RenderedTexture");
glActiveTextureARB(GL_TEXTURE0);
glActiveTextureARB(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, texname[0]);
if (uniformLoc != -1)
{
glUniform1iARB(uniformLoc, 0);
glUniform1iARB(uniformLoc, 5);
}
/* send depth texture to glsl program if it needs */
if (texflag[passindex] & 0x1) {
uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture");
glActiveTextureARB(GL_TEXTURE1);
glActiveTextureARB(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, texname[1]);
if (uniformLoc != -1)
{
glUniform1iARB(uniformLoc, 1);
glUniform1iARB(uniformLoc, 6);
}
}
/* send luminance texture to glsl program if it needs */
if (texflag[passindex] & 0x2) {
uniformLoc = glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture");
glActiveTextureARB(GL_TEXTURE2);
glActiveTextureARB(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, texname[2]);
if (uniformLoc != -1)
{
glUniform1iARB(uniformLoc, 2);
glUniform1iARB(uniformLoc, 7);
}
}
@@ -296,6 +323,23 @@ void RAS_2DFilterManager::StartShaderProgram(int passindex)
break;
}
}
int objTextures = m_textures[passindex].size();
for (i=0; i<objTextures; i++)
{
Image *img;
unsigned int bindcode;
if ((img = m_textures[passindex][i]) != NULL && (bindcode = img->bindcode[TEXTARGET_TEXTURE_2D]) != 0)
{
uniformLoc = glGetUniformLocationARB(m_filters[passindex], objTextureName[i]);
glActiveTextureARB(GL_TEXTURE0+i);
glBindTexture(GL_TEXTURE_2D, bindcode);
if (uniformLoc != -1)
{
glUniform1iARB(uniformLoc, i);
}
}
}
}
void RAS_2DFilterManager::EndShaderProgram()
@@ -315,6 +359,7 @@ void RAS_2DFilterManager::FreeTextures()
void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance)
{
GLenum error;
FreeTextures();
glGenTextures(1, (GLuint*)&texname[0]);
@@ -354,8 +399,8 @@ void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance)
void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas)
{
/* RAS_Rect canvas_rect = canvas->GetWindowArea(); */ /* UNUSED */
texturewidth = canvas->GetWidth()+1;
textureheight = canvas->GetHeight()+1;
texturewidth = canvas->GetWidth();
textureheight = canvas->GetHeight();
GLint i,j;
if (!GL_ARB_texture_non_power_of_two)
@@ -443,13 +488,13 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
}
if (need_depth) {
glActiveTextureARB(GL_TEXTURE1);
glActiveTextureARB(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, texname[1]);
glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, viewport[0], viewport[1], viewport[2], viewport[3], 0);
}
if (need_luminance) {
glActiveTextureARB(GL_TEXTURE2);
glActiveTextureARB(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, texname[2]);
glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, viewport[0], viewport[1], viewport[2], viewport[3], 0);
}
@@ -463,8 +508,8 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
glScissor(scissor_rect.GetLeft() + viewport[0],
scissor_rect.GetBottom() + viewport[1],
scissor_rect.GetWidth() + 1,
scissor_rect.GetHeight() + 1);
scissor_rect.GetWidth(),
scissor_rect.GetHeight());
glDisable(GL_DEPTH_TEST);
// in case the previous material was wire
@@ -488,9 +533,9 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
{
StartShaderProgram(passindex);
glActiveTextureARB(GL_TEXTURE0);
glActiveTextureARB(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, texname[0]);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, viewport[0], viewport[1], viewport[2], viewport[3], 0); // Don't use texturewidth and textureheight in case we don't have NPOT support
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, viewport[0], viewport[1], viewport[2], viewport[3], 0); // Don't use texturewidth and textureheight in case we don't have NPOT support
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS);
@@ -502,6 +547,7 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
glEnd();
}
}
glActiveTextureARB(GL_TEXTURE0);
glEnable(GL_DEPTH_TEST);
EndShaderProgram();
@@ -510,7 +556,7 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
glPopMatrix();
}
void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text)
void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* gameObj, void *mat, RAS_2DFILTER_MODE mode, int pass, STR_String& text)
{
if (!isshadersupported)
return;
@@ -536,7 +582,9 @@ void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* game
m_enabled[pass] = 0;
m_filters[pass] = 0;
m_gameObjects[pass] = NULL;
m_blmat[pass] = NULL;
m_properties[pass].clear();
m_textures[pass].clear();
texflag[pass] = 0;
return;
}
@@ -547,6 +595,7 @@ void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* game
glDeleteObjectARB(m_filters[pass]);
m_filters[pass] = CreateShaderProgram(text.Ptr());
m_gameObjects[pass] = gameObj;
m_blmat[pass] = mat;
AnalyseShader(pass, propNames);
m_enabled[pass] = 1;
return;
@@ -557,6 +606,7 @@ void RAS_2DFilterManager::EnableFilter(vector<STR_String>& propNames, void* game
glDeleteObjectARB(m_filters[pass]);
m_filters[pass] = CreateShaderProgram(mode);
m_gameObjects[pass] = NULL;
m_blmat[pass] = NULL;
AnalyseShader(pass, propNames);
m_enabled[pass] = 1;
}

View File

@@ -39,6 +39,7 @@
#endif
class RAS_ICanvas;
struct Image;
class RAS_2DFilterManager
{
@@ -78,6 +79,10 @@ private:
// stores object properties to send to shaders in each pass
std::vector<STR_String> m_properties[MAX_RENDER_PASS];
void* m_gameObjects[MAX_RENDER_PASS];
void *m_blmat[MAX_RENDER_PASS];
// stores the additional textures that should be mapped during render pass to GL_TEXTURE3..7
std::vector<struct Image *> m_textures[MAX_RENDER_PASS];
public:
enum RAS_2DFILTER_MODE {
RAS_2DFILTER_ENABLED = -2,
@@ -104,7 +109,7 @@ public:
void RenderFilters(RAS_ICanvas* canvas);
void EnableFilter(std::vector<STR_String>& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text);
void EnableFilter(std::vector<STR_String>& propNames, void* gameObj, void *mat, RAS_2DFILTER_MODE mode, int pass, STR_String& text);
#ifdef WITH_CXX_GUARDEDALLOC

View File

@@ -51,6 +51,10 @@ public:
RAS_OFS_RENDER_BUFFER = 0, // use render buffer as render target
RAS_OFS_RENDER_TEXTURE, // use texture as render target
};
enum RAS_OFS_COLOR_BITS {
RAS_OFS_COLOR_8BITS = 0, // color buffer will be 8bits unsigned per color
RAS_OFS_COLOR_FLOAT, // color buffer will be 32bits float per color (if OpenGL supports it)
};
int m_width;
int m_height;
@@ -59,7 +63,7 @@ public:
virtual ~RAS_IOffScreen() {}
virtual bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target) = 0;
virtual bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target, RAS_OFS_COLOR_BITS bits) = 0;
virtual void Destroy() = 0;
virtual void Bind(RAS_OFS_BIND_MODE mode) = 0;
virtual void Blit() = 0;

View File

@@ -263,7 +263,7 @@ public:
* Create an offscreen render buffer that can be used as target for render.
* For the time being, it is only used in VideoTexture for custom render.
*/
virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target) = 0;
virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target, int bits) = 0;
/**
* Create a sync object

View File

@@ -47,7 +47,7 @@ RAS_OpenGLOffScreen::~RAS_OpenGLOffScreen()
Destroy();
}
bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target)
bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target, RAS_OFS_COLOR_BITS bits)
{
GLenum status;
GLuint glo[2], fbo;
@@ -111,7 +111,10 @@ bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_REN
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_depthtx);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT, width, height, true);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_colortx);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, true);
if (bits == RAS_OFS_COLOR_FLOAT && GLEW_ARB_texture_float)
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, true);
else
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA32F, width, height, true);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -123,7 +126,10 @@ bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_REN
glBindTexture(GL_TEXTURE_2D, m_depthtx);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, m_colortx);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if (bits == RAS_OFS_COLOR_FLOAT && GLEW_ARB_texture_float)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
@@ -141,7 +147,10 @@ bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_REN
glBindRenderbufferEXT(GL_RENDERBUFFER, m_depthrb);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER, m_colorrb);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_RGBA8, width, height);
if (bits == RAS_OFS_COLOR_FLOAT && GLEW_ARB_texture_float)
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_RGBA32F, width, height);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_RGBA8, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
@@ -180,7 +189,10 @@ bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_REN
// m_color is the texture where the final render goes, the blit texture in this case
m_color = m_blittex = blit_tex;
glBindTexture(GL_TEXTURE_2D, m_blittex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if (bits == RAS_OFS_COLOR_FLOAT && GLEW_ARB_texture_float)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -198,7 +210,10 @@ bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_REN
}
m_blitrbo = blit_tex;
glBindRenderbufferEXT(GL_RENDERBUFFER, m_blitrbo);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 0, GL_RGBA8, width, height);
if (bits == RAS_OFS_COLOR_FLOAT && GLEW_ARB_texture_float)
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 0, GL_RGBA32F, width, height);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 0, GL_RGBA8, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo);
glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_blitrbo);

View File

@@ -53,7 +53,7 @@ public:
RAS_OpenGLOffScreen(RAS_ICanvas *canvas);
~RAS_OpenGLOffScreen();
bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target);
bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target, RAS_OFS_COLOR_BITS bits);
void Destroy();
void Bind(RAS_OFS_BIND_MODE mode);
void Blit();

View File

@@ -601,13 +601,13 @@ float RAS_OpenGLRasterizer::GetFocalLength()
return m_focallength;
}
RAS_IOffScreen *RAS_OpenGLRasterizer::CreateOffScreen(int width, int height, int samples, int target)
RAS_IOffScreen *RAS_OpenGLRasterizer::CreateOffScreen(int width, int height, int samples, int target, int bits)
{
RAS_IOffScreen *ofs;
ofs = new RAS_OpenGLOffScreen(m_2DCanvas);
if (!ofs->Create(width, height, samples, (RAS_IOffScreen::RAS_OFS_RENDER_TARGET)target)) {
if (!ofs->Create(width, height, samples, (RAS_IOffScreen::RAS_OFS_RENDER_TARGET)target, (RAS_IOffScreen::RAS_OFS_COLOR_BITS)bits)) {
delete ofs;
return NULL;
}

View File

@@ -181,7 +181,7 @@ public:
virtual float GetEyeSeparation();
virtual void SetFocalLength(const float focallength);
virtual float GetFocalLength();
virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target);
virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target, int bits);
virtual RAS_ISync *CreateSync(int type);
virtual void SwapBuffers();

View File

@@ -118,6 +118,26 @@ unsigned int * ImageBase::getImage (unsigned int texId, double ts)
return m_avail ? m_image : NULL;
}
unsigned int ImageBase::getPixelSize(unsigned int format)
{
switch (format)
{
case GL_RGBA:
case GL_BGRA:
case GL_DEPTH_COMPONENT32F:
return 4;
case GL_RGBA32F:
return 4*4;
case GL_RGB32F:
return 3*4;
case GL_RG32F:
return 2*4;
default:
return 0;
}
}
bool ImageBase::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts)
{
unsigned int *d, *s, v, len;
@@ -564,6 +584,14 @@ PyObject *Image_refresh (PyImage *self, PyObject *args)
format = GL_RGBA;
else if (!strcmp(mode, "BGRA"))
format = GL_BGRA;
else if (!strcmp(mode, "DEPTH"))
format = GL_DEPTH_COMPONENT32F;
else if (!strcmp(mode, "RGBA32F"))
format = GL_RGBA32F;
else if (!strcmp(mode, "RGB32F"))
format = GL_RGB32F;
else if (!strcmp(mode, "RG32F"))
format = GL_RG32F;
else
THRWEXCP(InvalidImageMode,S_OK);

View File

@@ -70,8 +70,9 @@ public:
/// get image size
short * getSize(void) { return m_size; }
/// get image buffer size
unsigned long getBuffSize(void)
unsigned long getBuffSize()
{ return m_size[0] * m_size[1] * sizeof(unsigned int); }
unsigned int getPixelSize(unsigned int format);
/// refresh image - invalidate its current content
virtual void refresh(void);

View File

@@ -134,7 +134,7 @@ void ImageRender::setBackgroundFromScene (KX_Scene *scene)
// capture image from viewport
void ImageRender::calcViewport (unsigned int texId, double ts, unsigned int format)
void ImageRender::calcImage (unsigned int texId, double ts)
{
// render the scene from the camera
if (!m_done) {
@@ -148,12 +148,34 @@ void ImageRender::calcViewport (unsigned int texId, double ts, unsigned int form
// wait until all render operations are completed
WaitSync();
// get image from viewport (or FBO)
ImageViewport::calcViewport(texId, ts, format);
calcViewport(texId, ts);
if (m_offscreen) {
m_offscreen->ofs->Unbind();
}
}
bool ImageRender::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts)
{
bool ret;
// render the scene from the camera
if (!m_done) {
if (!Render()) {
return false;
}
}
else if (m_offscreen) {
m_offscreen->ofs->Bind(RAS_IOffScreen::RAS_OFS_BIND_READ);
}
// wait until all render operations are completed
WaitSync();
// get image from viewport (or FBO)
ret = loadRender(buffer, size, format);
if (m_offscreen) {
m_offscreen->ofs->Unbind();
}
return ret;
}
bool ImageRender::Render()
{
RAS_FrameFrustum frustum;
@@ -246,7 +268,7 @@ bool ImageRender::Render()
m_canvas->UpdateViewPort(0, 0, m_offscreen->ofs->GetWidth(), m_offscreen->ofs->GetHeight());
}
else {
m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1);
m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0], m_position[1]+m_capSize[1]);
}
m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]);
m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);

View File

@@ -73,6 +73,8 @@ public:
void Unbind();
/// wait for render to complete
void WaitSync();
/// load render buffer directly into user image
virtual bool loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts);
protected:
/// true if ready to render
@@ -111,10 +113,7 @@ protected:
/// render 3d scene to image
virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); }
/// render 3d scene to image
virtual void calcViewport (unsigned int texId, double ts, unsigned int format);
virtual void calcImage (unsigned int texId, double ts);
void setBackgroundFromScene(KX_Scene *scene);
void SetWorldSettings(KX_WorldInfo* wi);

View File

@@ -132,9 +132,15 @@ void ImageViewport::setPosition (GLint pos[2])
m_upLeft[idx] = m_position[idx] + m_viewport[idx];
}
void ImageViewport::calcImage (unsigned int texId, double ts)
{
KX_GetActiveEngine()->BindOffScreen(true);
calcViewport(texId, ts);
KX_GetActiveEngine()->BindOffScreen(false);
}
// capture image from viewport
void ImageViewport::calcViewport (unsigned int texId, double ts, unsigned int format)
void ImageViewport::calcViewport (unsigned int texId, double ts)
{
// if scale was changed
if (m_scaleChange)
@@ -192,12 +198,12 @@ void ImageViewport::calcViewport (unsigned int texId, double ts, unsigned int fo
!m_flip &&
!m_pyfilter)
{
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format,
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA,
GL_UNSIGNED_BYTE, m_image);
m_avail = true;
}
else if (!m_pyfilter) {
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], format,
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1], GL_RGBA,
GL_UNSIGNED_BYTE, m_viewportImage);
FilterRGBA32 filt;
filterImage(filt, m_viewportImage, m_capSize);
@@ -207,10 +213,6 @@ void ImageViewport::calcViewport (unsigned int texId, double ts, unsigned int fo
GL_UNSIGNED_BYTE, m_viewportImage);
FilterRGBA32 filt;
filterImage(filt, m_viewportImage, m_capSize);
if (format == GL_BGRA) {
// in place byte swapping
swapImageBR();
}
}
}
else {
@@ -219,10 +221,6 @@ void ImageViewport::calcViewport (unsigned int texId, double ts, unsigned int fo
// filter loaded data
FilterRGB24 filt;
filterImage(filt, m_viewportImage, m_capSize);
if (format == GL_BGRA) {
// in place byte swapping
swapImageBR();
}
}
}
}
@@ -231,35 +229,55 @@ void ImageViewport::calcViewport (unsigned int texId, double ts, unsigned int fo
bool ImageViewport::loadImage(unsigned int *buffer, unsigned int size, unsigned int format, double ts)
{
unsigned int *tmp_image;
bool ret;
// if scale was changed
if (m_scaleChange) {
// reset image
init(m_capSize[0], m_capSize[1]);
}
// size must be identical
if (size < getBuffSize())
return false;
if (m_avail) {
// just copy
return ImageBase::loadImage(buffer, size, format, ts);
}
else {
tmp_image = m_image;
m_image = buffer;
calcViewport(0, ts, format);
ret = m_avail;
m_image = tmp_image;
// since the image was not loaded to our buffer, it's not valid
m_avail = false;
}
KX_GetActiveEngine()->BindOffScreen(true);
ret = loadRender(buffer, size, format);
KX_GetActiveEngine()->BindOffScreen(false);
return ret;
}
bool ImageViewport::loadRender(unsigned int *buffer, unsigned int size, unsigned int format)
{
unsigned int renderSize;
renderSize = getPixelSize(format)*m_capSize[0]*m_capSize[1];
if (renderSize == 0)
return false;
// size must be identical
if (size < renderSize)
return false;
switch (format) {
case GL_DEPTH_COMPONENT32F:
// Use read pixels with the depth buffer
// See warning above about m_viewportImage.
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
GL_DEPTH_COMPONENT, GL_FLOAT, buffer);
break;
case GL_RGBA:
case GL_BGRA:
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
format, GL_UNSIGNED_BYTE, buffer);
break;
case GL_RGBA32F:
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
GL_RGBA, GL_FLOAT, buffer);
break;
case GL_RGB32F:
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
GL_RGB, GL_FLOAT, buffer);
break;
case GL_RG32F:
glReadPixels(m_upLeft[0], m_upLeft[1], (GLsizei)m_capSize[0], (GLsizei)m_capSize[1],
GL_RG, GL_FLOAT, buffer);
break;
default:
return false;
}
return true;
}
// cast Image pointer to ImageViewport
inline ImageViewport * getImageViewport (PyImage *self)

View File

@@ -93,10 +93,13 @@ protected:
bool m_texInit;
/// capture image from viewport
virtual void calcImage (unsigned int texId, double ts) { calcViewport(texId, ts, GL_RGBA); }
virtual void calcImage (unsigned int texId, double ts);
/// capture image from viewport
virtual void calcViewport (unsigned int texId, double ts, unsigned int format);
virtual void calcViewport (unsigned int texId, double ts);
/// read render buffer to user buffer
virtual bool loadRender(unsigned int *buffer, unsigned int size, unsigned int format);
/// get viewport size
GLint * getViewportSize (void) { return m_viewport + 2; }