Manipulating GBitmap's Pixels?
by Paul Griffiths · in Torque Game Engine · 05/31/2006 (10:13 pm) · 18 replies
I'm building a web-cam capture add on to torque which i have images saved to files working. Now i wish to render the image to a GUI control i have ready.
Question is, how do you set a GBitmap's pixel color?
Ive copied the Theora GUI control and riped out the Theora library and put in vidCapture library instead.
My question is in the code below.
Thanks for your time.
Question is, how do you set a GBitmap's pixel color?
Ive copied the Theora GUI control and riped out the Theora library and put in vidCapture library instead.
My question is in the code below.
void VideoCaptureTexture::drawFrame()
{
GBitmap *bmp = mTextureHandle->getBitmap();
U8* dst = bmp->getAddress(0, 0);
for(S32 y = 0; y < bmp->getHeight(); y += 1)
{
for(S32 x = 0; x < bmp->getWidth(); x += 1)
{
// how do i set it's pixel color here? to say red?
}
}
}Thanks for your time.
#2
06/01/2006 (12:42 am)
Yes, thanks martin, i didnt know it was that simple, should be a breeze! i hope :)
#3
06/01/2006 (12:43 am)
Question though, how does dst increase?
#4
C:\Torque\SDK\engine\TMessenger\videoCapturePlayer.cc(101): error C2227: left of '->setColor' must point to class/struct/union
any ideas?
06/01/2006 (12:47 am)
Im receiving an error:C:\Torque\SDK\engine\TMessenger\videoCapturePlayer.cc(101): error C2227: left of '->setColor' must point to class/struct/union
any ideas?
#5
06/01/2006 (12:56 am)
Ups, sorry, used the wrong variable. it should be [b]bmp[/b]->setColor(x,y, col);
#6
to get a pointer through which you can manipulate the bmp data, rather than doing everything through the setColor function
06/01/2006 (12:58 am)
I imagine you'd be better off using U8 *pBmp = bmp->getWritableBits(0);
to get a pointer through which you can manipulate the bmp data, rather than doing everything through the setColor function
#7
06/01/2006 (1:02 am)
Sam, can you complete my example?
#8
06/01/2006 (1:11 am)
void VideoCaptureTexture::drawFrame()
{
GBitmap *bmp = mTextureHandle->getBitmap();
U8 *pBmp = bmp->getWritableBits(0);
U8 *pxLoc;
U32 w = bmp->getWidth(0);
U32 h = bmp->getHeight(0);
bool hasAlpha = (bmp->bytesPerPixel == 4);
for (U32 x=0; x<w; xx++)
{
for (U32 y=0; y<h; yy++)
{
pxLoc = pBmp+(((y * w) + x) * bmp->bytesPerPixel);
pxLoc[0] = 255; // red
pxLoc[1] = 0; // green
pxLoc[2] = 0; // blue
if (hasAlpha)
pxLoc[3] = 255; // alpha
}
}
}
#9
06/01/2006 (1:19 am)
All i'm getting is white, the same as before i changed the pixels. Can anyone see anything im missing?//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "videoCapturePlayer.h"
#include "math/mMath.h"
#include "util/safeDelete.h"
//-----------------------------------------------------------------------------
VideoCaptureTexture::VideoCaptureTexture()
{
init();
}
void VideoCaptureTexture::init()
{
mReady = false;
mPlaying = false;
mPlayThread = NULL;
mTextureHandle = NULL;
}
VideoCaptureTexture::~VideoCaptureTexture()
{
destroyTexture();
}
// tears down anything the texture has
void VideoCaptureTexture::destroyTexture(bool restartOgg)
{
mPlaying = false;
// kill the thread if its playing
SAFE_DELETE(mPlayThread);
// Set us to a null state.
mReady = false;
SAFE_DELETE(mTextureHandle);
}
bool VideoCaptureTexture::createVideoBuffers()
{
// Set up our texture.
const GBitmap *bmp = new GBitmap(
320,
240,
false, GBitmap::RGB);
mTextureHandle = new TextureHandle(NULL, bmp, true);
return true;
}
void VideoCaptureTexture::drawFrame()
{
// get destination buffer (and 1 row offset)
GBitmap *bmp = mTextureHandle->getBitmap();
Con::printf("Drawing to bmp width:" + bmp->getWidth());
for(S32 y = 0; y < bmp->getHeight(); y += 1)
{
for(S32 x = 0; x < bmp->getWidth(); x += 1)
{
ColorI col(0,255,0,0); // R G B A
bmp->setColor(x,y, col);
//Con::printf("setting pixel");
}
}
}
bool VideoCaptureTexture::play()
{
mReady = true;
if(!mPlaying)
mPlayThread = new Thread((ThreadRunFunction)playThread, (S32) this, 1);
return mPlayThread;
}
void VideoCaptureTexture::stop()
{
mPlaying = false;
if(mPlayThread)
{
SAFE_DELETE(mPlayThread);
}
}
void VideoCaptureTexture::playThread( void *udata )
{
VideoCaptureTexture* pThis = (VideoCaptureTexture *)udata;
pThis->playLoop();
}
bool VideoCaptureTexture::playLoop()
{
createVideoBuffers();
mPlaying = true;
Con::printf("######################## Start of loop ###########################");
// time to draw the frame!
drawFrame();
refresh();
return false;
}
// returns a handle for OpenGL calls
U32 VideoCaptureTexture::getGLName()
{
if(mTextureHandle)
{
mTextureHandle->refresh();
return mTextureHandle->getGLName();
}
return 0;
}
// copies the newest texture data to openGL video memory
void VideoCaptureTexture::refresh()
{
if(mTextureHandle)
mTextureHandle->refresh();
}
#10
Heres also my gui control:
06/01/2006 (1:44 am)
Sam even with your example itonly renders white.Heres also my gui control:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "gui/core/guiControl.h"
#include "guiVideoCaptureCtrl.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
//----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiVideoCaptureCtrl);
GuiVideoCaptureCtrl::GuiVideoCaptureCtrl()
{
mFilename = StringTable->insert("");
mDone = false;
mStopOnSleep = false;
mBackgroundColor.set(0,0,0);
}
//----------------------------------------------------------------------------
GuiVideoCaptureCtrl::~GuiVideoCaptureCtrl()
{
}
void GuiVideoCaptureCtrl::initPersistFields()
{
Parent::initPersistFields();
addGroup("Playback");
addField("videoCaptureFile", TypeFilename, Offset(mFilename, GuiVideoCaptureCtrl));
addField("done", TypeBool, Offset(mDone, GuiVideoCaptureCtrl));
addField("stopOnSleep", TypeBool, Offset(mStopOnSleep, GuiVideoCaptureCtrl));
addField("backgroundColor", TypeColorI,Offset(mBackgroundColor, GuiVideoCaptureCtrl));
endGroup("Playback");
}
ConsoleMethod( GuiVideoCaptureCtrl, setFile, void, 3, 3, "(string filename) Set an Ogg VideoCapture file to play.")
{
object->setFile(argv[2]);
}
ConsoleMethod( GuiVideoCaptureCtrl, stop, void, 2, 2, "() Stop playback.")
{
object->stop();
}
ConsoleMethod( GuiVideoCaptureCtrl, getCurrentTime, F32, 2, 2, "() Return the time elapsed in playback, in seconds.")
{
return object->getCurrentTime();
}
ConsoleMethod( GuiVideoCaptureCtrl, initializeVideoCamera, void, 0, 0, "Initialize camera.")
{
object->initializeVideoCamera();
}
void GuiVideoCaptureCtrl::initializeVideoCamera()
{
Con::printf("Initializing GUI video capture object.\n");
mVideoCaptureTexture.play();
}
void GuiVideoCaptureCtrl::setFile(const char* szFilename)
{
mDone = false;
//if(szFilename && szFilename[0])
// mVideoCaptureTexture.setFile(szFilename, true);
}
void GuiVideoCaptureCtrl::stop()
{
mVideoCaptureTexture.stop();
mDone = true;
}
//----------------------------------------------------------------------------
bool GuiVideoCaptureCtrl::onWake()
{
if (!Parent::onWake()) return false;
if(mVideoCaptureTexture.isReady())
return true;
setFile(mFilename);
return true;
}
//----------------------------------------------------------------------------
void GuiVideoCaptureCtrl::onSleep()
{
Parent::onSleep();
if(mStopOnSleep)
stop();
}
//----------------------------------------------------------------------------
void GuiVideoCaptureCtrl::onRender(Point2I offset, const RectI &updateRect)
{
const RectI rect(offset, mBounds.extent);
if(mVideoCaptureTexture.isReady() && mVideoCaptureTexture.isPlaying())
{
mVideoCaptureTexture.refresh();
dglDrawRectFill(rect, mBackgroundColor); // black rect
dglClearBitmapModulation();
dglDrawBitmapStretch(mVideoCaptureTexture, rect);
}
else
{
if(mVideoCaptureTexture.isReady())
mDone = true;
dglDrawRectFill(rect, mBackgroundColor); // black rect
}
dglDrawRect(rect, mBackgroundColor);
renderChildControls(offset, updateRect);
}
//----------------------------------------------------------------------------
void GuiVideoCaptureCtrl::inspectPostApply()
{
stop();
setFile(mFilename);
}
#11
Have you checked that mTextureHandle->refresh() works properly?
What I have been using is TextureManager::registerTexture to re-register the texture after it has changed.
Here's one of the variations I have used, in this case replacing an in-game texture (texturefilename) with another one (pixels) copied from another window's canvas using a Windows API call, and therefore in Windows-format BMP*:
The texture has to be registered as a BitmapKeepTexture, otherwise it's deleted from the engine after it has been sent to the graphics card.
* Windows BMPs have flipped y axes and also reversed RGB packing
06/01/2006 (2:03 am)
Hmm... this approach has worked for me in getting real-time screen-captured bitmaps onto a Torque texture, and also for blending textures. Have you checked that mTextureHandle->refresh() works properly?
What I have been using is TextureManager::registerTexture to re-register the texture after it has changed.
Here's one of the variations I have used, in this case replacing an in-game texture (texturefilename) with another one (pixels) copied from another window's canvas using a Windows API call, and therefore in Windows-format BMP*:
The texture has to be registered as a BitmapKeepTexture, otherwise it's deleted from the engine after it has been sent to the graphics card.
bool replaceTexture(const char* texturefilename, U8* pixels, int w, int h)
{
texturefilename = StringTable->insert(texturefilename);
TextureObject* t = TextureDictionary::find(texturefilename, BitmapKeepTexture, 1);
GBitmap* bmp;
int x, y;
if (t)
{ // bitmap is already in memory, probably modified already since being loaded
bmp = t->bitmap;
}
else // this is the 1st time this texture is being modified => reload image from disk
{
t = TextureDictionary::find(texturefilename);
if (!t)
return false; // cannot find texture
bmp = TextureManager::loadBitmapInstance(texturefilename);
t->type=BitmapKeepTexture;
}
U8 *pBmpLoc0 = bmp->getWritableBits(0);
U8 *pLoc, *pBmpLoc;
int bytesperpixel = bmp->bytesPerPixel;
for (x=0; x<w; x++)
{
for (y=0; y<h; y++)
{
pLoc = pixels+(((x) + ((h-1-y)*w))*4); // pixel in windows BMP (flipped y axis)
pBmpLoc = pBmpLoc0+((y*w)+x)*bytesperpixel; // pixel in texture
pBmpLoc[0]=pLoc[2]; // r
pBmpLoc[1]=pLoc[1]; // g
pBmpLoc[2]=pLoc[0]; // b
}
}
t->bitmap=bmp;
TextureManager::registerTexture(texturefilename, bmp, BitmapKeepTexture, 1);
return (!(t==NULL));
}* Windows BMPs have flipped y axes and also reversed RGB packing
#12
hard to tell, I included a Con::printf in the refresh function and it gets called.
06/01/2006 (2:16 am)
>Have you checked that mTextureHandle->refresh() works properly?hard to tell, I included a Con::printf in the refresh function and it gets called.
#13
06/01/2006 (2:19 am)
I really want to avoid manipulating an existing texture as different cameras capture at different resolutions.
#14
Nowhere in the theora code is there TextureManager::registerTexture so im guessing should not be needed in my case?
06/01/2006 (2:39 am)
The bmap is not being deleted as i can get it's width/height at any time.Nowhere in the theora code is there TextureManager::registerTexture so im guessing should not be needed in my case?
#15
06/01/2006 (4:32 am)
Any ideas anyone? im completly stuck.
#16
The theora plugin creates it's own so so should i should be able to too.
I'm looking for a pro to answer my question dated Jun 01, 2006 09:19.
I can't see anything im missing? It compiles fine and does not crash but my gui just turns white after i call GuiVideoCaptureCtrl::initializeVideoCamera().
I hope to release my code as a new resource but i just need this part answered.
06/01/2006 (9:26 pm)
Can you create a new texture resource and not manipulate an existing one?The theora plugin creates it's own so so should i should be able to too.
I'm looking for a pro to answer my question dated Jun 01, 2006 09:19.
I can't see anything im missing? It compiles fine and does not crash but my gui just turns white after i call GuiVideoCaptureCtrl::initializeVideoCamera().
I hope to release my code as a new resource but i just need this part answered.
#17
06/04/2006 (1:44 pm)
I have Webcam Capture to Torque GUI working nicely, screenshot here: pgmedia.game-host.org/Site/TMessenger/screenshot.php
#18
11/12/2009 (5:06 pm)
@Paul, how did you end up copying the CVImage to a bitmap?
Torque Owner Martin Schultz
for(S32 y = 0; y < bmp->getHeight(); y += 1) { for(S32 x = 0; x < bmp->getWidth(); x += 1) { // how do i set it's pixel color here? to say red? ColorI col(255,0,0,0); // R G B A dst->setColor(x,y, col); } }Alternatively you could set manually the color components for "col" like this:
col.red = 255; // red value
col.green = 255; // green
col.blue = 255; //blue
Does this help?
Martin