• Advertisement

Archived

This topic is now archived and is closed to further replies.

Please tell me Direct3D has a function to do this

This topic is 5634 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I need a way to scale an image from let's say a 200x200 surface to a 256x256 texture. I know I can load an image (.bmp, .dds, .dib, .jpg, .png, and .tga) from a file of any dimension and Direct3D will automatically scale and convert the format with the D3DXCreateTextureFromFile method. But what I need is to do this on a pcx image file that I've loaded into memory and copied into a blank texture. Right now the texture is all messed up unless It's of a dimension of something like 256, 512, ect. Because this is a hardware issue, I need a way to scale my image in memory to these dimensions. I thought maybe the D3DXCreateTextureFromFileInMemory function could do it, but after looking at the docs, it to only supports the file formats I listed above. And I have to scale many pcx textures to those dimensions, which would take to long to convert them in a program like photoshop. After searching this forum, I found what appears to be an OpenGL function that can do it (gluScaleImage). So please tell me that there's an equivalent Direct3D function? [edited by - MagTDK on May 30, 2002 2:02:12 PM]

Share this post


Link to post
Share on other sites
Advertisement
why not just have your textures at 256x256? scaling at runtime is silly since you will introduce scaling artifacts into the texture. though since your already using improper images, that wont matter much.

psp support batch processing, and pretty sure it can allow you to scale all the images in a directory (though why your art was not created at the proper size in the first place seems odd). if all else fails, write your own app to scale all the images in a directory or using a text file listing all the files.

why are you using pcx? why not a more common format like bmp or png? pcx dies with dos i am afraid (though some ppl still use them, they are pretty useless for 3d apps when pngs are supported nativly by d3d8).

writing your own scaling funtion wont be too tough, do some research on software bilinear resampling. or you could just access the texture using a max uv of 200.0/256.0,200.0/256.0 and ignore resizing the image. though if your tiling the texture this wont be nice looking to do blending artifacts at the edges.

Share this post


Link to post
Share on other sites
You should be able to copy the 200x200 image into the 256x256 texture without a problem. If you do that, you can map the texture using 200/256 as your max u and v (assuming you aren''t tiling). (Oops - sorry, I guess a person just said that...)

If you are tiling, or if you need a "full" texture for some other reason, you might want to take a look at scripting photoshop. Unless you are talking about huge numbers of images, batch processing shouldn''t take too long. You get the advantage of using Photoshop''s filtering instead of writing your own.

Share this post


Link to post
Share on other sites

The problem is, as I''ve mentioned before, I''m loading textures from the quake 2 game. There using the pcx format for there models and what appears to be there own format (.wal) for the world textures. And both formats are of odd sizes.

I found this code at: http://polygone.flipcode.com/download.htm

It''s a QMDLViewer v1.0 that loads the pcx format. Because he''s using DirectX 7, it looks like he was using the DD interface to stretch the image. But because I''m not very fluent in DD, I''m not that sure. Perhaps someone with DD experience can tell. Here is the function I believe he is stretching the image to the power of 2:


  
void convert_pcx()
{
DDSURFACEDESC2 ddsd, ddsd2;
int i,j;
float xstep, ystep, xt, yt, x1,y1;
int x,y;
RECT rect;
FILE *klutt;

if(pcx_width > 256) //Always scale up

scale_width = 512;
else if(pcx_width > 128)
scale_width = 256;
else if(pcx_width > 64)
scale_width = 128;
else if(pcx_width > 32)
scale_width = 64;

if(pcx_height > 256)
scale_height = 512;
else if(pcx_height > 128)
scale_height = 256;
else if(pcx_height > 64)
scale_height = 128;
else if(pcx_height > 32)
scale_height = 64;

ZeroMemory(&ddsd, sizeof(ddsd) );
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
ddsd.dwWidth = scale_width;
ddsd.dwHeight = scale_height;

lpDDraw->CreateSurface(&ddsd,&textsurf,NULL);

SetRect(&rect, 0, 0, scale_width, scale_height);
memset(&ddsd,0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
textsurf->Lock(&rect,&ddsd,DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);
double_buf = (WORD *)ddsd.lpSurface;

(float)xstep = (float)pcx_width / (float)scale_width;
(float)ystep = (float)pcx_height / (float)scale_height;
xt = 0.0; yt = 0.0; x1 = 0.0f; y1 = 0.0f;
x = 0; y = 0;
for (j = 0; j < scale_height; j++) {
(float)y1 += (float)ystep;
(float)yt = (float)y1;
(int)y = yt; if(y > pcx_height) y = pcx_height;
for (i = 0; i < scale_width; i++) {
(float)x1 += (float)xstep;
(float)xt = (float)x1;
(int)x = (float)xt; if(x > pcx_width) x = pcx_width;

double_buf[(j * scale_width + i)] = RGB16(((long)pcx_pal_buffer[3 * pcx_buffer[ ( y * pcx_width ) + x ]+0 ] / 8),
((long)pcx_pal_buffer[3 * pcx_buffer[ ( y * pcx_width ) + x ]+1 ] / 8),
((long)pcx_pal_buffer[3 * pcx_buffer[ ( y * pcx_width ) + x ]+2 ] / 8));



}
x = 0; x1 = 0.0;
}

for(i = (scale_width * scale_height) - ((float)scale_width * 1 + 34); i < (scale_width * (scale_height - 1)); i++)
double_buf[i] = RGB16(0,0,0);

textsurf->Unlock(&rect);

}


Now that I''ve found this source code, I think I''ll study it some more.

Share this post


Link to post
Share on other sites

By the way, does anyone know what DirectX uses for image scaling when loading a testure from file? Is it bilinear resampling, Bicubic interpolation, or some other algorithm.

Share this post


Link to post
Share on other sites
You can set flags I believe with the SetTextureStageState function to tell it how to load the image (linear, etc.).

Share this post


Link to post
Share on other sites
You could also use IDirectDrawSurface7::Blt(...)''s ability to stretch images to your advantage. This is especially useful if you are already loading your image onto a surface. Check out the SDK, it''s just a matter of having a source rect that is a different size than the dest rect, the stretching is automatic. In most cases, the stretching is done in hardware, making it pretty fast.

D

Share this post


Link to post
Share on other sites
It might be interesting/beneficial to look into packing several of the odd sized textures into one larger texture. For instance, packing 5 200x200 textures into 1 1024x256 texture would waste less resources than loading the 200x textures into 5 different 256x256 textures. That might be useful for the characters wher (AFAIK) there isn''t any tiling.

That way, you wouldn''t have to stretch at all. Stretching the original texture just introduces artifacts and wastes texture memory.

Share this post


Link to post
Share on other sites
do an AA scaler (ie weight each point against it neighbours when rescaling depending it strength) and get what size you shall resize to with:

        
for(int y = 0; y < 8; y++){
if(yres<=pow(2,y))break;
}
for(int x = 0; x < 8; x++){
if(xres<=pow(2,x))break;
}
int new_xres = pow(2,x);
int new_yres = pow(2,y);
if(new_xres!=xres||new_yres!=yres)
rescale(xres,yres,new_xres,new_yres);

and voila done

(lets see if i get that source shit work at last(editing)


uhm, ok fixing the < to <= .. sorry ;-) uhm iam bored and prety fucking fucked up.. this chemicales are cool

[edited by - stefandxm on June 9, 2002 2:45:40 PM]

Share this post


Link to post
Share on other sites
Eeeewwwww! Stay away from pow(), especially in tight loops.
use bit shifts instead:

  
int new_xres = 1 << x;


Steve

Steve
DirectX Programmer
Soon to be the new Bill Gates

Share this post


Link to post
Share on other sites
you call that a tight loop?

and besides, its at loading time not at runtime + it was written to help a person, not to optimize something, this code hasnt been tested but it looks clean enough to read, i prefer letting the implementer optimize for his system.

Share this post


Link to post
Share on other sites
why not just adjust your texture coordinates? ie instead of going from 0.0 to 1.0 go from 0.0 to realImageWidth/textureWidth and realImageHeight/textureHeight. its MUCH faster then scaling the images at load time and you wont get nasty artifacts EXCEPT if you plan to tile the textures. in that case you will have to scale the image. its funny. all quake2 textures are 256x256, possible you should switch to the md2 format instead?

in any case if you do plan on doing post porcessing (ie scaling the images), you best make sure that it dont take long to load. if it does you may wish to write a simple app that will scale all the images for you then you can use the pre scaled images.

scaling however will ALWAYS introduce artifacts. you are much better off dealing with quake2 simply because its more designed with the power of 2 hardware restriction. however i find it interesting that quake did not use such restrictions since it makes it TONS faster to tile (ie a simple logical AND). possible carmack had his reasons.

i suggest trying a few alternatives. placing a few textures together may be benificial (if the card can support large textures). not only does it help save vram, but at the same time reduces texture switches. however it does potential cause problems with extra texture swapping from sysmem if models in the large textures are not local (ie when rendering them they dont appear on the screen at the same time). this may actually cause slow down compard to the wasted vram and switches.

Share this post


Link to post
Share on other sites
D3DXLoadSurfaceFromMemory is what you want.

It will scale based any of the standard filters that D3DX has.

Remember a surface isn''t a texture (texture usually contain multiple surfaces known as the MIP-chain). Call this in a loop to make a mip chain yourself on a texture. The procedure here is to create a texture, get the surface(s) you want to fill and party on.

If you want to convert formats, do something like:

D3DXLoadSurfaceFromMemory
D3DXSaveSurfaceToFile

Share this post


Link to post
Share on other sites
Paint Shop Pro has a batch format conversion. You could convert all your graphics to a more modern format with one command.


Jack

Share this post


Link to post
Share on other sites

  • Advertisement