• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

Archived

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

q3stanky

loading time

39 posts in this topic

i ve a prob in my opengl project i must load textures (bmp) but i dont know why it takes so long and now i m searching a jpg loader or a way i can load textures faster like in all 3d games (i use the loading engine from http://nehe.gamedev.net) thanks
0

Share this post


Link to post
Share on other sites
Try the Intel JPEG Library. I use it and find it very fast.
You can download it here:
http://www.intel.com/software/products/perflib/index.htm

To quickly get started with it, search for EncodeJPGFileFromDIB and
DecodeJPGFileToGeneralBuffer in ijlman.pdf.
0

Share this post


Link to post
Share on other sites
How many textures are you loading ? And how big are they (resolution, colour depth) ?

- AH
0

Share this post


Link to post
Share on other sites
Load times depend on more than just file format. Things like amount of free memory, memory speed, hard disk speed, cpu speed, etc all affect it.

Also, jpegs need to be read in and then decompressed, whereas bitmaps just need to be read in. Jpegs wont have as good quality neither.

-----------------------
0wn 0wn 0wn your goat
gently down the pw33n
0

Share this post


Link to post
Share on other sites
You might also like to try DevIL which can be downloaded from http://openil.sourceforge.net/
It can load all sorts of graphic formats, including bmp, jpg, tga and png.
0

Share this post


Link to post
Share on other sites
the textures are all 50 mb big and they are 40 and the biggest resuluton is 1600+1200 (the surface of mars)the textureloading would not be a prob if i can find a way to load text in the opengl engine . when i include text ca 20 lines with 10 words the engine has a performance problem so i would need a solution of this prob too

thanks
0

Share this post


Link to post
Share on other sites
> the textures are all 50 mb big and they are 40

You are loading 2GB textures ?!
Or did you mean, they make 50mb alltogether ?

Well I hope you meant the later. At current HD speeds, it would take around 2 to 3 seconds, if you are directly streaming your data to memory.

Something like:

fp = fopen(...);
fread(buffer, 1, 1600*1200*4 + sizeof(header), fp);
fclose(fp);


Will load a 1600*1200 32bit texture to memory in less than a second, depending on your HD speed, transfer mode, etc...
But: It loads the raw texture data, it does not decode, decompress, interprete the data. But it''s always faster to run the decompression or whatever other process you need over a memory buffer, than doing things like:


// Bad and evil example of how to not do it
//
for( y=0; y<ysize; y++) for( x=0; x<xsize; x++) {
fread(&red, 1, 1, fp);
fread(&green, 1, 1, fp);
fread(&blue, 1, 1, fp);
fread(&alpha, 1, 1, fp);
// process rgba
}


This will be slow as hell.

Jpeg might be an alternative, if your HD speed is slow, and the decompressor outperforms your HD. Depends on your HD and CPU speed, and the quality (performance) of the jpeg decompressor.

- AH


0

Share this post


Link to post
Share on other sites
they are 50 MB alltogether

and they need 25 seconds(athlonxp1900+,u-dma 100,7200 rpm, 256 ddr)

and 2 minutes(p3 500, u-dma 66,5400 rpm,64 mb sd ram)

and i load :

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
AUX_RGBImageRec *LoadBMP(char *Filename)
{
FILE *File=NULL; if (!Filename) {
return NULL; }
File=fopen(Filename,"r");
if (File)
{
fclose(File);
return auxDIBImageLoad(Filename);
}

return NULL;
}
.
.
.
.
.
.

bool Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[30]; // Create Storage Space For The Textures
memset(TextureImage,0,sizeof(void *)*30); // Set The Pointer To NULL

if ((TextureImage[ 0]=LoadBMP("Data/mars.bmp")) &&
(TextureImage[ 1]=LoadBMP("Data/sonne2.bmp")) &&
(TextureImage[ 2]=LoadBMP("Data/merkur.bmp")) &&
(TextureImage[ 3]=LoadBMP("Data/venus.bmp")) &&
(TextureImage[ 4]=LoadBMP("Data/erde.bmp")) &&
(TextureImage[ 5]=LoadBMP("Data/mars.bmp")) &&
(TextureImage[ 6]=LoadBMP("Data/jupiter.bmp")) &&
(TextureImage[ 7]=LoadBMP("Data/saturn.bmp")) &&
(TextureImage[ 8]=LoadBMP("Data/uranus.bmp")) &&
(TextureImage[ 9]=LoadBMP("Data/neptun.bmp")) &&
(TextureImage[10]=LoadBMP("Data/pluto.bmp")) &&
(TextureImage[11]=LoadBMP("Data/saturn_ringe.bmp")) &&
(TextureImage[12]=LoadBMP("Data/korona.bmp")) &&
(TextureImage[13]=LoadBMP("Data/button.bmp")) &&
(TextureImage[14]=LoadBMP("Data/button2.bmp")) &&
(TextureImage[15]=LoadBMP("Data/button3.bmp")) &&
(TextureImage[16]=LoadBMP("Data/light2.bmp")) &&
(TextureImage[17]=LoadBMP("Data/mond.bmp")) &&
(TextureImage[18]=LoadBMP("Data/flare.bmp")) &&
(TextureImage[19]=LoadBMP("Data/erde2.bmp")) &&
(TextureImage[20]=LoadBMP("Data/wolken.bmp")) &&
(TextureImage[21]=LoadBMP("Data/white.bmp")) &&
(TextureImage[22]=LoadBMP("Data/satring.bmp")) &&
(TextureImage[23]=LoadBMP("Data/s1.bmp")) &&
(TextureImage[24]=LoadBMP("Data/s2.bmp")) &&
(TextureImage[25]=LoadBMP("Data/s3.bmp")) &&
(TextureImage[26]=LoadBMP("Data/s4.bmp")) &&
(TextureImage[27]=LoadBMP("Data/s5.bmp")) &&
(TextureImage[28]=LoadBMP("Data/s6.bmp")) &&
(TextureImage[29]=LoadBMP("Data/satri.bmp")))
{
Status=TRUE; // Set The Status To TRUE
glGenTextures(30, &texture[0]); // Create Five Textures

for (loop=0; loop<30; loop++) // Loop Through All 5 Textures
{

glBindTexture(GL_TEXTURE_2D, texture[loop]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);

/* // Create Linear Filtered Texturez
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[loop]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
*/ }
}
for (loop=0; loop<30; loop++) // Loop Through All 5 Textures
{
if (TextureImage[loop]) // If Texture Exists
{
if (TextureImage[loop]->data) // If Texture Image Exists
{
free(TextureImage[loop]->data); // Free The Texture Image Memory
}
free(TextureImage[loop]); // Free The Image Structure
}
0

Share this post


Link to post
Share on other sites
Well, I just flew over your code, and at a first glance, I can see 3 problems:

1) Remove this *HUGE* if statement ! Replace it with a loop. It won''t affect performance (very much), but this is just horrible

2) auxDIBImageLoad(): never trust Microsoft API calls, if you are interested in speed. Make your own BMP or TGA loader, it''s very easy, and faster.

3) gluBuild2DMipmaps(): This one *kills* performance. Esp. with huge textures. I think, it is the main reason for your slow loading. Professional games do the mipmap level filtering in a precalc step, and store them along with the texture. They are then directly loaded at runtime. Though you will need your own proprietary texture fileformat for that - but it will most definitely speed things up (alot).

- AH
0

Share this post


Link to post
Share on other sites
thanks for this tip but i dont know how to make a compatiple bmp loader


and i dont understand tip 3



thanks
0

Share this post


Link to post
Share on other sites
AH,
Can you please explain how someone would precalc the mipmaps. Do you save multiple versions of the texure in the file.
I''m not positive of how mipmapping works. Maybe I''m thinking of the wrong thing. But is mipmapping changng the texture to make it look better from all distances?
-anonymous
0

Share this post


Link to post
Share on other sites
tne reason glumipmaps is slow is cause it rescales the images with a slow rescale image function.
solution. rescale the images with a faster method i believe theres a new mipmap function out there that is much faster sgis_mipmaps or something or write your own optimized rescaling function or do as AH saiz + rescale the images say with gimp and save those as well thus u read the original size texture + copies of it all the way down to 1x1 off the harddisk

http://uk.geocities.com/sloppyturds/gotterdammerung.html
0

Share this post


Link to post
Share on other sites
can you just save each scale of the mipmapped textures as seperate images (jpegs preferably) and load them like that?

// God.c
void main() {
WORLD Earth;
LIFE People = Earth.CreateLife(HUMAN);
GiveHope(&People);
delete Earth;
EvilCackle();
}
0

Share this post


Link to post
Share on other sites
Just a little reminder, how mipmapping works:

You have your original texture (say 1024*1024, to make it easier). If the texture is scaled down alot by texturing, eg. your polygon is far away or small, then you would notice sparkeling artifacts, because the 3D hardware can only resmaple 4 textes at a time.

This is why mipmaps are used: they are scaled versions of your original texture, in such a way, that the 3D card only needs to interpolate among 4 texels at most, in any circumstance.
You create them by scaling down (resizing) your orginal texture many times, always cutting it''s size to one quarter (half resolution). Each resized version is called a mipmap level.

Example:
Original texture (level 0): 1024*1024
Mipmap level 1: 512*512
Mipmap level 2: 256*256
Mipmap level 3: 128*128
Mipmap level 4: 64*64
Mipmap level 5: 32*32
Mipmap level 6: 16*16
Mipmap level 7: 8*8
Mipmap level 8: 4*4
Mipmap level 9: 2*2
( Mipmap level 10: 1*1 ) This one isn''t really needed, but it''s in the OGL specs, so we do it anyway.

This would be a complete mipmap hierarchy. This is done for each texture. Now you can imagine, that all this scaling takes time, especially, if complex (high quality) scaling filters are used, such as bicubic interpolation. This is why gluBuild2DMipmaps() is slow.

Now, you can prebuild your mipmaps and store them along with your texture. Just create all the levels for each texture, and store them sequentially in your own texture fileformat. At runtime, you load them in, and simply bind the texture incl. all mipmaps. No gluBuild2DMipmaps() needed.

You *could* create them by hand, eg. with Photoshop or Gimp, but that''s a *lot* of work. Write a small programm that loads your original texture, and performs the resampling. It''s easy, for each level, take the level before and average 4 texels. This average value creates the new texel in your current level.

quote:

But is mipmapping changng the texture to make it look better from all distances?



Yes, that''s it.

quote:

can you just save each scale of the mipmapped textures as seperate images (jpegs preferably) and load them like that?



Yes, you could. But I would stay away from jpeg''s for mipmaps. They are +-OK for original level 0 textures, that get resampled at startup, but don''t use them as mipmap levels. The Jpeg compressor uses an internal resampling and filtering system, that defeats the purpose of well adjusted mipmaps. You will reintroduce those ugly sparkeling effects, since some frequencies are missing in the mipmap level, due to jpeg compression. PNG''s are well suited, they compress rather well (although not as good as jpeg, obviously), but they are lossless.

- AH
0

Share this post


Link to post
Share on other sites
I thought, I''d just provide a small mipmap filter. It''s not so great quality (only linear filtering), but it does the job rather well (I think just as good as gluBuild2DMipmaps). It only works for isotropic textures.

  
static void FilterMipmapsLinear(iRGBA *Src, iRGBA *Dst, int size)
{
int x, y, l, psize;

psize = size*2; // size of previous mipmap level


for(y=0;y<size;y++) for(x=0;x<size;x++) {
l=y*2*psize+x*2;
Dst[y*size+x].r = (Src[l].r+Src[l+1].r+Src[l+psize].r+Src[l+psize+1].r)/4;
Dst[y*size+x].g = (Src[l].g+Src[l+1].g+Src[l+psize].g+Src[l+psize+1].g)/4;
Dst[y*size+x].b = (Src[l].b+Src[l+1].b+Src[l+psize].b+Src[l+psize+1].b)/4;
Dst[y*size+x].a = (Src[l].a+Src[l+1].a+Src[l+psize].a+Src[l+psize+1].a)/4;
}
}


Use it like that (eg. for a 1024*1024 texture):

FilterMipmapsLinear( OriginalTexture, Level1Mipmap, 512 );
FilterMipmapsLinear( Level1Mipmap, Level2Mipmap, 256 );
FilterMipmapsLinear( Level2Mipmap, Level3Mipmap, 128);
FilterMipmapsLinear( Level3Mipmap, Level4Mipmap, 64);
etc...

- AH
0

Share this post


Link to post
Share on other sites
when i mipmap the textures in this way it takes 2 min at a system what took 20 seconds before

i think thats logical because now i''m loading effectly 30*10 =300 textures
0

Share this post


Link to post
Share on other sites
> when i mipmap the textures in this way it takes 2 min at a system what took 20 seconds before

Well, you did something wrong then.

On my engine, it takes around 4 seconds to load 70MBtextures pre-mipmaped with the function above. I use my own texture format, where I sequentially store the mipmap levels, and load them all at once with a single fread().

- AH
0

Share this post


Link to post
Share on other sites
So, does mipmapping improve the image quality, or the speed?
0

Share this post


Link to post
Share on other sites
On older cards, the quality only.
On newer cards, both.

It takes more memory, though.
- AH
0

Share this post


Link to post
Share on other sites
i''ve a geforce 3 ti 500

it shold work but i''m a bit blemblem

the last possibility:

may somebody post a whole fast bmp loading code with an loading exemple that is not compiled that i can see the system and when i compile it in vc ++ 6.0 it should work allone (please for direct compile) i can better see the system when i can change something and see what happens.

sorry

thanks
0

Share this post


Link to post
Share on other sites
Hmm...

One time I made a replacement for auxDIBImageLoad...
I don''t know how efficient it is--seeming I''m a win32 app coder, primarily, and I only play around with OGL in my free time--but it seemed to work good for me.

Here goes:
  


//this replaces auxDIBImageLoad

static BMPINFO *LoadBMP(char *filename)
{
BMPINFO *bmpinfo;
HBITMAP hbitmap = NULL;
UINT32 ret;
BITMAP bitmap;
UINT32 x;
BYTE tmp;

//load the image from file

hbitmap = (HBITMAP) wec_LoadImage(NULL, filename, IMAGE_BITMAP, 0, 0,
LR_DEFAULTCOLOR | LR_LOADFROMFILE);

#if (err_DEBUG)
if (hbitmap == NULL)
{
DERROR(castle_BADARG, "Invalid filename for bitmap");
}
#endif

//get descriptor, including width/height

wec_GetObject(hbitmap, sizeof(bitmap), &bitmap);

ret = ecmem_Alloc(sizeof(BMPINFO), &bmpinfo);

if (ret == 0)
{
UERROR(castle_BMPERR, "Could not alloc memory for bitmap information");
}

bmpinfo->width = bitmap.bmWidth;
bmpinfo->height = bitmap.bmHeight;

ret = ecmem_Alloc(bmpinfo->width * bmpinfo->height * 4 + 1, &bmpinfo->data);

if (ret == 0)
{
UERROR(castle_BMPERR, "Could not alloc memory for bitmap raw data");
}

//zero memory space

memset(bmpinfo->data, 0, bmpinfo->width * bmpinfo->height * 4);

//receive DIB bits into bmpinfo->data

wec_GetBitmapBits(hbitmap, bmpinfo->width * bmpinfo->height * 4, bmpinfo->data);

//now we begin a 2 step process of changing the data into GL_RGB format

//first, swap the order of the image, top to bottom, bottom to top

for (x = 0; x < bmpinfo->height * bmpinfo->height * 2; x++)
{
tmp = *(bmpinfo->data + x);
*(bmpinfo->data + x) = *(bmpinfo->data + ((bmpinfo->height * bmpinfo->width * 4) - x));
*(bmpinfo->data + ((bmpinfo->height * bmpinfo->width * 4) - x)) = tmp;
}

//next, get rid of the "zero" padding that''s included in windows color data

for (x = 0; x < bmpinfo->width * bmpinfo->height * 3; x++)
{
*(bmpinfo->data + x) = *(bmpinfo->data + x + (x / 3) + 2);
}

wec_DeleteObject(hbitmap);

return bmpinfo;
}



Then here''s how you''d use it, similar to nehe''s code:

  

static void LoadTextures(void)
{
UINT32 x;
BMPINFO *textureimage[1];

memset(textureimage, 0, sizeof(void *) * 1);

textureimage[0] = LoadBMP("data\\wall.bmp");

if (textureimage[0] == NULL)
{
UERROR(castle_BMPERR, "Unable to load textures");
return;
}

for (x = 0; x < sizeof(texture) / sizeof(texture[0]); x++)
{
glGenTextures(1, &texture[x].texture);
}

//create GL_LINEAR (high quality) texture

glBindTexture(GL_TEXTURE_2D, texture[0].texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

gluBuild2DMipmaps(GL_TEXTURE_2D, 3, textureimage[0]->height, textureimage[0]->width,
GL_RGB, GL_UNSIGNED_BYTE, textureimage[0]->data);

texture[0].width = 1.0f;
texture[0].height = 1.0f;

if (textureimage[0])
{
if (textureimage[0]->data)
{
ecmem_Free(textureimage[0]->data);
}
ecmem_Free(textureimage[0]);
}
}



That might help you out...it''s just basically generic win32 code to load textures, into the OGL format, and setup the mipmaps, etc.

Umm, a few notes about the code:
1) "wec_"''s are just win32 api calls...delete the wec from the beginning of the function call, and it''ll be just like win32 api.
2) UERROR is sorta like an ASSERT, in my coding style...it''s for error reporting purposes...you''ll have to modify those portions of code to your own error-catching style
3) #if (err_DEBUG) and DERROR are for debug-time error checking...you can basically just delete all this code, for release build purposes.

That might help you understand how to load textures w/o using auxDIBImageLoad.

Any questions: duck0026@tc.umn.edu

-Rob
0

Share this post


Link to post
Share on other sites
it looks like i must load all textutes at the beginning in the same way i loaded before and i can cuse the same funktion to loade the textuter before i call an object ok ?
0

Share this post


Link to post
Share on other sites
Dragn: I think this is a lot less efficient than DIBImageLoad. There is way to much copying, swapping, and converting. Take a look at the BMP filespecs, and write one from scratch, without all those WinAPI conversion functions. That''s the only way to make it really fast.
0

Share this post


Link to post
Share on other sites