/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at
golgotha_source@usa.net (Subject should have "GOLG" in it)
***********************************************************************/
#include "software/r1_software_texture.hh"
#include "video/win32/dx5.hh"
#include "time/profile.hh"
#include "r1_res.hh"
i4_profile_class pf_software_install_vram("software install vram texture");
i4_profile_class pf_software_free_vram("software free vram texture");
r1_software_texture_class *r1_software_texture_class_instance=0;
r1_software_texture_class::r1_software_texture_class(const i4_pal *pal)
: r1_texture_manager_class(pal),finished_array(16,16)
{
r1_software_texture_class_instance = this;
tex_heap_man = 0;
texture_heap = 0;
init();
min_texture_dimention = 1;
max_texture_dimention = r1_max_texture_size;
//setup the texture formats
regular_format = pal->source;
chroma_format = regular_format;
alpha_format.red_mask = 15 << 8;
alpha_format.green_mask = 15 << 4;
alpha_format.blue_mask = 15;
alpha_format.alpha_mask = 15 << 12;
alpha_format.lookup = 0;
alpha_format.calc_shift();
alpha_format.pixel_depth = I4_16BIT;
}
void r1_software_texture_class::init()
{
r1_texture_manager_class::init();
int tex_mem_size = 1024*1024*8;
if (i4_available()/4 < tex_mem_size)
tex_mem_size=i4_available()/4;
i4_warning("Software texture memory heap allocated: %d bytes", tex_mem_size);
texture_heap = (w8 *)i4_malloc(tex_mem_size,"software texture memory heap");
tex_heap_man = new r1_texture_heap_class(tex_mem_size,
(w32)texture_heap,
sizeof(free_node),
sizeof(used_node),
&frame_count);
array_lock.lock();
array_lock.unlock();
bytes_loaded = 0;
textures_loaded = 0;
}
void r1_software_texture_class::uninit()
{
if (tex_heap_man)
{
delete tex_heap_man;
tex_heap_man = 0;
}
if (texture_heap)
{
i4_warning("Software texture memory heap deallocated: 8 megs");
i4_free(texture_heap);
texture_heap = 0;
}
r1_texture_manager_class::uninit();
}
i4_bool r1_software_texture_class::immediate_mip_load(r1_mip_load_info *load_info)
{
if (textures_loaded > 0)
{
if (load_info->dest_mip->last_frame_used != -1)
{
load_info->error = R1_MIP_LOAD_BUSY;
return i4_F;
}
}
pf_software_install_vram.start();
r1_miplevel_t *mip = load_info->dest_mip;
sw32 i,need_size;
need_size = mip->width * mip->height * 2;
used_node *new_used = (used_node *)tex_heap_man->alloc(need_size);
if (!new_used)
{
pf_software_install_vram.stop();
load_info->error = R1_MIP_LOAD_NO_ROOM;
return i4_F;
}
free_node *f = (free_node *)new_used->node;
//f is the node we'll use
if (load_info->src_file)
{
load_info->src_file->read((w16 *)f->start,mip->width*mip->height*2);
}
else
{
i4_str *fn = r1_texture_id_to_filename(mip->entry->id, r1_get_decompressed_dir());
i4_file_class *fp = i4_open(*fn);
delete fn;
fp->seek(mip->entry->file_offsets[mip->level]+8);
fp->read((w16 *)f->start,mip->width*mip->height*2);
delete fp;
}
bytes_loaded += mip->width*mip->height*2;
textures_loaded++;
//load the texture
f->mip = mip;
mip->vram_handle = new_used;
if (mip->last_frame_used != -1)
mip->last_frame_used = frame_count;
pf_software_install_vram.stop();
return i4_T;
}
static i4_critical_section_class num_async_pending_lock;
static int num_async_pending=0;
r1_software_texture_class::~r1_software_texture_class()
{
while (num_async_pending!=0)
i4_sleep(0);
uninit();
}
//typedef void (*async_callback)(w32 count, void *context);
void software_async_callback(w32 count, void *context)
{
r1_software_texture_class::used_node *u = (r1_software_texture_class::used_node *)context;
r1_software_texture_class::free_node *f = (r1_software_texture_class::free_node *)u->node;
if (f->async_fp)
delete f->async_fp;
f->async_fp = 0;
if (count != f->mip->width*f->mip->height*2)
i4_warning("async texture read failure");
r1_software_texture_class_instance->async_load_finished(u);
num_async_pending_lock.lock();
num_async_pending--;
num_async_pending_lock.unlock();
}
i4_bool r1_software_texture_class::async_mip_load(r1_mip_load_info *load_info)
{
if (bytes_loaded > 32768 || textures_loaded > 16)
{
if (load_info->dest_mip->last_frame_used != -1)
{
load_info->error = R1_MIP_LOAD_BUSY;
return i4_F;
}
}
pf_software_install_vram.start();
sw32 i;
r1_miplevel_t *mip = load_info->dest_mip;
w32 need_size = mip->width * mip->height * 2;
used_node *new_used = (used_node *)tex_heap_man->alloc(need_size,R1_TEX_HEAP_DONT_LIST);
if (!new_used)
{
pf_software_install_vram.stop();
load_info->error = R1_MIP_LOAD_NO_ROOM;
return i4_F;
}
//f is the node we'll use
free_node *f = (free_node *)new_used->node;
f->mip = mip;
f->async_fp = 0;
mip->flags |= R1_MIPLEVEL_IS_LOADING;
i4_bool async_worked;
num_async_pending_lock.lock();
num_async_pending++;
num_async_pending_lock.unlock();
if (load_info->src_file)
{
async_worked = load_info->src_file->async_read((w16 *)f->start,mip->width*mip->height*2,software_async_callback,new_used);
}
else
{
i4_str *fn = r1_texture_id_to_filename(mip->entry->id,r1_get_decompressed_dir());
i4_file_class *fp = i4_open(*fn,I4_READ | I4_NO_BUFFER | I4_SUPPORT_ASYNC);
delete fn;
if (!fp)
async_worked = i4_F;
else
{
f->async_fp = fp;
fp->seek(mip->entry->file_offsets[mip->level]+8);
async_worked = fp->async_read((w16 *)f->start,mip->width*mip->height*2,software_async_callback,new_used);
}
}
if (!async_worked)
{
if (f->async_fp)
delete f->async_fp;
mip->flags &= (~R1_MIPLEVEL_IS_LOADING);
tex_heap_man->free((r1_tex_heap_used_node *)new_used);
load_info->error = R1_MIP_LOAD_BUSY;
pf_software_install_vram.stop();
num_async_pending_lock.lock();
num_async_pending--;
num_async_pending_lock.unlock();
return i4_F;
}
bytes_loaded += mip->width*mip->height*2;
textures_loaded++;
pf_software_install_vram.stop();
return i4_T;
}
void r1_software_texture_class::async_load_finished(used_node *u)
{
array_lock.lock();
finished_array.add(u);
array_lock.unlock();
}
void r1_software_texture_class::next_frame()
{
r1_texture_manager_class::next_frame();
sw32 i;
array_lock.lock();
for (i=0; inode;
//this officially puts it in vram
f->mip->vram_handle = u;
f->mip->flags &= (~R1_MIPLEVEL_IS_LOADING);
if (f->mip->last_frame_used != -1)
f->mip->last_frame_used = frame_count;
//this adds it into the list of used nodes
tex_heap_man->update_usage((r1_tex_heap_used_node *)u);
}
finished_array.clear();
array_lock.unlock();
if (tex_heap_man->needs_cleanup)
{
tex_heap_man->free_really_old();
}
bytes_loaded = 0;
textures_loaded = 0;
}
void r1_software_texture_class::free_mip(r1_vram_handle_type vram_handle)
{
pf_software_free_vram.start();
tex_heap_man->free((r1_tex_heap_used_node *)vram_handle);
pf_software_free_vram.stop();
}
void r1_software_texture_class::select_texture(r1_vram_handle_type handle,
float &smul, float &tmul)
{
r1_tex_heap_used_node *u = (r1_tex_heap_used_node *)handle;
free_node *f = (free_node *)u->node;
smul = f->mip->width;
tmul = f->mip->height;
}
r1_miplevel_t *r1_software_texture_class::get_texture(r1_texture_handle handle,
w32 frame_counter,
sw32 desired_width,
sw32 &w, sw32 &h)
{
r1_miplevel_t *mip = r1_texture_manager_class::get_texture(handle,frame_counter,desired_width,w,h);
if (!mip)
return 0;
r1_tex_heap_used_node *u = (r1_tex_heap_used_node *)mip->vram_handle;
if (u)
tex_heap_man->update_usage(u);
return mip;
}