Doom 3 engine release and game code

Discuss programming topics for any language, any source base. If it is programming related but doesn't fit in one of the below categories, it goes here.
anonreclaimer
Posts: 21
Joined: Tue Aug 28, 2012 4:36 am

Re: Doom 3 engine release and game code

Post by anonreclaimer »

reckless wrote:Only because Doom3's cinematic code needs jpeg for the huff encoding :)
and a few Things changed in the newer jpeg library so the old macros didnt Work the same as before. Example old one had GLOBAL void new one uses GLOBAL(void) etc.

Just like to improve on it no other reason besides sharpening my sklls in C++ :) before Doom3 i only coded in C.
I wonder why they got rid of megatextures and the tools?

You only do it to work on your skills I thought you were making a game.

From your view point which is a better engine bfg or doom 3?
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Post by revelator »

BFG undobtly has the better renderer :) Vanilla is ok but it still uses a load of deprecated opengl calls.
Megatextures where not used at all in Vanilla either so i guess they left it out completly. Also Vanillas megatexture code was probably one of id's first versions and it had some drawbacks. Newer the less it would have been nice for a modder for outdoor areas :) but giving us rages updated version before rage actually became GPL and free to use was probably not in carmacks plans :lol:

Id like to make a game unfortunatly my skills in the mapping department are less than stellar (can hardly Draw a pencilman without breaking both the paper and the pencil lol) so i stick to coding :).

The tools for BFG are out but just a warning the download is 35 gb :shock: they also are not for the faint of Heart to use. You can grab them on steam. Look for Rage Toolkit or something like that.
Productivity is a state of mind.
anonreclaimer
Posts: 21
Joined: Tue Aug 28, 2012 4:36 am

Re: Doom 3 engine release and game code

Post by anonreclaimer »

reckless wrote:BFG undobtly has the better renderer :) Vanilla is ok but it still uses a load of deprecated opengl calls.
Megatextures where not used at all in Vanilla either so i guess they left it out completly. Also Vanillas megatexture code was probably one of id's first versions and it had some drawbacks. Newer the less it would have been nice for a modder for outdoor areas :) but giving us rages updated version before rage actually became GPL and free to use was probably not in carmacks plans :lol:

Id like to make a game unfortunatly my skills in the mapping department are less than stellar (can hardly Draw a pencilman without breaking both the paper and the pencil lol) so i stick to coding :).

The tools for BFG are out but just a warning the download is 35 gb :shock: they also are not for the faint of Heart to use. You can grab them on steam. Look for Rage Toolkit or something like that.
Well its good both are gpl since we can improve both now.
I would like to see a improve megatexture code too.:) but I doubt will see rage gpl I think john carmack might leave id idk.

Anyway I never told you why I work on doom 3 I original wanted to use quakeworld because I love quake but I knew I couldn't hack it.
tbh I've been making a hybrid between both doom 3 and bfg but I want to wait in till etqw get gpl but I don't think it will happen. :cry:
I got the idea from valve when they got the quakeworld licences.They made something incredible I want to do the same.

Dude you can probably make some cool crap plus your coding skills are amazing maybe you could whip up a g good thing with your engine
All you need is creativity and imagination. :D

Wait bfg used the rage toolkit for tools wow! :shock:
What do you mean they also are not for the faint of Heart to use.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Post by revelator »

What do you mean they also are not for the faint of Heart to use.
A lot of them are commandline tools so its probably not for people who newer tried dos. And aye it uses the rage tooolkit :)

Rage will at some point be GPL but that might be way out in the future.

Hehe ok we got a bit of the same idea then :) use BFG and Vanilla stuff together.

Im good at parts but i actually started coding with basic back in the days of the spectrum zx80. Then i took my exam as a radio tech and several years went by not coding anything and forgetting most of what i learned, untill one day i needed help setting up a quake server and i ended up on the now defunt quakesrc site. It poked my interrest Again and i started playing with the quake sources.
Over the time i learned quite a deal though not enough to start from scratch on my own engine, but enough to actually put my skills to Work in areas like porting GNU tools to Windows, and making a special version of msys with a lot of the bugs fixed the original had. I have my own compiler suite which qbism here uses atleast. When Doom3 became GPL i knew Little to nothing of C++ so it took me a while to get used to the new language but im getting there :)
Productivity is a state of mind.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Post by revelator »

Drop in replacement for VBO.

This is Mh's Work just had a Little cleanup by me.

Code: Select all

/*
===========================================================================

Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").

Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/

#include "../idlib/precompiled.h"
#pragma hdrstop
#include "tr_local.h"

/* GL_NVX_gpu_memory_info */
#ifndef GL_NVX_gpu_memory_info
#define GL_NVX_gpu_memory_info 1

#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047
#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048
#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049
#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A
#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B
#endif /* GL_NVX_gpu_memory_info */

/* GL_ATI_meminfo */
#ifndef GL_ATI_meminfo
#define GL_ATI_meminfo 1

#define GL_VBO_FREE_MEMORY_ATI 0x87FB
#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC
#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD
#endif /* GL_ATI_meminfo */

static const int	FRAME_MEMORY_BYTES = 0x400000;
static const int	EXPAND_HEADERS = 32;

idCVar idVertexCache::r_showVertexCache("r_showVertexCache", "0", CVAR_INTEGER|CVAR_RENDERER, "show vertex cache");
idCVar idVertexCache::r_useArbBufferRange("r_useArbBufferRange", "1", CVAR_BOOL|CVAR_RENDERER, "use ARB_map_buffer_range for optimization");
idCVar idVertexCache::r_reuseVertexCacheSooner("r_reuseVertexCacheSooner", "1", CVAR_BOOL | CVAR_RENDERER, "reuse vertex buffers as soon as possible after freeing");
idCVar idVertexCache::r_freeVertexCache("r_freeVertexCache", "0", CVAR_BOOL | CVAR_RENDERER, "experimental Fill the vertex buffer with zeros");

idVertexCache		vertexCache;

static void R_ShowVideoMem_f(const idCmdArgs &args)
{
    vertexCache.ShowMem();
}

/*
==============
R_ListVertexCache_f
==============
*/
static void R_ListVertexCache_f(const idCmdArgs &args)
{
    vertexCache.List();
}

/*
==============
idVertexCache::ActuallyFree
==============
*/
void idVertexCache::ActuallyFree(vertCache_t *block)
{
    if (!block)
    {
        common->Error("idVertexCache Free: NULL pointer");
    }
    if (block->user)
    {
        // let the owner know we have purged it
        *block->user = NULL;
        block->user = NULL;
    }
    // temp blocks are in a shared space that won't be freed
    if (block->tag != TAG_TEMP)
    {
        bool done = false;
        staticAllocTotal -= block->size;
        staticCountTotal--;
        if (block->vbo && !done)
        {
			// experimental fill the vertex buffer with zeros = free.
            if (r_freeVertexCache.GetBool())
            {
                BindIndex(GL_ARRAY_BUFFER_ARB, block->vbo);
                qglBufferDataARB(GL_ARRAY_BUFFER_ARB, block->size, NULL, GL_DYNAMIC_DRAW_ARB);
            }

            // mark it as done and skip the rest.
            done = true;
        }
        else if (block->virtMem && !done)
        {
            delete [] block->virtMem;
            block->virtMem = NULL;
            // mark it as done and skip the rest.
            done = true;
        }
    }
    block->tag = TAG_FREE;		// mark as free
    // unlink stick it back on the free list
    block->next->prev = block->prev;
    block->prev->next = block->next;
    if (r_reuseVertexCacheSooner.GetBool())
    {
        // stick it on the front of the free list so it will be reused immediately
        block->next = freeStaticHeaders.next;
        block->prev = &freeStaticHeaders;
    }
    else
    {
        // stick it on the back of the free list so it won't be reused soon (just for debugging)
        block->next = &freeStaticHeaders;
        block->prev = freeStaticHeaders.prev;
    }
    block->next->prev = block;
    block->prev->next = block;
}

/*
==============
idVertexCache::Position

this will be a real pointer with virtual memory,
but it will be an int offset cast to a pointer with
ARB_vertex_buffer_object

The ARB_vertex_buffer_object will be bound
==============
*/
void *idVertexCache::Position(vertCache_t *buffer)
{
    if (!buffer || buffer->tag == TAG_FREE)
    {
        common->FatalError("idVertexCache::Position: bad vertCache_t");
    }
    // the ARB vertex object just uses an offset
    if (buffer->vbo)
    {
        if (r_showVertexCache.GetInteger() == 2)
        {
            if (buffer->tag == TAG_TEMP)
            {
                common->Printf("GL_ARRAY_BUFFER_ARB = %i + %i (%i bytes)\n", buffer->vbo, buffer->offset, buffer->size);
            }
            else
            {
                common->Printf("GL_ARRAY_BUFFER_ARB = %i (%i bytes)\n", buffer->vbo, buffer->size);
            }
        }
        BindIndex((buffer->indexBuffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER), buffer->vbo);
        return (void *)buffer->offset;
    }
    // virtual memory is a real pointer
    return (void *)((byte *)buffer->virtMem + buffer->offset);
}

/*
===========
idVertexCache::BindIndex
===========
*/
void idVertexCache::BindIndex(GLenum target, GLuint vbo)
{
    GLuint vertexBuffer = 0;
    GLuint indexBuffer = 0;

    if (target == GL_ARRAY_BUFFER)
    {
        if (vertexBuffer == vbo) 
		{ 
			return; 
		}
        qglBindBufferARB(target, vbo);
        vertexBuffer = vbo;
    }
    else if (target == GL_ELEMENT_ARRAY_BUFFER)
    {
        if (indexBuffer == vbo) 
		{ 
			return; 
		}
        qglBindBufferARB(target, vbo);
        indexBuffer = vbo;
    }
    else
    {
        common->FatalError("BindIndex : unknown buffer target : %i\n", (int) target);
    }
}

/*
===========
idVertexCache::UnbindIndex
===========
*/
void idVertexCache::UnbindIndex(GLenum target)
{
    if (target == GL_ARRAY_BUFFER)
    {
        qglBindBufferARB(target, 0);
    }
    else if (target == GL_ELEMENT_ARRAY_BUFFER)
    {
        qglBindBufferARB(target, 0);
    }
    else
    {
        common->FatalError("UnbindIndex : unknown buffer target : %i\n", (int) target);
    }
}

//================================================================================

/*
===========
idVertexCache::Init
===========
*/
void idVertexCache::Init()
{
    cmdSystem->AddCommand("showVideoMem", R_ShowVideoMem_f, CMD_FL_RENDERER, "Show Video Memory");
    cmdSystem->AddCommand("listVertexCache", R_ListVertexCache_f, CMD_FL_RENDERER, "lists Vertex Cache");
    // use ARB_vertex_buffer_object unless explicitly disabled
    if (r_useVertexBuffers.GetInteger() && glConfig.ARBVertexBufferObjectAvailable)
    {
        virtualMemory = false;
        r_useIndexBuffers.SetBool(true);
        common->Printf("using ARB_vertex_buffer_object memory\n");
    }
    else
    {
        virtualMemory = true;
        r_useIndexBuffers.SetBool(false);
        common->Printf("WARNING: vertex array range in virtual memory (SLOW)\n");
    }
    // initialize the cache memory blocks
    freeStaticHeaders.next = freeStaticHeaders.prev = &freeStaticHeaders;
    staticHeaders.next = staticHeaders.prev = &staticHeaders;
    freeDynamicHeaders.next = freeDynamicHeaders.prev = &freeDynamicHeaders;
    dynamicHeaders.next = dynamicHeaders.prev = &dynamicHeaders;
    deferredFreeList.next = deferredFreeList.prev = &deferredFreeList;
    // set up the dynamic frame memory
    frameBytes = FRAME_MEMORY_BYTES;
    staticAllocTotal = 0;
    byte *frameBuffer = new byte[frameBytes];
    for (int i = 0 ; i < NUM_VERTEX_FRAMES ; i++)
    {
        // force the alloc to use GL_STREAM_DRAW_ARB
        allocatingTempBuffer = true;
        Alloc(frameBuffer, frameBytes, &tempBuffers[i]);
        allocatingTempBuffer = false;
        tempBuffers[i]->tag = TAG_FIXED;
        // unlink these from the static list, so they won't ever get purged
        tempBuffers[i]->next->prev = tempBuffers[i]->prev;
        tempBuffers[i]->prev->next = tempBuffers[i]->next;
    }
    delete [] frameBuffer;
    frameBuffer = NULL;
    EndFrame();
}

/*
===========
idVertexCache::PurgeAll

Used when toggling vertex programs on or off, because
the cached data isn't valid
===========
*/
void idVertexCache::PurgeAll()
{
    while (staticHeaders.next != &staticHeaders)
    {
        ActuallyFree(staticHeaders.next);
    }
}

/*
===========
idVertexCache::Shutdown
===========
*/
void idVertexCache::Shutdown()
{
    headerAllocator.Shutdown();
}

/*
===========
idVertexCache::Alloc
===========
*/
void idVertexCache::Alloc(void *data, int size, vertCache_t **buffer, bool indexBuffer)
{
    vertCache_t	*block = NULL;
    if (size <= 0)
    {
        common->Error("idVertexCache::Alloc: size = %i\n", size);
    }
    // if we can't find anything, it will be NULL
    *buffer = NULL;
    // if we don't have any remaining unused headers, allocate some more
    if (freeStaticHeaders.next == &freeStaticHeaders)
    {
        for (int i = 0; i < EXPAND_HEADERS; i++)
        {
            block = headerAllocator.Alloc();
            if (!virtualMemory)
            {
                qglGenBuffersARB(1, &block->vbo);
                block->size = 0;
            }
            block->next = freeStaticHeaders.next;
            block->prev = &freeStaticHeaders;
            block->next->prev = block;
            block->prev->next = block;
        }
    }
    GLenum target = (indexBuffer ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER);
    GLenum usage = (allocatingTempBuffer ? GL_STREAM_DRAW : GL_STATIC_DRAW);

    // try to find a matching block to replace so that we're not continually respecifying vbo data each frame
    for (vertCache_t *findblock = freeStaticHeaders.next; /**/; findblock = findblock->next)
    {
        if (findblock == &freeStaticHeaders)
        {
            block = freeStaticHeaders.next;
            break;
        }
        if (findblock->target != target)
		{ 
			continue; 
		}
        if (findblock->usage != usage)
		{ 
			continue; 
		}
        if (findblock->size != size) 
		{
			continue; 
		}
        block = findblock;
        break;
    }
    // move it from the freeStaticHeaders list to the staticHeaders list
    block->target = target;
    block->usage = usage;
    if (block->vbo)
    {
        // orphan the buffer in case it needs respecifying (it usually will)
        BindIndex(target, block->vbo);
        qglBufferDataARB(target, static_cast<GLsizeiptr>(size), NULL, usage);
        qglBufferDataARB(target, static_cast<GLsizeiptr>(size), data, usage);
    }
    else
    {
        block->virtMem = new byte[size];
        SIMDProcessor->Memcpy(block->virtMem, data, size);
    }
    block->next->prev = block->prev;
    block->prev->next = block->next;
    block->next = staticHeaders.next;
    block->prev = &staticHeaders;
    block->next->prev = block;
    block->prev->next = block;
    block->size = size;
    block->offset = 0;
    block->tag = TAG_USED;
    // save data for debugging
    staticAllocThisFrame += block->size;
    staticCountThisFrame++;
    staticCountTotal++;
    staticAllocTotal += block->size;
    // this will be set to zero when it is purged
    block->user = buffer;
    *buffer = block;
    // allocation doesn't imply used-for-drawing, because at level
    // load time lots of things may be created, but they aren't
    // referenced by the GPU yet, and can be purged if needed.
    block->frameUsed = currentFrame - NUM_VERTEX_FRAMES;
    block->indexBuffer = indexBuffer;
}

/*
===========
idVertexCache::Touch
===========
*/
void idVertexCache::Touch(vertCache_t *block)
{
    if (!block)
    {
        common->Error("idVertexCache Touch: NULL pointer");
    }
    if (block->tag == TAG_FREE)
    {
        common->FatalError("idVertexCache Touch: freed pointer");
    }
    if (block->tag == TAG_TEMP)
    {
        common->FatalError("idVertexCache Touch: temporary pointer");
    }
    block->frameUsed = currentFrame;
    // move to the head of the LRU list
    block->next->prev = block->prev;
    block->prev->next = block->next;
    block->next = staticHeaders.next;
    block->prev = &staticHeaders;
    staticHeaders.next->prev = block;
    staticHeaders.next = block;
}

/*
===========
idVertexCache::Free
===========
*/
void idVertexCache::Free(vertCache_t *block)
{
    if (!block)
    {
        return;
    }
    if (block->tag == TAG_FREE)
    {
        common->FatalError("idVertexCache Free: freed pointer");
    }
    if (block->tag == TAG_TEMP)
    {
        common->FatalError("idVertexCache Free: temporary pointer");
    }
    // this block still can't be purged until the frame count has expired,
    // but it won't need to clear a user pointer when it is
    block->user = NULL;
    block->next->prev = block->prev;
    block->prev->next = block->next;
    block->next = deferredFreeList.next;
    block->prev = &deferredFreeList;
    deferredFreeList.next->prev = block;
    deferredFreeList.next = block;
}

/*
===========
idVertexCache::AllocFrameTemp

A frame temp allocation must never be allowed to fail due to overflow.
We can't simply sync with the GPU and overwrite what we have, because
there may still be future references to dynamically created surfaces.
===========
*/
vertCache_t	*idVertexCache::AllocFrameTemp(void *data, int size)
{
    vertCache_t	*block;
    if (size <= 0)
    {
        common->Error("idVertexCache::AllocFrameTemp: size = %i\n", size);
    }
    if (dynamicAllocThisFrame + size > frameBytes)
    {
        // if we don't have enough room in the temp block, allocate a static block,
        // but immediately free it so it will get freed at the next frame
        tempOverflow = true;
        Alloc(data, size, &block);
        Free(block);
        return block;
    }
    // this data is just going on the shared dynamic list
    // if we don't have any remaining unused headers, allocate some more
    if (freeDynamicHeaders.next == &freeDynamicHeaders)
    {
        for (int i = 0; i < EXPAND_HEADERS; i++)
        {
            block = headerAllocator.Alloc();
            block->next = freeDynamicHeaders.next;
            block->prev = &freeDynamicHeaders;
            block->next->prev = block;
            block->prev->next = block;
        }
    }
    // move it from the freeDynamicHeaders list to the dynamicHeaders list
    block = freeDynamicHeaders.next;
    block->next->prev = block->prev;
    block->prev->next = block->next;
    block->next = dynamicHeaders.next;
    block->prev = &dynamicHeaders;
    block->next->prev = block;
    block->prev->next = block;
    block->size = size;
    block->tag = TAG_TEMP;
    block->indexBuffer = false;
    block->offset = dynamicAllocThisFrame;
    dynamicAllocThisFrame += block->size;
    dynamicCountThisFrame++;
    block->user = NULL;
    block->frameUsed = 0;
    // copy the data
    block->virtMem = tempBuffers[listNum]->virtMem;
    block->vbo = tempBuffers[listNum]->vbo;
    // mh code start
    if (block->vbo)
    {
        BindIndex(GL_ARRAY_BUFFER, block->vbo);
        // try to get an unsynchronized map if at all possible
        if (glConfig.ARBMapBufferRangeAvailable && r_useArbBufferRange.GetBool())
        {
            GLvoid		*dst = NULL;
            GLbitfield	access = (GL_MAP_WRITE_BIT | ((block->offset == 0) ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT) | GL_MAP_INVALIDATE_RANGE_BIT);
            // if the buffer has wrapped then we orphan it
            if ((dst = qglMapBufferRange(GL_ARRAY_BUFFER, block->offset, static_cast<GLsizeiptr>(size), access)) != NULL)
            {
                SIMDProcessor->Memcpy((byte *) dst, data, size);
                qglUnmapBufferARB(GL_ARRAY_BUFFER);
                return block;
            }
            else
            {
                qglBufferSubDataARB(GL_ARRAY_BUFFER, block->offset, static_cast<GLsizeiptr>(size), data);
            }
        }
        else
        {
            qglBufferSubDataARB(GL_ARRAY_BUFFER, block->offset, static_cast<GLsizeiptr>(size), data);
        }
    }
    else
    {
        SIMDProcessor->Memcpy(reinterpret_cast<byte *>(block->virtMem) + block->offset, data, size);
    }
    return block;
}

/*
===========
idVertexCache::EndFrame
===========
*/
void idVertexCache::EndFrame()
{
    // display debug information
    if (r_showVertexCache.GetBool())
    {
        int	staticUseCount = 0;
        int staticUseSize = 0;
        for (vertCache_t *block = staticHeaders.next ; block != &staticHeaders ; block = block->next)
        {
            if (block->frameUsed == currentFrame)
            {
                staticUseCount++;
                staticUseSize += block->size;
            }
        }
        const char *frameOverflow = tempOverflow ? "(OVERFLOW)" : "";
        common->Printf("vertex dynamic:%i=%ik%s, static alloc:%i=%ik used:%i=%ik total:%i=%ik\n",
                       dynamicCountThisFrame, dynamicAllocThisFrame/1024, frameOverflow,
                       staticCountThisFrame, staticAllocThisFrame/1024,
                       staticUseCount, staticUseSize/1024,
                       staticCountTotal, staticAllocTotal/1024);
    }
    if (!virtualMemory)
    {
        // unbind vertex buffers so normal virtual memory will be used in case
        // r_useVertexBuffers / r_useIndexBuffers
        UnbindIndex(GL_ARRAY_BUFFER_ARB);
        UnbindIndex(GL_ELEMENT_ARRAY_BUFFER_ARB);
    }
    currentFrame = tr.frameCount;
    listNum = currentFrame % NUM_VERTEX_FRAMES;
    staticAllocThisFrame = 0;
    staticCountThisFrame = 0;
    dynamicAllocThisFrame = 0;
    dynamicCountThisFrame = 0;
    tempOverflow = false;
    // free all the deferred free headers
    while (deferredFreeList.next != &deferredFreeList)
    {
        ActuallyFree(deferredFreeList.next);
    }
    // free all the frame temp headers
    vertCache_t	*block = dynamicHeaders.next;
    if (block != &dynamicHeaders)
    {
        block->prev = &freeDynamicHeaders;
        dynamicHeaders.prev->next = freeDynamicHeaders.next;
        freeDynamicHeaders.next->prev = dynamicHeaders.prev;
        freeDynamicHeaders.next = block;
        dynamicHeaders.next = dynamicHeaders.prev = &dynamicHeaders;
    }
}

/*
=============
idVertexCache::List
=============
*/
void idVertexCache::List(void)
{
    int	numActive = 0;
    int frameStatic = 0;
    int	totalStatic = 0;
    vertCache_t *block;
    for (block = staticHeaders.next ; block != &staticHeaders ; block = block->next)
    {
        numActive++;
        totalStatic += block->size;
        if (block->frameUsed == currentFrame)
        {
            frameStatic += block->size;
        }
    }
    int	numFreeStaticHeaders = 0;
    for (block = freeStaticHeaders.next ; block != &freeStaticHeaders ; block = block->next)
    {
        numFreeStaticHeaders++;
    }
    int	numFreeDynamicHeaders = 0;
    for (block = freeDynamicHeaders.next ; block != &freeDynamicHeaders ; block = block->next)
    {
        numFreeDynamicHeaders++;
    }
    common->Printf("%i dynamic temp buffers of %ik\n", NUM_VERTEX_FRAMES, frameBytes / 1024);
    common->Printf("%5i active static headers\n", numActive);
    common->Printf("%5i free static headers\n", numFreeStaticHeaders);
    common->Printf("%5i free dynamic headers\n", numFreeDynamicHeaders);
    if (!virtualMemory)
    {
        common->Printf("Vertex cache is in ARB_vertex_buffer_object memory (FAST).\n");
    }
    else
    {
        common->Printf("Vertex cache is in virtual memory (SLOW)\n");
    }
    if (r_useIndexBuffers.GetBool())
    {
        common->Printf("Index buffers are accelerated.\n");
    }
    else
    {
        common->Printf("Index buffers are not used.\n");
    }
}

/*
=============
idVertexCache::ShowMem

Barnes, 
replaces the broken glconfig string version.
=============
*/
void idVertexCache::ShowMem(void)
{
    GLint  mem[4];
    if (strstr(glConfig.extensions_string, "GL_NVX_gpu_memory_info"))
    {
        common->Printf("\nNvidia specific memory info:\n");
        common->Printf("\n");
        qglGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX , mem);
        common->Printf("dedicated video memory %i MB\n", mem[0] >>10);
        qglGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX , mem);
        common->Printf("total available memory %i MB\n", mem[0] >>10);
        qglGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX , mem);
        common->Printf("currently unused GPU memory %i MB\n", mem[0] >>10);
        qglGetIntegerv(GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX , mem);
        common->Printf("count of total evictions seen by system %i MB\n", mem[0] >>10);
        qglGetIntegerv(GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX , mem);
        common->Printf("total video memory evicted %i MB\n", mem[0] >>10);
    }
    else
    {
        if (strstr(glConfig.extensions_string, "GL_ATI_meminfo"))
        {
            common->Printf("\nATI/AMD specific memory info:\n");
            common->Printf("\n");
            qglGetIntegerv(GL_VBO_FREE_MEMORY_ATI, mem);
            common->Printf("VBO: total memory free in the pool %i MB\n", mem[0] >> 10);
            common->Printf("VBO: largest available free block in the pool %i MB\n", mem[1] >> 10);
            common->Printf("VBO: total auxiliary memory free %i MB\n", mem[2] >> 10);
            common->Printf("VBO: largest auxiliary free block %i MB\n", mem[3] >> 10);
            qglGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, mem);
            common->Printf("Texture: total memory free in the pool %i MB\n", mem[0] >> 10);
            common->Printf("Texture: largest available free block in the pool %i MB\n", mem[1] >> 10);
            common->Printf("Texture: total auxiliary memory free %i MB\n", mem[2] >> 10);
            common->Printf("Texture: largest auxiliary free block %i MB\n", mem[3] >> 10);
            qglGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI, mem);
            common->Printf("RenderBuffer: total memory free in the pool %i MB\n", mem[0] >> 10);
            common->Printf("RenderBuffer: largest available free block in the pool %i MB\n", mem[1] >> 10);
            common->Printf("RenderBuffer: total auxiliary memory free %i MB\n", mem[2] >> 10);
            common->Printf("RenderBuffer: largest auxiliary free block %i MB\n", mem[3] >> 10);
        }
        else
        {
            common->Printf("MemInfo not availabled for your video card or driver!\n");
        }
    }
}

/*
=============
idVertexCache::IsFast

just for gfxinfo printing
=============
*/
bool idVertexCache::IsFast()
{
    if (virtualMemory)
    {
        return false;
    }
    return true;
}

Code: Select all

/*
===========================================================================

Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").

Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/

// vertex cache calls should only be made by the front end
const int NUM_VERTEX_FRAMES = 2;

typedef enum
{
    TAG_FREE,
    TAG_USED,
    TAG_FIXED,		// for the temp buffers
    TAG_TEMP		// in frame temp area, not static area
} vertBlockTag_t;

typedef struct vertCache_s
{
    GLuint				vbo;
    GLenum				target;
    GLenum				usage;
    void				*virtMem;			// only one of vbo / virtMem will be set
    bool				indexBuffer;		// holds indexes instead of vertexes

    int					offset;
    int					size;				// may be larger than the amount asked for, due
    // to round up and minimum fragment sizes
    int					tag;				// a tag of 0 is a free block
    struct vertCache_s	**user;				// will be set to zero when purged
    struct vertCache_s	*next, *prev;		// may be on the static list or one of the frame lists
    int					frameUsed;			// it can't be purged if near the current frame
} vertCache_t;

class idVertexCache
{
    public:
        void			Init();
        void			Shutdown();

        // just for gfxinfo printing
        bool			IsFast();

        // called when vertex programs are enabled or disabled, because
        // the cached data is no longer valid
        void			PurgeAll();

        // Tries to allocate space for the given data in fast vertex
        // memory, and copies it over.
        // Alloc does NOT do a touch, which allows purging of things
        // created at level load time even if a frame hasn't passed yet.
        // These allocations can be purged, which will zero the pointer.
        void			Alloc(void *data, int bytes, vertCache_t **buffer, bool indexBuffer = false);

        // This will be a real pointer with virtual memory,
        // but it will be an int offset cast to a pointer of ARB_vertex_buffer_object
        void *			Position(vertCache_t *buffer);

        // initialize the element array buffers
        void			BindIndex(GLenum target, GLuint vbo);

        // if r_useIndexBuffers is enabled, but you need to draw something without
        // an indexCache, this must be called to reset GL_ELEMENT_ARRAY_BUFFER_ARB
        void			UnbindIndex(GLenum target);

        // automatically freed at the end of the next frame
        // used for specular texture coordinates and gui drawing, which
        // will change every frame.
        // will return NULL if the vertex cache is completely full
        // As with Position(), this may not actually be a pointer you can access.
        vertCache_t	*	AllocFrameTemp(void *data, int bytes);

        // notes that a buffer is used this frame, so it can't be purged
        // out from under the GPU
        void			Touch(vertCache_t *buffer);

        // this block won't have to zero a buffer pointer when it is purged,
        // but it must still wait for the frames to pass, in case the GPU
        // is still referencing it
        void			Free(vertCache_t *buffer);

        // updates the counter for determining which temp space to use
        // and which blocks can be purged
        // Also prints debugging info when enabled
        void			EndFrame();

        // listVertexCache calls this
        void			List();

        // showVertexMemory calls this
        void			ShowMem();

    private:
        void			InitMemoryBlocks(int size);
        void			ActuallyFree(vertCache_t *block);

        static idCVar	r_showVertexCache;
        static idCVar	r_useArbBufferRange;
        static idCVar	r_reuseVertexCacheSooner;
        static idCVar	r_freeVertexCache;

        int				staticCountTotal;
        int				staticAllocTotal;		// for end of frame purging

        int				staticAllocThisFrame;	// debug counter
        int				staticCountThisFrame;
        int				dynamicAllocThisFrame;
        int				dynamicCountThisFrame;

        int				currentFrame;			// for purgable block tracking
        int				listNum;				// currentFrame % NUM_VERTEX_FRAMES, determines which tempBuffers to use

        bool			virtualMemory;			// not fast stuff

        bool			allocatingTempBuffer;	// force GL_STREAM_DRAW_ARB

        vertCache_t		*tempBuffers[NUM_VERTEX_FRAMES];		// allocated at startup
        bool			tempOverflow;			// had to alloc a temp in static memory

        idBlockAlloc<vertCache_t,1024>	headerAllocator;

        vertCache_t		freeStaticHeaders;		// head of doubly linked list
        vertCache_t		freeDynamicHeaders;		// head of doubly linked list
        vertCache_t		dynamicHeaders;			// head of doubly linked list
        vertCache_t		deferredFreeList;		// head of doubly linked list
        vertCache_t		staticHeaders;			// head of doubly linked list in MRU order, staticHeaders.next is most recently used
        int				frameBytes;				// for each of NUM_VERTEX_FRAMES frames
};

extern	idVertexCache	vertexCache;
changed from C allocations to C++ allocations eg (new vs malloc delete vs free).
modified existing unbindindex to be used engine wide.
added bindindex.
added cvar to toy with freeing the VBO.
added barnes code for showing videomemory (replaces the crash prone glconfig string crap).

Cleaned up a few Things.
Changed to using C++ casts for pointers.
Productivity is a state of mind.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Post by revelator »

Checked out how many times BindIndex and UnBindIndex tries to allocate an allready allocated VBO and its quite an eye opener :shock: it literally causes the engine to run in slomo if i enable the debug printfs thats how many times it will try and allocate the same buffers yikes.

Heres the revised version of my two functions.

It will only allow allocation in case its not allready allocated same for freeing.

Code: Select all

GLuint vertexBuffer = 0;
GLuint indexBuffer = 0;

/*
===========
idVertexCache::BindIndex
===========
*/
void idVertexCache::BindIndex(GLenum target, GLuint vbo)
{
    if (target == GL_ARRAY_BUFFER)
    {
        if (vertexBuffer == vbo) 
		{ 
			// this happens more often than you might think :(
			//common->DPrintf("BindIndex : Vertex Buffers allready allocated, skipping\n");
			return; 
		}
        qglBindBufferARB(target, vbo);
        vertexBuffer = vbo;
    }
    else if (target == GL_ELEMENT_ARRAY_BUFFER)
    {
        if (indexBuffer == vbo) 
		{ 
			// this happens more often than you might think :(
			//common->DPrintf("BindIndex : Index Buffers allready allocated, skipping\n");
			return; 
		}
        qglBindBufferARB(target, vbo);
        indexBuffer = vbo;
    }
    else
    {
        common->FatalError("BindIndex : unknown buffer target : %i\n", (int) target);
    }
}

/*
===========
idVertexCache::UnbindIndex
===========
*/
void idVertexCache::UnbindIndex(GLenum target)
{
    if (target == GL_ARRAY_BUFFER)
    {
		if (vertexBuffer == 0) 
		{ 
			// this happens more often than you might think :(
			//common->DPrintf("UnbindIndex : Vertex Buffers allready deallocated, skipping\n");
			return; 
		}
        qglBindBufferARB(target, 0);
        vertexBuffer = 0;
    }
    else if (target == GL_ELEMENT_ARRAY_BUFFER)
    {
		if (indexBuffer == 0) 
		{ 
			// this happens more often than you might think :(
			//common->DPrintf("UnbindIndex : Index Buffers allready deallocated, skipping\n");
			return; 
		}
        qglBindBufferARB(target, 0);
        indexBuffer = 0;
    }
    else
    {
        common->FatalError("UnbindIndex : unknown buffer target : %i\n", (int) target);
    }
}
Productivity is a state of mind.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Doom 3 engine release and game code

Post by Spike »

could be worse, could be glTexImage. :s
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Post by revelator »

Heh yeah might be a good way of stalling the engine to check how many times that gets called :S
Productivity is a state of mind.
Sikkpin
Posts: 3
Joined: Mon Jul 16, 2012 5:09 pm

Re: Doom 3 engine release and game code

Post by Sikkpin »

When you say: "Drop in replacement", do you mean this can be used directly with the base gpl code? You don't need any other modifications that you've made to your code base? Also, is there still compatibility/performance issues with Ati hardware when using this?
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Post by revelator »

Pretty much allthough i allways forget that you need to typedef the missing api calls in rendersystem_init.cpp and a few other Places.

Missing stuff here.

at the top of rendersystem_init.cpp just above the comment for

// GL_EXT_depth_bounds_test

put this.

Code: Select all

// ARB_MapBufferRange
PFNGLMAPBUFFERRANGEPROC				qglMapBufferRange;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC			qglFlushMappedBufferRange;
in qgl.h above the same comment.

Code: Select all

// ARB_MapBufferRange
extern PFNGLMAPBUFFERRANGEPROC			qglMapBufferRange;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC		qglFlushMappedBufferRange;
rendersystem.h in the glconfig_t struct yank this in somewhere with the other ARB stuff.

Code: Select all

    bool				ARBMapBufferRangeAvailable;
and back in rendersystem_init.cpp in the R_CheckPortableExtensions function put this somewhere at the end.

Code: Select all

    // ARB_mapbuffer_range
    glConfig.ARBMapBufferRangeAvailable = R_CheckExtension("GL_ARB_map_buffer_range");
    if (glConfig.ARBMapBufferRangeAvailable)
    {
        qglMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) GLimp_ExtensionPointer("glMapBufferRange");
        qglFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) GLimp_ExtensionPointer("glFlushMappedBufferRange");
    }
as far as i been able to determine it had nothing to do with the slowdowns on ATI Cards,
though i newer found the real culprit i suspect it might be due to me changing to GLEW for the opengl api calls (probably a minor screwup somewhere).
i also done a modified dhewm3 with the same code and it runs a ok on ATI.

Get the latest glext.h from khronos and replace the one in Doom3 the old one does not have arbmapbufferrange.
Good to go :)
Productivity is a state of mind.
anonreclaimer
Posts: 21
Joined: Tue Aug 28, 2012 4:36 am

Re: Doom 3 engine release and game code

Post by anonreclaimer »

reckless wrote:Pretty much allthough i allways forget that you need to typedef the missing api calls in rendersystem_init.cpp and a few other Places.

Missing stuff here.

at the top of rendersystem_init.cpp just above the comment for

// GL_EXT_depth_bounds_test

put this.

Code: Select all

// ARB_MapBufferRange
PFNGLMAPBUFFERRANGEPROC				qglMapBufferRange;
PFNGLFLUSHMAPPEDBUFFERRANGEPROC			qglFlushMappedBufferRange;
in qgl.h above the same comment.

Code: Select all

// ARB_MapBufferRange
extern PFNGLMAPBUFFERRANGEPROC			qglMapBufferRange;
extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC		qglFlushMappedBufferRange;
rendersystem.h in the glconfig_t struct yank this in somewhere with the other ARB stuff.

Code: Select all

    bool				ARBMapBufferRangeAvailable;
and back in rendersystem_init.cpp in the R_CheckPortableExtensions function put this somewhere at the end.

Code: Select all

    // ARB_mapbuffer_range
    glConfig.ARBMapBufferRangeAvailable = R_CheckExtension("GL_ARB_map_buffer_range");
    if (glConfig.ARBMapBufferRangeAvailable)
    {
        qglMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) GLimp_ExtensionPointer("glMapBufferRange");
        qglFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) GLimp_ExtensionPointer("glFlushMappedBufferRange");
    }
as far as i been able to determine it had nothing to do with the slowdowns on ATI Cards,
though i newer found the real culprit i suspect it might be due to me changing to GLEW for the opengl api calls (probably a minor screwup somewhere).
i also done a modified dhewm3 with the same code and it runs a ok on ATI.

Get the latest glext.h from khronos and replace the one in Doom3 the old one does not have arbmapbufferrange.
Good to go :)
Cool I'll test it soon.

I saw some stuff in BFG I think you wanna see I don't know if you saw it or not?

Code: Select all

/*
================
R_MipMapWithAlphaSpecularity

Returns a new copy of the texture, quartered in size and filtered.
The alpha channel is taken to be the minimum of the dots of all surrounding normals.
================
*/
#define MIP_MIN(a,b) (a<b?a:b)

byte *R_MipMapWithAlphaSpecularity( const byte *in, int width, int height ) {
	int		i, j, c, x, y, sx, sy;
	const byte	*in_p;
	byte	*out, *out_p;
	int		row;
	int		newWidth, newHeight;
	float	*fbuf, *fbuf_p;

	if ( width < 1 || height < 1 || ( width + height == 2 ) ) {
		common->FatalError( "R_MipMapWithAlphaMin called with size %i,%i", width, height );
	}

	// convert the incoming texture to centered floating point
	c = width * height;
	fbuf = (float *)_alloca( c * 4 * sizeof( *fbuf ) );
	in_p = in;
	fbuf_p = fbuf;
	for ( i = 0 ; i < c ; i++, in_p+=4, fbuf_p += 4 ) {
		fbuf_p[0] = ( in_p[0] / 255.0 ) * 2.0 - 1.0;	// convert to a normal
		fbuf_p[1] = ( in_p[1] / 255.0 ) * 2.0 - 1.0;
		fbuf_p[2] = ( in_p[2] / 255.0 ) * 2.0 - 1.0;
		fbuf_p[3] = ( in_p[3] / 255.0 );				// filtered divegence / specularity
	}

	row = width * 4;

	newWidth = width >> 1;
	newHeight = height >> 1;
	if ( !newWidth ) {
		newWidth = 1;
	}
	if ( !newHeight ) {
		newHeight = 1;
	}
	out = (byte *)R_StaticAlloc( newWidth * newHeight * 4 );
	out_p = out;

	in_p = in;

	for ( i=0 ; i<newHeight ; i++ ) {
		for ( j=0 ; j<newWidth ; j++, out_p+=4 ) {
			idVec3	total;
			float	totalSpec;

			total.Zero();
			totalSpec = 0;
			// find the average normal
			for ( x = -1 ; x <= 1 ; x++ ) {
				sx = ( j * 2 + x ) & (width-1);
				for ( y = -1 ; y <= 1 ; y++ ) {
					sy = ( i * 2 + y ) & (height-1);
					fbuf_p = fbuf + ( sy * width + sx ) * 4;

					total[0] += fbuf_p[0];
					total[1] += fbuf_p[1];
					total[2] += fbuf_p[2];

					totalSpec += fbuf_p[3];
				}
			}
			total.Normalize();
			totalSpec /= 9.0;

			// find the maximum divergence
			for ( x = -1 ; x <= 1 ; x++ ) {
				for ( y = -1 ; y <= 1 ; y++ ) {
				}
			}

			// store the average normal and divergence
		}
	}

	return out;
}

float mip_gammaTable[256] = {
	0.000000f, 0.000005f, 0.000023f, 0.000057f, 0.000107f, 0.000175f, 0.000262f, 0.000367f, 0.000493f, 0.000638f, 0.000805f, 0.000992f, 0.001202f, 0.001433f, 0.001687f, 0.001963f,
	0.002263f, 0.002586f, 0.002932f, 0.003303f, 0.003697f, 0.004116f, 0.004560f, 0.005028f, 0.005522f, 0.006041f, 0.006585f, 0.007155f, 0.007751f, 0.008373f, 0.009021f, 0.009696f,
	0.010398f, 0.011126f, 0.011881f, 0.012664f, 0.013473f, 0.014311f, 0.015175f, 0.016068f, 0.016988f, 0.017936f, 0.018913f, 0.019918f, 0.020951f, 0.022013f, 0.023104f, 0.024223f,
	0.025371f, 0.026549f, 0.027755f, 0.028991f, 0.030257f, 0.031551f, 0.032876f, 0.034230f, 0.035614f, 0.037029f, 0.038473f, 0.039947f, 0.041452f, 0.042987f, 0.044553f, 0.046149f,
	0.047776f, 0.049433f, 0.051122f, 0.052842f, 0.054592f, 0.056374f, 0.058187f, 0.060032f, 0.061907f, 0.063815f, 0.065754f, 0.067725f, 0.069727f, 0.071761f, 0.073828f, 0.075926f,
	0.078057f, 0.080219f, 0.082414f, 0.084642f, 0.086901f, 0.089194f, 0.091518f, 0.093876f, 0.096266f, 0.098689f, 0.101145f, 0.103634f, 0.106156f, 0.108711f, 0.111299f, 0.113921f,
	0.116576f, 0.119264f, 0.121986f, 0.124741f, 0.127530f, 0.130352f, 0.133209f, 0.136099f, 0.139022f, 0.141980f, 0.144972f, 0.147998f, 0.151058f, 0.154152f, 0.157281f, 0.160444f,
	0.163641f, 0.166872f, 0.170138f, 0.173439f, 0.176774f, 0.180144f, 0.183549f, 0.186989f, 0.190463f, 0.193972f, 0.197516f, 0.201096f, 0.204710f, 0.208360f, 0.212044f, 0.215764f,
	0.219520f, 0.223310f, 0.227137f, 0.230998f, 0.234895f, 0.238828f, 0.242796f, 0.246800f, 0.250840f, 0.254916f, 0.259027f, 0.263175f, 0.267358f, 0.271577f, 0.275833f, 0.280124f,
	0.284452f, 0.288816f, 0.293216f, 0.297653f, 0.302126f, 0.306635f, 0.311181f, 0.315763f, 0.320382f, 0.325037f, 0.329729f, 0.334458f, 0.339223f, 0.344026f, 0.348865f, 0.353741f,
	0.358654f, 0.363604f, 0.368591f, 0.373615f, 0.378676f, 0.383775f, 0.388910f, 0.394083f, 0.399293f, 0.404541f, 0.409826f, 0.415148f, 0.420508f, 0.425905f, 0.431340f, 0.436813f,
	0.442323f, 0.447871f, 0.453456f, 0.459080f, 0.464741f, 0.470440f, 0.476177f, 0.481952f, 0.487765f, 0.493616f, 0.499505f, 0.505432f, 0.511398f, 0.517401f, 0.523443f, 0.529523f,
	0.535642f, 0.541798f, 0.547994f, 0.554227f, 0.560499f, 0.566810f, 0.573159f, 0.579547f, 0.585973f, 0.592438f, 0.598942f, 0.605484f, 0.612066f, 0.618686f, 0.625345f, 0.632043f,
	0.638779f, 0.645555f, 0.652370f, 0.659224f, 0.666117f, 0.673049f, 0.680020f, 0.687031f, 0.694081f, 0.701169f, 0.708298f, 0.715465f, 0.722672f, 0.729919f, 0.737205f, 0.744530f,
	0.751895f, 0.759300f, 0.766744f, 0.774227f, 0.781751f, 0.789314f, 0.796917f, 0.804559f, 0.812241f, 0.819964f, 0.827726f, 0.835528f, 0.843370f, 0.851252f, 0.859174f, 0.867136f,
	0.875138f, 0.883180f, 0.891262f, 0.899384f, 0.907547f, 0.915750f, 0.923993f, 0.932277f, 0.940601f, 0.948965f, 0.957370f, 0.965815f, 0.974300f, 0.982826f, 0.991393f, 1.000000f
};

Code: Select all

/*
================
R_MipMapGamma

Returns a new copy of the texture, quartered in size with gamma correction.
================
*/
byte * R_MipMapWithGamma( const byte *in, int width, int height ) {
	int		i, j;
	const byte	*in_p;
	byte	*out, *out_p;
	int		row;
	int		newWidth, newHeight;

	if ( width < 1 || height < 1 || ( width + height == 2 ) ) {
		return NULL;
	}

	row = width * 4;

	newWidth = width >> 1;
	newHeight = height >> 1;
	if ( !newWidth ) {
		newWidth = 1;
	}
	if ( !newHeight ) {
		newHeight = 1;
	}
	out = (byte *)R_StaticAlloc( newWidth * newHeight * 4 );
	out_p = out;

	in_p = in;

	width >>= 1;
	height >>= 1;

	if ( width == 0 || height == 0 ) {
		width += height;	// get largest
		for (i=0 ; i<width ; i++, out_p+=4, in_p+=8 ) {
			out_p[0] = idMath::Ftob( 255.0f * idMath::Pow( 0.5f * ( mip_gammaTable[in_p[0]] + mip_gammaTable[in_p[4]] ), 1.0f / 2.2f ) );
			out_p[1] = idMath::Ftob( 255.0f * idMath::Pow( 0.5f * ( mip_gammaTable[in_p[1]] + mip_gammaTable[in_p[5]] ), 1.0f / 2.2f ) );
			out_p[2] = idMath::Ftob( 255.0f * idMath::Pow( 0.5f * ( mip_gammaTable[in_p[2]] + mip_gammaTable[in_p[6]] ), 1.0f / 2.2f ) );
			out_p[3] = idMath::Ftob( 255.0f * idMath::Pow( 0.5f * ( mip_gammaTable[in_p[3]] + mip_gammaTable[in_p[7]] ), 1.0f / 2.2f ) );
		}
		return out;
	}
	for (i=0 ; i<height ; i++, in_p+=row) {
		for (j=0 ; j<width ; j++, out_p+=4, in_p+=8) {
			out_p[0] = idMath::Ftob( 255.0f * idMath::Pow( 0.25f * ( mip_gammaTable[in_p[0]] + mip_gammaTable[in_p[4]] + mip_gammaTable[in_p[row+0]] + mip_gammaTable[in_p[row+4]] ), 1.0f / 2.2f ) );
			out_p[1] = idMath::Ftob( 255.0f * idMath::Pow( 0.25f * ( mip_gammaTable[in_p[1]] + mip_gammaTable[in_p[5]] + mip_gammaTable[in_p[row+1]] + mip_gammaTable[in_p[row+5]] ), 1.0f / 2.2f ) );
			out_p[2] = idMath::Ftob( 255.0f * idMath::Pow( 0.25f * ( mip_gammaTable[in_p[2]] + mip_gammaTable[in_p[6]] + mip_gammaTable[in_p[row+2]] + mip_gammaTable[in_p[row+6]] ), 1.0f / 2.2f ) );
			out_p[3] = idMath::Ftob( 255.0f * idMath::Pow( 0.25f * ( mip_gammaTable[in_p[3]] + mip_gammaTable[in_p[7]] + mip_gammaTable[in_p[row+3]] + mip_gammaTable[in_p[row+7]] ), 1.0f / 2.2f ) );
		}
	}

	return out;
}
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Post by revelator »

Didnt notice that one :) thanks.
Productivity is a state of mind.
anonreclaimer
Posts: 21
Joined: Tue Aug 28, 2012 4:36 am

Re: Doom 3 engine release and game code

Post by anonreclaimer »

reckless wrote:check this out ;)

Image
Hey reckless what is this map called I would like to know and where I can get it?
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: Doom 3 engine release and game code

Post by revelator »

Sorry for the late reply. Tbh i dont remember where i got it :S but i was searching Google for Doom3 outdoor maps and i found this in some thread, so try that :).

Might not reply back for a while im waiting for surgery :S gallstones was obviously not enough i also had kidney stones :evil:
Productivity is a state of mind.
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: Doom 3 engine release and game code

Post by frag.machine »

Ugh... Good luck with your surgery. :(
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
Post Reply