fabinou
Registered just to make one post
Posts: 1
Registered: 01-10 |
I'm glad some people enjoyed my article, I write this stuff mainly as memo for myself, but it is obviously a huge bonus when people like it.
The way it's done is actually not rocket science, here is the process if you want to do it on Eternity:
The approach is to limit the number of pixel drawn each frames, save the frame as a bitmap and generate a movie out of it.
I used two variables: max_num_pixels=0 and remaining_pixels_for_frame.
At the beginning on a frame in D_Display:
code:
remaining_pixels_for_frame = max_num_pixels;
max_num_pixels++;
All draw operations are nicely grouped in r_draw.c, depending on the rendition quality (high or low), the engine will use either:
code:
R_DrawColumn ()
R_DrawFuzzColumn ()
R_DrawTranslatedColumn ()
R_DrawSpan ()
or
code:
R_DrawColumnLow ()
R_DrawFuzzColumnLow ()
R_DrawTranslatedColumnLow ()
R_DrawSpanLow ()
For each method, test:
code:
if (remaining_pixels_for_frame >0 )
{
remaining_pixels_for_frame--
draw
}
Two issues:
- Doom never cleared the framebuffer because the entire screen was updated each frame, you need to do this otherwise you still have the menu or whatever was there before you started:
In D_Display:
code:
memset(screens[0], 0, SCREENWIDTH * SCREENHEIGHT);
Each frame, the screen is saved as BMP:
In I_FinishUpdate:
code:
memset(screenName,0,256);
sprintf(screenName,"./screens/draw%d.bmp",numFrames);
SDL_SaveBMP(screen,screenName);
I then used Quicktime to open an image sequence and generate an mp4.
For the iPhone version, it's a little bit more complicated because it's working with GL_TRIANGLES and GL_TRIANGLE_STRIP but the approach is the same: limit the number of triangles, read the framebuffer via a glReadPixels, write the frame.
In the end you get something like this:
http://fd.fabiensanglard.net/doomIp...honePreview.mov
Walls and Flats are drawn not in distance order but in textureID order to limit the number of openGL state change (something that you probably saw in Quake engine as well).
The video also illustrate the way the tessellation worked via the blue floor (you can see the triangles drawn as a fan, left to right)
If I find enough interesting stuff about iPhone version, I'll publish something.
EDIT: I don't believe Eternity is SDL based but you can as well generated a TGA, here is a code snippet from my dEngine:
code:
int num_screenshot=0;
void dEngine_WriteScreenshot(char* directory)
{
char* data;
int i;//,j;
FILE* pScreenshot;
char fullPath[256];
char num[5];
char tga_header[18];
char* pixel;
char tmpChannel;
int renderHeight = 480;
int renderWidth = 320 ;
sprintf(num, "%04d", num_screenshot++);
//itoa(,num,3);
memset(fullPath, 256, sizeof(char));
strcat(fullPath,directory);
strcat(fullPath,num);
strcat(fullPath,".tga");
data = calloc(renderHeight*renderWidth, 4);
glReadPixels(0,0,renderWidth,renderHeight,GL_RGBA, GL_UNSIGNED_BYTE,data);
pScreenshot = fopen(fullPath, "wb");
memset(tga_header, 0, 18);
tga_header[2] = 2;
tga_header[12] = (renderWidth & 0x00FF);
tga_header[13] = (renderWidth & 0xFF00) / 256;
tga_header[14] = (renderHeight & 0x00FF) ;
tga_header[15] =(renderHeight & 0xFF00) / 256;
tga_header[16] = 32 ;
fwrite(&tga_header, 18, sizeof(char), pScreenshot);
//RGBA > BGRA
pixel = data;
for(i=0 ; i < renderWidth * renderHeight ; i++)
{
tmpChannel = pixel[0];
pixel[0] = pixel[2];
pixel[2] = tmpChannel;
pixel += 4;
}
fwrite(data, renderWidth * renderHeight, 4 * sizeof(char), pScreenshot);
fclose(pScreenshot);
free(data);
}
It's no great code but it gets the job done.
Last edited by fabinou on 01-18-10 at 20:22
|