Merge remote-tracking branch 'upstream/master'

This commit is contained in:
John Cote 2026-01-30 20:16:19 -05:00
commit 0661574448
No known key found for this signature in database
GPG Key ID: A5250CCD017DFCA5
32 changed files with 1620 additions and 37922 deletions

View File

@ -20,7 +20,7 @@ jobs:
include:
- profile: ubuntu-bionic-double-standard-unity-makefile
os: ubuntu-22.04
os: ubuntu-24.04
config: Standard
unity: YES
generator: Unix Makefiles
@ -32,7 +32,7 @@ jobs:
asan: YES
- profile: ubuntu-bionic-coverage-ninja
os: ubuntu-22.04
os: ubuntu-24.04
config: Coverage
unity: NO
generator: Ninja
@ -404,12 +404,12 @@ jobs:
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
strategy:
matrix:
os: [ubuntu-22.04, windows-2022, macOS-15]
os: [ubuntu-24.04, windows-2022, macOS-15]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Install dependencies (Ubuntu)
if: matrix.os == 'ubuntu-22.04'
if: matrix.os == 'ubuntu-24.04'
run: |
sudo apt-get update
sudo apt-get install build-essential bison flex libfreetype6-dev libgl1-mesa-dev libjpeg-dev libode-dev libopenal-dev libpng-dev libssl-dev libvorbis-dev libx11-dev libxcursor-dev libxrandr-dev nvidia-cg-toolkit zlib1g-dev

View File

@ -1,5 +1,5 @@
import os
import imp
import importlib.util
class FileMgr:
@ -32,10 +32,10 @@ class FileMgr:
f.write(data)
f.write('\n')
f.close()
self.editor.updateStatusReadout('Sucessfully saved to %s'%fileName)
self.editor.updateStatusReadout(f'Sucessfully saved to {fileName}')
self.editor.fNeedToSave = False
except IOError:
print('failed to save %s'%fileName)
print(f'failed to save {fileName}')
if f:
f.close()
@ -43,10 +43,11 @@ class FileMgr:
dirname, moduleName = os.path.split(fileName)
if moduleName.endswith('.py'):
moduleName = moduleName[:-3]
file, pathname, description = imp.find_module(moduleName, [dirname])
spec = importlib.util.spec_from_file_location(moduleName, fileName)
try:
module = imp.load_module(moduleName, file, pathname, description)
self.editor.updateStatusReadout('Sucessfully opened file %s'%fileName)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
self.editor.updateStatusReadout(f'Sucessfully opened file {fileName}')
self.editor.fNeedToSave = False
except Exception:
print('failed to load %s'%fileName)
print(f'failed to load {fileName}')

View File

@ -1,4 +1,4 @@
import imp
import importlib.util
class LevelLoaderBase:
@ -30,10 +30,15 @@ class LevelLoaderBase:
if fileName.endswith('.py'):
fileName = fileName[:-3]
file, pathname, description = imp.find_module(fileName, [filePath])
try:
module = imp.load_module(fileName, file, pathname, description)
spec = importlib.util.spec_from_file_location(fileName, filePath)
if spec is None or spec.loader is None:
raise ImportError
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return True
except Exception:
print('failed to load %s'%fileName)
print(f'failed to load {fileName}')
return None

View File

@ -2,7 +2,7 @@
Palette for Prototyping
"""
import os
import imp
import importlib.util
class ProtoObjs:
@ -15,8 +15,13 @@ class ProtoObjs:
def populate(self):
moduleName = self.name
try:
file, pathname, description = imp.find_module(moduleName, [self.dirname])
module = imp.load_module(moduleName, file, pathname, description)
pathname = self.dirname + self.filename
spec = importlib.util.spec_from_file_location(moduleName, pathname)
if spec is None or spec.loader is None:
raise ImportError
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
self.data = module.protoData
except Exception:
print(f"{self.name} doesn't exist")

View File

@ -1,7 +1,8 @@
"""
Palette for Prototyping
"""
import imp
import importlib.util
import os, sys
from .ObjectPaletteBase import ObjectBase, ObjectPaletteBase
@ -23,8 +24,15 @@ class ProtoPaletteBase(ObjectPaletteBase):
def populate(self):
moduleName = 'protoPaletteData'
try:
file, pathname, description = imp.find_module(moduleName, [self.dirname])
module = imp.load_module(moduleName, file, pathname, description)
pathname = os.path.join(self.dirname, moduleName + ".py")
spec = importlib.util.spec_from_file_location(moduleName, pathname)
if spec is None or spec.loader is None:
raise ImportError
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
self.data = module.protoData
self.dataStruct = module.protoDataStruct
except:

View File

@ -39,6 +39,8 @@ public:
virtual ~CocoaGLGraphicsStateGuardian();
virtual bool make_current();
INLINE void lock_context();
INLINE void unlock_context();

View File

@ -297,6 +297,18 @@ choose_pixel_format(const FrameBufferProperties &properties,
}
}
/**
* Ensures that the context is current. May return false if the context cannot
* be bound without a window.
*/
bool CocoaGLGraphicsStateGuardian::
make_current() {
lock_context();
[_context makeCurrentContext];
unlock_context();
return true;
}
/**
* Queries the runtime version of OpenGL in use.
*/

View File

@ -1206,6 +1206,7 @@ dispatch_compute(const LVecBase3i &work_groups, const RenderState *state, Graphi
nassertv(gsg != nullptr);
run_on_draw_thread([=] () {
gsg->make_current();
gsg->push_group_marker(std::string("Compute ") + shader->get_filename(Shader::ST_compute).get_basename());
gsg->set_state_and_transform(state, TransformState::make_identity());
gsg->dispatch_compute(work_groups[0], work_groups[1], work_groups[2]);

View File

@ -3084,6 +3084,15 @@ reset() {
_is_valid = true;
}
/**
* Ensures that the context is current. May return false if the context cannot
* be bound without a window.
*/
bool GraphicsStateGuardian::
make_current() {
return false;
}
/**
* Simultaneously resets the render state and the transform state.
*

View File

@ -421,6 +421,7 @@ public:
INLINE bool reset_if_new();
INLINE void mark_new();
virtual void reset();
virtual bool make_current();
INLINE CPT(TransformState) get_external_transform() const;
INLINE CPT(TransformState) get_internal_transform() const;

View File

@ -280,12 +280,36 @@ void eglGraphicsStateGuardian::
reset() {
BaseGraphicsStateGuardian::reset();
#ifdef OPENGLES
_supports_surfaceless = has_extension("GL_OES_surfaceless_context") &&
#else
_supports_surfaceless =
#endif
has_extension("EGL_KHR_surfaceless_context");
if (_gl_renderer == "Software Rasterizer") {
_fbprops.set_force_software(1);
_fbprops.set_force_hardware(0);
}
}
/**
* Ensures that the context is current. May return false if the context cannot
* be bound without a window.
*/
bool eglGraphicsStateGuardian::
make_current() {
if (eglGetCurrentContext() == _context) {
return true;
}
if (_supports_surfaceless) {
return eglMakeCurrent(_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, _context) != EGL_FALSE;
}
return false;
}
/**
* Returns true if the runtime GLX version number is at least the indicated
* value, false otherwise.
@ -377,3 +401,12 @@ void *eglGraphicsStateGuardian::
do_get_extension_func(const char *name) {
return (void *)eglGetProcAddress(name);
}
/**
* Returns true if this implementation may support Cg shaders.
*/
bool eglGraphicsStateGuardian::
may_support_cg_shaders() {
// Never supported under EGL as CgGL is hard-wired to use GLX functions.
return false;
}

View File

@ -49,6 +49,7 @@ public:
virtual ~eglGraphicsStateGuardian();
virtual void reset();
virtual bool make_current();
bool egl_is_at_least_version(int major_version, int minor_version) const;
@ -60,6 +61,7 @@ public:
#endif
EGLConfig _fbconfig;
FrameBufferProperties _fbprops;
bool _supports_surfaceless = false;
protected:
virtual void gl_flush() const;
@ -68,6 +70,7 @@ protected:
virtual void query_gl_version();
virtual void get_extra_extensions();
virtual void *do_get_extension_func(const char *name);
virtual bool may_support_cg_shaders();
private:
int _egl_version_major, _egl_version_minor;

View File

@ -2059,7 +2059,8 @@ reset() {
// Check for support for other types of shaders that can be used by Cg.
_supports_basic_shaders = false;
#if defined(HAVE_CG) && !defined(OPENGLES)
if (has_extension("GL_ARB_vertex_program") &&
if (may_support_cg_shaders() &&
has_extension("GL_ARB_vertex_program") &&
has_extension("GL_ARB_fragment_program")) {
_supports_basic_shaders = true;
_shader_caps._active_vprofile = (int)CG_PROFILE_ARBVP1;
@ -3997,8 +3998,8 @@ reset() {
}
_auto_detect_shader_model = _shader_model;
if (GLCAT.is_debug()) {
#ifdef HAVE_CG
if (GLCAT.is_debug() && may_support_cg_shaders()) {
#if CG_VERSION_NUM >= 2200
GLCAT.debug() << "Supported Cg profiles:\n";
int num_profiles = cgGetNumSupportedProfiles();
@ -4036,8 +4037,10 @@ reset() {
GLCAT.debug()
<< "Cg active geometry profile = "
<< cgGetProfileString((CGprofile)_shader_caps._active_gprofile) << "\n";
}
#endif // HAVE_CG
if (GLCAT.is_debug()) {
GLCAT.debug() << "shader model = " << _shader_model << "\n";
}
#endif // !OPENGLES
@ -7027,6 +7030,22 @@ prepare_shader(Shader *se) {
void CLP(GraphicsStateGuardian)::
release_shader(ShaderContext *sc) {
#ifndef OPENGLES_1
if (_vertex_array_shader_context == sc) {
_vertex_array_shader = nullptr;
_vertex_array_shader_context = nullptr;
}
if (_texture_binding_shader_context == sc) {
_texture_binding_shader = nullptr;
_texture_binding_shader_context = nullptr;
}
if (_current_shader_context == sc) {
sc->unbind();
_current_shader = nullptr;
_current_shader_context = nullptr;
}
if (sc->is_of_type(CLP(ShaderContext)::get_class_type())) {
((CLP(ShaderContext) *)sc)->release_resources();
}
@ -7035,7 +7054,7 @@ release_shader(ShaderContext *sc) {
((CLP(CgShaderContext) *)sc)->release_resources();
}
#endif
#endif
#endif // !OPENGLES_1
delete sc;
}
@ -10236,6 +10255,18 @@ do_get_extension_func(const char *) {
return nullptr;
}
/**
* Returns true if this implementation may support Cg shaders.
*/
bool CLP(GraphicsStateGuardian)::
may_support_cg_shaders() {
#if defined(HAVE_CG) && !defined(OPENGLES)
return true;
#else
return false;
#endif
}
/**
* Sets up the glDrawBuffer to render into the buffer indicated by the
* RenderBuffer object. This only sets up the color and aux bits; it does not

View File

@ -525,6 +525,7 @@ protected:
INLINE bool is_at_least_gles_version(int major_version, int minor_version) const;
void *get_extension_func(const char *name);
virtual void *do_get_extension_func(const char *name);
virtual bool may_support_cg_shaders();
virtual void reissue_transforms();

View File

@ -413,7 +413,8 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
_glgsg->report_my_gl_errors();
// Restore the active shader.
if (_glgsg->_current_shader_context == nullptr) {
if (_glgsg->_current_shader_context == nullptr ||
!_glgsg->_current_shader_context->valid()) {
_glgsg->_glUseProgram(0);
} else {
_glgsg->_current_shader_context->bind(_glgsg);
@ -2185,7 +2186,7 @@ release_resources() {
*/
bool CLP(ShaderContext)::
valid() {
if (_shader->get_error_flag()) {
if (_shader == nullptr || _shader->get_error_flag()) {
return false;
}
return (_glsl_program != 0);
@ -2197,6 +2198,8 @@ valid() {
*/
void CLP(ShaderContext)::
bind(GraphicsStateGuardian *gsg) {
nassertv(_shader != nullptr);
CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)gsg;
_glgsg = glgsg;
@ -3314,6 +3317,9 @@ glsl_compile_and_link() {
_glsl_shaders.clear();
_glsl_program = _glgsg->_glCreateProgram();
if (!_glsl_program) {
// If this happens, check whether you have a current GL context
GLCAT.error()
<< "Failed to create GLSL program object\n";
return false;
}

View File

@ -434,6 +434,19 @@ choose_pixel_format(const FrameBufferProperties &properties,
_context_has_pbuffer = false;
}
/**
* Ensures that the context is current. May return false if the context cannot
* be bound without a window.
*/
bool glxGraphicsStateGuardian::
make_current() {
if (glXGetCurrentContext() == _context) {
return true;
}
return false;
}
/**
* Returns true if the runtime GLX version number is at least the indicated
* value, false otherwise.
@ -572,6 +585,18 @@ do_get_extension_func(const char *name) {
return PosixGraphicsStateGuardian::do_get_extension_func(name);
}
/**
* Returns true if this implementation may support Cg shaders.
*/
bool glxGraphicsStateGuardian::
may_support_cg_shaders() {
#ifdef HAVE_CG
return true;
#else
return false;
#endif
}
/**
* Queries the GLX extension pointers.
*/

View File

@ -88,6 +88,8 @@ public:
virtual ~glxGraphicsStateGuardian();
virtual bool make_current();
bool glx_is_at_least_version(int major_version, int minor_version) const;
GLXContext _share_context;
@ -128,6 +130,7 @@ protected:
virtual void query_gl_version();
virtual void get_extra_extensions();
virtual void *do_get_extension_func(const char *name);
virtual bool may_support_cg_shaders();
private:
void query_glx_extensions();

View File

@ -131,6 +131,18 @@ compare_to_impl(const RenderAttrib *other) const {
return (int)_b - (int)ta->_b;
}
if (_alpha_mode != ta->_alpha_mode) {
return (int)_alpha_mode - (int)ta->_alpha_mode;
}
if (_alpha_a != ta->_alpha_a) {
return (int)_alpha_a - (int)ta->_alpha_a;
}
if (_alpha_b != ta->_alpha_b) {
return (int)_alpha_b - (int)ta->_alpha_b;
}
return _color.compare_to(ta->_color);
}
@ -146,6 +158,9 @@ get_hash_impl() const {
hash = int_hash::add_hash(hash, (int)_mode);
hash = int_hash::add_hash(hash, (int)_a);
hash = int_hash::add_hash(hash, (int)_b);
hash = int_hash::add_hash(hash, (int)_alpha_mode);
hash = int_hash::add_hash(hash, (int)_alpha_a);
hash = int_hash::add_hash(hash, (int)_alpha_b);
hash = _color.add_hash(hash);
return hash;

View File

@ -27,7 +27,7 @@ void gl_transform_to_viewport(GLContext *c,GLVertex *v)
+ c->viewport.trans.v[2] );
// Add the z-bias, if any. Be careful not to overflow the int.
int z = v->zp.z + (c->zbias << (ZB_POINT_Z_FRAC_BITS + 4));
int z = v->zp.z + c->zbias;
if (z < v->zp.z && c->zbias > 0) {
v->zp.z = INT_MAX;
} else if (z > v->zp.z && c->zbias < 0) {

View File

@ -24,10 +24,50 @@ FNAME(store_pixel) (ZBuffer *zb, PIXEL &result, int r, int g, int b, int a) {
unsigned int fb = PIXEL_B(result);
unsigned int fa = PIXEL_A(result);
r = STORE_PIXEL_0(fr, ((unsigned int)r * OP_A(fr, r) >> 16) + ((unsigned int)fr * OP_B(fr, r) >> 16));
g = STORE_PIXEL_1(fg, ((unsigned int)g * OP_A(fg, g) >> 16) + ((unsigned int)fg * OP_B(fg, g) >> 16));
b = STORE_PIXEL_2(fb, ((unsigned int)b * OP_A(fb, b) >> 16) + ((unsigned int)fb * OP_B(fb, b) >> 16));
a = STORE_PIXEL_3(fa, ((unsigned int)a * OP_A(fa, a) >> 16) + ((unsigned int)fa * OP_B(fa, a) >> 16));
#if HAVE_R
unsigned int r_ops[] = {0, (unsigned int)r, fr, (unsigned int)a, fa};
unsigned int r_opa = r_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_r;
unsigned int r_opb = r_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_r;
(void)r_opa;
(void)r_opb;
r = MODE_RGB(r, r_opa, fr, r_opb);
#else
r = fr;
#endif
#if HAVE_G
unsigned int g_ops[] = {0, (unsigned int)g, fg, (unsigned int)a, fa};
unsigned int g_opa = g_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_g;
unsigned int g_opb = g_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_g;
(void)g_opa;
(void)g_opb;
g = MODE_RGB(g, g_opa, fg, g_opb);
#else
g = fg;
#endif
#if HAVE_B
unsigned int b_ops[] = {0, (unsigned int)b, fb, (unsigned int)a, fa};
unsigned int b_opa = b_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_b;
unsigned int b_opb = b_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_b;
(void)b_opa;
(void)b_opb;
b = MODE_RGB(b, b_opa, fb, b_opb);
#else
b = fb;
#endif
#if HAVE_A
unsigned int a_ops[] = {0, (unsigned int)a, fa, (unsigned int)a, fa};
unsigned int a_opa = a_ops[zb->blenda.op_alpha] ^ zb->blenda.xor_a;
unsigned int a_opb = a_ops[zb->blendb.op_alpha] ^ zb->blendb.xor_a;
(void)a_opa;
(void)a_opb;
a = MODE_ALPHA(a, a_opa, fa, a_opb);
#else
a = fa;
#endif
result = RGBA_TO_PIXEL(r, g, b, a);
}
@ -36,25 +76,67 @@ FNAME(store_pixel) (ZBuffer *zb, PIXEL &result, int r, int g, int b, int a) {
static void
FNAME_S(store_pixel) (ZBuffer *zb, PIXEL &result, int r, int g, int b, int a) {
#if HAVE_R || HAVE_G || HAVE_B || HAVE_A
unsigned int fr = PIXEL_SR(result);
unsigned int fg = PIXEL_SG(result);
unsigned int fb = PIXEL_SB(result);
unsigned int fa = PIXEL_A(result);
r = STORE_PIXEL_0(fr, ((unsigned int)r * OP_A(fr, r) >> 16) + ((unsigned int)fr * OP_B(fr, r) >> 16));
g = STORE_PIXEL_1(fg, ((unsigned int)g * OP_A(fg, g) >> 16) + ((unsigned int)fg * OP_B(fg, g) >> 16));
b = STORE_PIXEL_2(fb, ((unsigned int)b * OP_A(fb, b) >> 16) + ((unsigned int)fb * OP_B(fb, b) >> 16));
a = STORE_PIXEL_3(fa, ((unsigned int)a * OP_A(fa, a) >> 16) + ((unsigned int)fa * OP_B(fa, a) >> 16));
#if HAVE_R
unsigned int r_ops[] = {0, (unsigned int)r, fr, (unsigned int)a, fa};
unsigned int r_opa = r_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_r;
unsigned int r_opb = r_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_r;
(void)r_opa;
(void)r_opb;
r = MODE_RGB(r, r_opa, fr, r_opb);
#else
r = fr;
#endif
#if HAVE_G
unsigned int g_ops[] = {0, (unsigned int)g, fg, (unsigned int)a, fa};
unsigned int g_opa = g_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_g;
unsigned int g_opb = g_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_g;
(void)g_opa;
(void)g_opb;
g = MODE_RGB(g, g_opa, fg, g_opb);
#else
g = fg;
#endif
#if HAVE_B
unsigned int b_ops[] = {0, (unsigned int)b, fb, (unsigned int)a, fa};
unsigned int b_opa = b_ops[zb->blenda.op_rgb] ^ zb->blenda.xor_b;
unsigned int b_opb = b_ops[zb->blendb.op_rgb] ^ zb->blendb.xor_b;
(void)b_opa;
(void)b_opb;
b = MODE_RGB(b, b_opa, fb, b_opb);
#else
b = fb;
#endif
#if HAVE_A
unsigned int a_ops[] = {0, (unsigned int)a, fa, (unsigned int)a, fa};
unsigned int a_opa = a_ops[zb->blenda.op_alpha] ^ zb->blenda.xor_a;
unsigned int a_opb = a_ops[zb->blendb.op_alpha] ^ zb->blendb.xor_a;
(void)a_opa;
(void)a_opb;
a = MODE_ALPHA(a, a_opa, fa, a_opb);
#else
a = fa;
#endif
result = SRGBA_TO_PIXEL(r, g, b, a);
#endif
}
#undef FNAME_S
#endif
#undef FNAME
#undef OP_A
#undef OP_B
#undef STORE_PIXEL_0
#undef STORE_PIXEL_1
#undef STORE_PIXEL_2
#undef STORE_PIXEL_3
#undef MODE_RGB
#undef MODE_ALPHA
#undef HAVE_R
#undef HAVE_G
#undef HAVE_B
#undef HAVE_A

134
panda/src/tinydisplay/store_pixel.py Normal file → Executable file
View File

@ -7,109 +7,83 @@ Each different combination of options is compiled to a different
inner-loop store function. The code in tinyGraphicsStateGuardian.cxx
will select the appropriate function pointer at draw time. """
Operands = [
'zero', 'one',
'icolor', 'micolor',
'fcolor', 'mfcolor',
'ialpha', 'mialpha',
'falpha', 'mfalpha',
'ccolor', 'mccolor',
'calpha', 'mcalpha',
Modes = [
'add',
'min',
'max',
]
CodeTable = {
'zero' : '0',
'one' : '0x10000',
'icolor' : 'i',
'micolor' : '0xffff - i',
'fcolor' : 'f',
'mfcolor' : '0xffff - f',
'ialpha' : 'a',
'mialpha' : '0xffff - a',
'falpha' : 'fa',
'mfalpha' : '0xffff - fa',
'ccolor' : 'zb->blend_ ## i',
'mccolor' : '0xffff - zb->blend_ ## i',
'calpha' : 'zb->blend_a',
'mcalpha' : '0xffff - zb->blend_a',
}
# We handle alpha write as a special "off" mode, reducing redundancy.
AlphaModes = Modes + ['off']
CodeTable = {
'add': 'STORE_PIX_CLAMP(((unsigned int)c * c_opa >> 16) + ((unsigned int)fc * c_opb >> 16))',
'min': 'std::min((unsigned int)c, (unsigned int)fc)',
'max': 'std::max((unsigned int)c, (unsigned int)fc)',
'off': '(unsigned int)fc',
}
bitnames = 'rgba'
def getFname(op_a, op_b, mask):
def get_fname(rgb_mode, alpha_mode, mask):
maskname = ''
for b in range(4):
for b in range(3):
if (mask & (1 << b)):
maskname += bitnames[b]
else:
maskname += '0'
return 'store_pixel_%s_%s_%s' % (op_a, op_b, maskname)
return 'store_pixel_%s_%s_%s' % (rgb_mode, alpha_mode, maskname)
# We write the code that actually instantiates the various
# pixel-storing functions to store_pixel_code.h.
code = open('store_pixel_code.h', 'wb')
print >> code, '/* This file is generated code--do not edit. See store_pixel.py. */'
print >> code, ''
code = open('store_pixel_code.h', 'w')
print('/* This file is generated code--do not edit. See store_pixel.py. */', file=code)
print('', file=code)
# The external reference for the table containing the above function
# pointers gets written here.
table = open('store_pixel_table.h', 'wb')
print >> table, '/* This file is generated code--do not edit. See store_pixel.py. */'
print >> table, ''
table = open('store_pixel_table.h', 'w')
print('/* This file is generated code--do not edit. See store_pixel.py. */', file=table)
print('', file=table)
for op_a in Operands:
for op_b in Operands:
for mask in range(0, 16):
fname = getFname(op_a, op_b, mask)
print >> code, '#define FNAME(name) %s' % (fname)
if mask & (1 | 2 | 3):
print >> code, '#define FNAME_S(name) %s_s' % (fname)
for rgb_mode in Modes:
for alpha_mode in AlphaModes:
for mask in range(0, 8):
fname = get_fname(rgb_mode, alpha_mode, mask)
print('#define FNAME(name) %s' % (fname), file=code)
if mask != 0:
print('#define FNAME_S(name) %s_s' % (fname), file=code)
print >> code, '#define OP_A(f, i) ((unsigned int)(%s))' % (CodeTable[op_a])
print >> code, '#define OP_B(f, i) ((unsigned int)(%s))' % (CodeTable[op_b])
for b in range(0, 4):
print('#define MODE_RGB(c, c_opa, fc, c_opb) %s' % (CodeTable[rgb_mode]), file=code)
print('#define MODE_ALPHA(c, c_opa, fc, c_opb) %s' % (CodeTable[alpha_mode]), file=code)
for b in range(0, 3):
if (mask & (1 << b)):
print >> code, "#define STORE_PIXEL_%s(fr, r) STORE_PIX_CLAMP(r)" % (b)
else:
print >> code, "#define STORE_PIXEL_%s(fr, r) (fr)" % (b)
print >> code, '#include "store_pixel.h"'
print >> code, ''
print("#define HAVE_%s 1" % (bitnames[b].upper()), file=code)
if alpha_mode != 'off':
print("#define HAVE_A 1", file=code)
print('#include "store_pixel.h"', file=code)
print('', file=code)
# Now, generate the table of function pointers.
arraySize = '[%s][%s][16]' % (len(Operands), len(Operands))
arraySize = '[%s][%s][8][2]' % (len(Modes), len(AlphaModes))
print >> table, 'extern const ZB_storePixelFunc store_pixel_funcs%s;' % (arraySize)
print >> code, 'const ZB_storePixelFunc store_pixel_funcs%s = {' % (arraySize)
print('extern const ZB_storePixelFunc store_pixel_funcs%s;' % (arraySize), file=table)
print('const ZB_storePixelFunc store_pixel_funcs%s = {' % (arraySize), file=code)
for op_a in Operands:
print >> code, ' {'
for op_b in Operands:
print >> code, ' {'
for mask in range(0, 16):
fname = getFname(op_a, op_b, mask)
print >> code, ' %s,' % (fname)
print >> code, ' },'
print >> code, ' },'
print >> code, '};'
print >> code
# Now do this again, but for the sRGB function pointers.
print >> table, 'extern const ZB_storePixelFunc store_pixel_funcs_sRGB%s;' % (arraySize)
print >> code, 'const ZB_storePixelFunc store_pixel_funcs_sRGB%s = {' % (arraySize)
for op_a in Operands:
print >> code, ' {'
for op_b in Operands:
print >> code, ' {'
for mask in range(0, 16):
fname = getFname(op_a, op_b, mask)
if mask & (1 | 2 | 3):
print >> code, ' %s_s,' % (fname)
for rgb_mode in Modes:
print(' {', file=code)
for alpha_mode in AlphaModes:
print(' {', file=code)
for mask in range(0, 8):
fname = get_fname(rgb_mode, alpha_mode, mask)
if mask != 0:
fname_s = fname + '_s'
else:
print >> code, ' %s,' % (fname)
print >> code, ' },'
print >> code, ' },'
print >> code, '};'
fname_s = fname
print(' {%s, %s},' % (fname, fname_s), file=code)
print(' },', file=code)
print(' },', file=code)
print('};', file=code)
print('', file=code)

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
/* This file is generated code--do not edit. See store_pixel.py. */
extern const ZB_storePixelFunc store_pixel_funcs[14][14][16];
extern const ZB_storePixelFunc store_pixel_funcs_sRGB[14][14][16];
extern const ZB_storePixelFunc store_pixel_funcs[3][4][8][2];

View File

@ -22,6 +22,7 @@
#include "directionalLight.h"
#include "spotlight.h"
#include "depthWriteAttrib.h"
#include "depthBiasAttrib.h"
#include "depthOffsetAttrib.h"
#include "colorWriteAttrib.h"
#include "alphaTestAttrib.h"
@ -94,6 +95,7 @@ reset() {
_inv_state_mask.clear_bit(ColorAttrib::get_class_slot());
_inv_state_mask.clear_bit(ColorScaleAttrib::get_class_slot());
_inv_state_mask.clear_bit(CullFaceAttrib::get_class_slot());
_inv_state_mask.clear_bit(DepthBiasAttrib::get_class_slot());
_inv_state_mask.clear_bit(DepthOffsetAttrib::get_class_slot());
_inv_state_mask.clear_bit(RenderModeAttrib::get_class_slot());
_inv_state_mask.clear_bit(RescaleNormalAttrib::get_class_slot());
@ -229,10 +231,9 @@ clear(DrawableRegion *clearable) {
}
bool clear_z = false;
int z = 0;
ZPOINT z = 0;
if (clearable->get_clear_depth_active()) {
// We ignore the specified depth clear value, since we don't support
// alternate depth compare functions anyway.
z = (ZPOINT)((1.0f - clearable->get_clear_depth()) * (1 << ZB_Z_BITS));
clear_z = true;
}
@ -280,6 +281,18 @@ prepare_display_region(DisplayRegionPipelineReader *dr) {
_c->viewport.ysize = ysize;
set_scissor(0.0f, 1.0f, 0.0f, 1.0f);
PN_stdfloat dr_near = 0.0f;
PN_stdfloat dr_far = 1.0f;
dr->get_depth_range(dr_near, dr_far);
if (dr_near == 0.0f && dr_far == 1.0f) {
_c->has_zrange = false;
} else {
_c->has_zrange = true;
_c->zmin = dr_near;
_c->zrange = dr_far - dr_near;
}
nassertv(xmin >= 0 && xmin < _c->zb->xsize &&
ymin >= 0 && ymin < _c->zb->ysize &&
xmin + xsize >= 0 && xmin + xsize <= _c->zb->xsize &&
@ -757,96 +770,100 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
int color_write_state = 0; // cstore
const ColorWriteAttrib *target_color_write = DCAST(ColorWriteAttrib, _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot()));
const ColorWriteAttrib *target_color_write;
_target_rs->get_attrib_def(target_color_write);
unsigned int color_channels =
target_color_write->get_channels() & _color_write_mask;
unsigned int rgb_channels = color_channels & ColorWriteAttrib::C_rgb;
if (color_channels == ColorWriteAttrib::C_all) {
if (srgb_blend) {
color_write_state = 4; // csstore
} else {
color_write_state = 0; // cstore
}
} else {
// Implement a color mask.
int op_a = get_color_blend_op(ColorBlendAttrib::O_one);
int op_b = get_color_blend_op(ColorBlendAttrib::O_zero);
if (srgb_blend) {
_c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
} else {
_c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
}
color_write_state = 2; // cgeneral
}
const TransparencyAttrib *target_transparency = DCAST(TransparencyAttrib, _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
switch (target_transparency->get_mode()) {
case TransparencyAttrib::M_alpha:
case TransparencyAttrib::M_dual:
if (color_channels == ColorWriteAttrib::C_all) {
if (srgb_blend) {
color_write_state = 5; // csblend
} else {
color_write_state = 1; // cblend
}
} else {
// Implement a color mask, with alpha blending.
int op_a = get_color_blend_op(ColorBlendAttrib::O_incoming_alpha);
int op_b = get_color_blend_op(ColorBlendAttrib::O_one_minus_incoming_alpha);
if (srgb_blend) {
_c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
} else {
_c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
}
color_write_state = 2; // cgeneral
}
break;
case TransparencyAttrib::M_premultiplied_alpha:
{
// Implement a color mask, with pre-multiplied alpha blending.
int op_a = get_color_blend_op(ColorBlendAttrib::O_one);
int op_b = get_color_blend_op(ColorBlendAttrib::O_one_minus_incoming_alpha);
if (srgb_blend) {
_c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
} else {
_c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
}
color_write_state = 2; // cgeneral
}
break;
default:
break;
}
const ColorBlendAttrib *target_color_blend = DCAST(ColorBlendAttrib, _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
if (target_color_blend->get_mode() == ColorBlendAttrib::M_add) {
// If we have a color blend set that we can support, it overrides the
// transparency set.
LColor c = target_color_blend->get_color();
_c->zb->blend_r = (int)(c[0] * ZB_POINT_RED_MAX);
_c->zb->blend_g = (int)(c[1] * ZB_POINT_GREEN_MAX);
_c->zb->blend_b = (int)(c[2] * ZB_POINT_BLUE_MAX);
_c->zb->blend_a = (int)(c[3] * ZB_POINT_ALPHA_MAX);
int op_a = get_color_blend_op(target_color_blend->get_operand_a());
int op_b = get_color_blend_op(target_color_blend->get_operand_b());
if (srgb_blend) {
_c->zb->store_pix_func = store_pixel_funcs_sRGB[op_a][op_b][color_channels];
} else {
_c->zb->store_pix_func = store_pixel_funcs[op_a][op_b][color_channels];
}
color_write_state = 2; // cgeneral
}
const ColorBlendAttrib *target_color_blend;
_target_rs->get_attrib_def(target_color_blend);
if (color_channels == ColorWriteAttrib::C_off) {
color_write_state = 3; // coff
}
else if (target_color_blend->get_mode() != ColorBlendAttrib::M_none) {
// If we have a color blend set that we can support, it overrides the
// transparency set.
int rgb_mode = get_color_blend_mode(target_color_blend->get_mode());
int alpha_mode;
if (color_channels & ColorWriteAttrib::C_alpha) {
alpha_mode = get_color_blend_mode(target_color_blend->get_alpha_mode());
} else {
// Disabled alpha write is encoded as a separate alpha mode, to cut down
// on redundancy in the store_pixel table.
alpha_mode = 3;
}
LColor c = target_color_blend->get_color();
unsigned int cr = (int)(c[0] * ZB_POINT_RED_MAX);
unsigned int cg = (int)(c[1] * ZB_POINT_GREEN_MAX);
unsigned int cb = (int)(c[2] * ZB_POINT_BLUE_MAX);
unsigned int ca = (int)(c[3] * ZB_POINT_ALPHA_MAX);
setup_color_blend(_c->zb->blenda, target_color_blend->get_operand_a(),
target_color_blend->get_alpha_operand_a(),
cr, cg, cb, ca);
setup_color_blend(_c->zb->blendb, target_color_blend->get_operand_b(),
target_color_blend->get_alpha_operand_b(),
cr, cg, cb, ca);
_c->zb->store_pix_func = store_pixel_funcs[rgb_mode][alpha_mode][rgb_channels][srgb_blend];
color_write_state = 2; // cgeneral
}
else {
const TransparencyAttrib *target_transparency;
_target_rs->get_attrib_def(target_transparency);
switch (target_transparency->get_mode()) {
case TransparencyAttrib::M_alpha:
case TransparencyAttrib::M_dual:
if (color_channels == ColorWriteAttrib::C_all) {
if (srgb_blend) {
color_write_state = 5; // csblend
} else {
color_write_state = 1; // cblend
}
} else {
// Implement a color mask, with alpha blending.
setup_color_blend(_c->zb->blenda, ColorBlendAttrib::O_incoming_alpha, ColorBlendAttrib::O_one);
setup_color_blend(_c->zb->blendb, ColorBlendAttrib::O_one_minus_incoming_alpha, ColorBlendAttrib::O_one_minus_incoming_alpha);
int alpha_mode = (color_channels & ColorWriteAttrib::C_alpha) ? 0 : 3;
_c->zb->store_pix_func = store_pixel_funcs[0][alpha_mode][rgb_channels][srgb_blend];
color_write_state = 2; // cgeneral
}
break;
case TransparencyAttrib::M_premultiplied_alpha:
{
// Implement a color mask, with pre-multiplied alpha blending.
setup_color_blend(_c->zb->blenda, ColorBlendAttrib::O_one, ColorBlendAttrib::O_one);
setup_color_blend(_c->zb->blendb, ColorBlendAttrib::O_one_minus_incoming_alpha, ColorBlendAttrib::O_one_minus_incoming_alpha);
int alpha_mode = (color_channels & ColorWriteAttrib::C_alpha) ? 0 : 3;
_c->zb->store_pix_func = store_pixel_funcs[0][alpha_mode][rgb_channels][srgb_blend];
color_write_state = 2; // cgeneral
}
break;
default:
if (color_channels == ColorWriteAttrib::C_all) {
if (srgb_blend) {
color_write_state = 4; // csstore
} else {
color_write_state = 0; // cstore
}
} else {
// Implement a color mask.
setup_color_blend(_c->zb->blenda, ColorBlendAttrib::O_one, ColorBlendAttrib::O_one);
setup_color_blend(_c->zb->blendb, ColorBlendAttrib::O_zero, ColorBlendAttrib::O_zero);
int alpha_mode = (color_channels & ColorWriteAttrib::C_alpha) ? 0 : 3;
_c->zb->store_pix_func = store_pixel_funcs[0][alpha_mode][rgb_channels][srgb_blend];
color_write_state = 2; // cgeneral
}
break;
}
}
int alpha_test_state = 0; // anone
const AlphaTestAttrib *target_alpha_test = DCAST(AlphaTestAttrib, _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
@ -875,7 +892,8 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
int depth_test_state = 1; // zless
_c->depth_test = 1; // set this for ZB_line
const DepthTestAttrib *target_depth_test = DCAST(DepthTestAttrib, _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot()));
if (target_depth_test->get_mode() == DepthTestAttrib::M_none) {
if (target_depth_test->get_mode() == DepthTestAttrib::M_none ||
target_depth_test->get_mode() == DepthTestAttrib::M_always) {
depth_test_state = 0; // zless
_c->depth_test = 0;
}
@ -1415,10 +1433,17 @@ framebuffer_copy_to_ram(Texture *tex, int view, int z,
z_size = 1;
}
Texture::ComponentType component_type = Texture::T_unsigned_byte;
Texture::Format format = Texture::F_rgba;
if (_current_properties->get_srgb_color()) {
format = Texture::F_srgb_alpha;
Texture::ComponentType component_type;
Texture::Format format;
if (rb._buffer_type & RenderBuffer::T_depth) {
component_type = Texture::T_unsigned_int;
format = Texture::F_depth_component;
} else {
component_type = Texture::T_unsigned_byte;
format = Texture::F_rgba;
if (_current_properties->get_srgb_color()) {
format = Texture::F_srgb_alpha;
}
}
if (tex->get_x_size() != w || tex->get_y_size() != h ||
@ -1445,32 +1470,53 @@ framebuffer_copy_to_ram(Texture *tex, int view, int z,
}
}
PIXEL *ip = (PIXEL *)(image_ptr + image_size);
PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
for (int y = 0; y < h; ++y) {
ip -= w;
#ifndef WORDS_BIGENDIAN
// On a little-endian machine, we can copy the whole row at a time.
memcpy(ip, fo, w * PSZB);
#else
// On a big-endian machine, we have to reverse the color-component order.
const char *source = (const char *)fo;
const char *stop = (const char *)fo + w * PSZB;
char *dest = (char *)ip;
while (source < stop) {
char b = source[0];
char g = source[1];
char r = source[2];
char a = source[3];
dest[0] = a;
dest[1] = r;
dest[2] = g;
dest[3] = b;
dest += 4;
source += 4;
if (rb._buffer_type & RenderBuffer::T_depth) {
size_t dst_stride = tex->get_x_size();
unsigned int *dst = (unsigned int *)(image_ptr + image_size);
size_t src_stride = _c->zb->xsize;
ZPOINT *src = _c->zb->zbuf + xo + src_stride * yo;
for (int y = 0; y < h; ++y) {
dst -= dst_stride;
for (int x = 0; x < w; ++x) {
ZPOINT z = src[x];
if (z == 0) {
z = 0xFFFFFFFF;
} else {
z = (1 << ZB_Z_BITS) - z;
z = z << (32 - ZB_Z_BITS);
}
dst[x] = z;
}
}
} else {
PIXEL *ip = (PIXEL *)(image_ptr + image_size);
PIXEL *fo = _c->zb->pbuf + xo + yo * _c->zb->linesize / PSZB;
for (int y = 0; y < h; ++y) {
ip -= w;
#ifndef WORDS_BIGENDIAN
// On a little-endian machine, we can copy the whole row at a time.
memcpy(ip, fo, w * PSZB);
#else
// On a big-endian machine, we have to reverse the color-component order.
const char *source = (const char *)fo;
const char *stop = (const char *)fo + w * PSZB;
char *dest = (char *)ip;
while (source < stop) {
char b = source[0];
char g = source[1];
char r = source[2];
char a = source[3];
dest[0] = a;
dest[1] = r;
dest[2] = g;
dest[3] = b;
dest += 4;
source += 4;
}
#endif
fo += _c->zb->linesize / PSZB;
fo += _c->zb->linesize / PSZB;
}
}
if (request != nullptr) {
@ -1539,11 +1585,15 @@ set_state_and_transform(const RenderState *target,
_state_mask.set_bit(cull_face_slot);
}
int depth_bias_slot = DepthBiasAttrib::get_class_slot();
int depth_offset_slot = DepthOffsetAttrib::get_class_slot();
if (_target_rs->get_attrib(depth_offset_slot) != _state_rs->get_attrib(depth_offset_slot) ||
if (_target_rs->get_attrib(depth_bias_slot) != _state_rs->get_attrib(depth_bias_slot) ||
_target_rs->get_attrib(depth_offset_slot) != _state_rs->get_attrib(depth_offset_slot) ||
!_state_mask.get_bit(depth_bias_slot) ||
!_state_mask.get_bit(depth_offset_slot)) {
// PStatTimer timer(_draw_set_state_depth_offset_pcollector);
do_issue_depth_offset();
do_issue_depth_bias();
_state_mask.set_bit(depth_bias_slot);
_state_mask.set_bit(depth_offset_slot);
}
@ -2070,13 +2120,30 @@ do_issue_rescale_normal() {
*
*/
void TinyGraphicsStateGuardian::
do_issue_depth_offset() {
const DepthOffsetAttrib *target_depth_offset = DCAST(DepthOffsetAttrib, _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot()));
do_issue_depth_bias() {
const DepthOffsetAttrib *target_depth_offset;
_target_rs->get_attrib_def(target_depth_offset);
int offset = target_depth_offset->get_offset();
_c->zbias = offset;
const DepthBiasAttrib *target_depth_bias;
if (_target_rs->get_attrib(target_depth_bias)) {
PN_stdfloat constant_factor = target_depth_bias->get_constant_factor();
_c->zbias = (int)(((PN_stdfloat)offset - constant_factor) * (1 << (ZB_POINT_Z_FRAC_BITS + 4)));
} else {
_c->zbias = offset << (ZB_POINT_Z_FRAC_BITS + 4);
}
PN_stdfloat dr_near = 0.0f;
PN_stdfloat dr_far = 1.0f;
if (_current_display_region != nullptr) {
_current_display_region->get_depth_range(dr_near, dr_far);
}
PN_stdfloat min_value = target_depth_offset->get_min_value();
PN_stdfloat max_value = target_depth_offset->get_max_value();
min_value = dr_far * min_value + dr_near * (1 - min_value);
max_value = dr_far * max_value + dr_near * (1 - max_value);
if (min_value == 0.0f && max_value == 1.0f) {
_c->has_zrange = false;
} else {
@ -3035,66 +3102,141 @@ load_matrix(M4 *matrix, const TransformState *transform) {
}
/**
* Returns the integer element of store_pixel_funcs (as defined by
* store_pixel.py) that corresponds to the indicated ColorBlendAttrib operand
* code.
* Returns the integer index into the array of store_pixel functions
* corresponding to the given blend mode.
*/
int TinyGraphicsStateGuardian::
get_color_blend_mode(ColorBlendAttrib::Mode mode) {
switch (mode) {
case ColorBlendAttrib::M_none:
case ColorBlendAttrib::M_add:
case ColorBlendAttrib::M_subtract:
case ColorBlendAttrib::M_inv_subtract:
return 0;
case ColorBlendAttrib::M_min:
return 1;
case ColorBlendAttrib::M_max:
return 2;
}
return 0;
}
/**
* Returns the integer index into the array of operands computed by store_pixel
* that corresponds to the indicated ColorBlendAttrib operand code.
*/
int TinyGraphicsStateGuardian::
get_color_blend_op(ColorBlendAttrib::Operand operand) {
switch (operand) {
case ColorBlendAttrib::O_zero:
return 0;
case ColorBlendAttrib::O_one:
return 1;
case ColorBlendAttrib::O_incoming_color:
return 2;
case ColorBlendAttrib::O_one_minus_incoming_color:
return 3;
case ColorBlendAttrib::O_fbuffer_color:
return 4;
case ColorBlendAttrib::O_one_minus_fbuffer_color:
return 5;
case ColorBlendAttrib::O_incoming_alpha:
return 6;
case ColorBlendAttrib::O_one_minus_incoming_alpha:
return 7;
case ColorBlendAttrib::O_fbuffer_alpha:
return 8;
case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
return 9;
case ColorBlendAttrib::O_constant_color:
return 10;
case ColorBlendAttrib::O_one_minus_constant_color:
return 11;
case ColorBlendAttrib::O_constant_alpha:
return 12;
case ColorBlendAttrib::O_one_minus_constant_alpha:
return 13;
case ColorBlendAttrib::O_incoming_color_saturate:
return 1;
case ColorBlendAttrib::O_incoming1_color:
return 1;
case ColorBlendAttrib::O_one_minus_incoming1_color:
return 0;
case ColorBlendAttrib::O_incoming1_alpha:
return 1;
case ColorBlendAttrib::O_one_minus_incoming1_alpha:
return 0;
case ColorBlendAttrib::O_color_scale:
return 10;
case ColorBlendAttrib::O_one_minus_color_scale:
return 11;
case ColorBlendAttrib::O_alpha_scale:
return 12;
case ColorBlendAttrib::O_one_minus_alpha_scale:
return 13;
return 0;
case ColorBlendAttrib::O_incoming_color:
case ColorBlendAttrib::O_one_minus_incoming_color:
case ColorBlendAttrib::O_incoming_color_saturate:
case ColorBlendAttrib::O_incoming1_color:
case ColorBlendAttrib::O_one_minus_incoming1_color:
case ColorBlendAttrib::O_incoming1_alpha:
case ColorBlendAttrib::O_one_minus_incoming1_alpha:
return 1;
case ColorBlendAttrib::O_fbuffer_color:
case ColorBlendAttrib::O_one_minus_fbuffer_color:
return 2;
case ColorBlendAttrib::O_incoming_alpha:
case ColorBlendAttrib::O_one_minus_incoming_alpha:
return 3;
case ColorBlendAttrib::O_fbuffer_alpha:
case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
return 4;
}
return 0;
}
/**
* Returns true if the color blend operand should be inverted.
*/
bool TinyGraphicsStateGuardian::
is_color_blend_op_inverted(ColorBlendAttrib::Operand operand) {
switch (operand) {
case ColorBlendAttrib::O_zero:
case ColorBlendAttrib::O_constant_color:
case ColorBlendAttrib::O_constant_alpha:
case ColorBlendAttrib::O_color_scale:
case ColorBlendAttrib::O_alpha_scale:
case ColorBlendAttrib::O_incoming_color:
case ColorBlendAttrib::O_incoming_color_saturate:
case ColorBlendAttrib::O_incoming1_color:
case ColorBlendAttrib::O_incoming1_alpha:
case ColorBlendAttrib::O_fbuffer_color:
case ColorBlendAttrib::O_incoming_alpha:
case ColorBlendAttrib::O_fbuffer_alpha:
return false;
case ColorBlendAttrib::O_one:
case ColorBlendAttrib::O_one_minus_constant_color:
case ColorBlendAttrib::O_one_minus_constant_alpha:
case ColorBlendAttrib::O_one_minus_color_scale:
case ColorBlendAttrib::O_one_minus_alpha_scale:
case ColorBlendAttrib::O_one_minus_incoming_color:
case ColorBlendAttrib::O_one_minus_incoming1_color:
case ColorBlendAttrib::O_one_minus_incoming1_alpha:
case ColorBlendAttrib::O_one_minus_fbuffer_color:
case ColorBlendAttrib::O_one_minus_incoming_alpha:
case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
return true;
}
return false;
}
/**
* Sets up the color blending state for the given blend operand.
*/
void TinyGraphicsStateGuardian::
setup_color_blend(ZBlend &blend, ColorBlendAttrib::Operand op_rgb,
ColorBlendAttrib::Operand op_alpha,
int cr, int cg, int cb, int ca) {
blend.op_rgb = get_color_blend_op(op_rgb);
blend.op_alpha = get_color_blend_op(op_alpha);
// If it's inverted (one minus), we xor the value with 0xffff
unsigned int mask_rgb = is_color_blend_op_inverted(op_rgb) ? 0xffff : 0x0;
unsigned int mask_alpha = is_color_blend_op_inverted(op_alpha) ? 0xffff : 0x0;
blend.xor_r = mask_rgb;
blend.xor_g = mask_rgb;
blend.xor_b = mask_rgb;
blend.xor_a = mask_alpha;
// A constant factor is implemented by doing effectively O_zero ^ constant,
// so we can conveniently reuse the xor mask field to store it!
if (op_rgb == ColorBlendAttrib::O_constant_color ||
op_rgb == ColorBlendAttrib::O_one_minus_constant_color) {
blend.xor_r ^= cr;
blend.xor_g ^= cg;
blend.xor_b ^= cb;
}
if (op_rgb == ColorBlendAttrib::O_constant_alpha ||
op_rgb == ColorBlendAttrib::O_one_minus_constant_alpha) {
blend.xor_r ^= ca;
blend.xor_g ^= ca;
blend.xor_b ^= ca;
}
if (op_alpha == ColorBlendAttrib::O_constant_color ||
op_alpha == ColorBlendAttrib::O_constant_alpha ||
op_alpha == ColorBlendAttrib::O_one_minus_constant_color ||
op_alpha == ColorBlendAttrib::O_one_minus_constant_alpha) {
blend.xor_a ^= ca;
}
}
/**
* Returns the pointer to the appropriate filter function according to the
* texture's filter type.

View File

@ -102,7 +102,7 @@ private:
void do_issue_render_mode();
void do_issue_cull_face();
void do_issue_rescale_normal();
void do_issue_depth_offset();
void do_issue_depth_bias();
void do_issue_material();
void do_issue_texture();
void do_issue_scissor();
@ -125,7 +125,13 @@ private:
void setup_material(GLMaterial *gl_material, const Material *material);
void do_auto_rescale_normal();
static void load_matrix(M4 *matrix, const TransformState *transform);
static int get_color_blend_mode(ColorBlendAttrib::Mode mode);
static int get_color_blend_op(ColorBlendAttrib::Operand operand);
static bool is_color_blend_op_inverted(ColorBlendAttrib::Operand operand);
static void setup_color_blend(ZBlend &blend,
ColorBlendAttrib::Operand op_rgb,
ColorBlendAttrib::Operand op_alpha,
int cr=0, int cg=0, int cb=0, int ca=0);
static ZB_lookupTextureFunc get_tex_filter_func(SamplerState::FilterType filter);
static ZB_texWrapFunc get_tex_wrap_func(SamplerState::WrapMode wrap_mode);

View File

@ -420,7 +420,7 @@ ZB_clear_viewport(ZBuffer * zb, int clear_z, ZPOINT z, int clear_color, PIXEL co
if (clear_z) {
zz = zb->zbuf + xmin + ymin * zb->xsize;
for (y = 0; y < ysize; ++y) {
memset(zz, 0, xsize * sizeof(ZPOINT));
memset_l(zz, z, xsize);
zz += zb->xsize;
}
}

View File

@ -158,6 +158,15 @@ struct ZTextureDef {
PIXEL border_color;
};
struct ZBlend {
int op_rgb;
int op_alpha;
unsigned int xor_r;
unsigned int xor_g;
unsigned int xor_b;
unsigned int xor_a;
};
struct ZBuffer {
int xsize,ysize;
int linesize; /* line size, in bytes */
@ -172,7 +181,8 @@ struct ZBuffer {
int *ctable;
ZTextureDef current_textures[MAX_TEXTURE_STAGES];
int reference_alpha;
int blend_r, blend_g, blend_b, blend_a;
ZBlend blenda;
ZBlend blendb;
ZB_storePixelFunc store_pix_func;
};

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
""" This simple Python script can be run to generate
ztriangle_code_*.h, ztriangle_table.*, and ztriangle_*.cxx, which
are a poor man's form of generated code to cover the explosion of
@ -34,6 +34,7 @@ Options = [
]
# The total number of different combinations of the various Options, above.
from functools import reduce
OptionsCount = reduce(lambda a, b: a * b, map(lambda o: len(o), Options))
# The various combinations of these options are explicit within
@ -99,7 +100,7 @@ ZTriangleStub = """
"""
ops = [0] * len(Options)
class DoneException:
class DoneException(Exception):
pass
# We write the code that actually instantiates the various
@ -148,11 +149,11 @@ def getFref(ops):
def closeCode():
""" Close the previously-opened code file. """
if code:
print >> code, ''
print >> code, 'ZB_fillTriangleFunc ztriangle_code_%s[%s] = {' % (codeSeg, len(fnameList))
print('', file=code)
print('ZB_fillTriangleFunc ztriangle_code_%s[%s] = {' % (codeSeg, len(fnameList)), file=code)
for fname in fnameList:
print >> code, ' %s,' % (fname)
print >> code, '};'
print(' %s,' % (fname), file=code)
print('};', file=code)
code.close()
@ -173,13 +174,13 @@ def openCode(count):
fnameList = []
# Open a new file.
code = open('ztriangle_code_%s.h' % (codeSeg), 'wb')
print >> code, '/* This file is generated code--do not edit. See ztriangle.py. */'
print >> code, ''
code = open('ztriangle_code_%s.h' % (codeSeg), 'w')
print('/* This file is generated code--do not edit. See ztriangle.py. */', file=code)
print('', file=code)
# Also generate ztriangle_*.cxx, to include the above file.
zt = open('ztriangle_%s.cxx' % (codeSeg), 'wb')
print >> zt, ZTriangleStub % (codeSeg)
zt = open('ztriangle_%s.cxx' % (codeSeg), 'w')
print(ZTriangleStub % (codeSeg), file=zt)
# First, generate the code.
count = 0
@ -189,14 +190,14 @@ try:
for i in range(len(ops)):
keyword = Options[i][ops[i]]
print >> code, CodeTable[keyword]
print(CodeTable[keyword], file=code)
# This reference gets just the initial fname: omitting the
# ExtraOptions, which are implicit in ztriangle_two.h.
fname = getFname(ops)
print >> code, '#define FNAME(name) %s_ ## name' % (fname)
print >> code, '#include "ztriangle_two.h"'
print >> code, ''
print('#define FNAME(name) %s_ ## name' % (fname), file=code)
print('#include "ztriangle_two.h"', file=code)
print('', file=code)
# We store the full fnames generated by the above lines
# (including the ExtraOptions) in the fnameDict and fnameList
@ -220,22 +221,22 @@ closeCode()
# The external reference for the table containing the above function
# pointers gets written here.
table_decl = open('ztriangle_table.h', 'wb')
print >> table_decl, '/* This file is generated code--do not edit. See ztriangle.py. */'
print >> table_decl, ''
table_decl = open('ztriangle_table.h', 'w')
print('/* This file is generated code--do not edit. See ztriangle.py. */', file=table_decl)
print('', file=table_decl)
# The actual table definition gets written here.
table_def = open('ztriangle_table.cxx', 'wb')
print >> table_def, '/* This file is generated code--do not edit. See ztriangle.py. */'
print >> table_def, ''
print >> table_def, '#include "pandabase.h"'
print >> table_def, '#include "zbuffer.h"'
print >> table_def, '#include "ztriangle_table.h"'
print >> table_def, ''
table_def = open('ztriangle_table.cxx', 'w')
print('/* This file is generated code--do not edit. See ztriangle.py. */', file=table_def)
print('', file=table_def)
print('#include "pandabase.h"', file=table_def)
print('#include "zbuffer.h"', file=table_def)
print('#include "ztriangle_table.h"', file=table_def)
print('', file=table_def)
for i in range(NumSegments):
print >> table_def, 'extern ZB_fillTriangleFunc ztriangle_code_%s[];' % (i + 1)
print >> table_def, ''
print('extern ZB_fillTriangleFunc ztriangle_code_%s[];' % (i + 1), file=table_def)
print('', file=table_def)
def writeTableEntry(ops):
indent = ' ' * (len(ops) + 1)
@ -245,27 +246,27 @@ def writeTableEntry(ops):
if i + 1 == len(FullOptions):
# The last level: write out the actual function names.
for j in range(numOps - 1):
print >> table_def, indent + getFref(ops + [j]) + ','
print >> table_def, indent + getFref(ops + [numOps - 1])
print(indent + getFref(ops + [j]) + ',', file=table_def)
print(indent + getFref(ops + [numOps - 1]), file=table_def)
else:
# Intermediate levels: write out a nested reference.
for j in range(numOps - 1):
print >> table_def, indent + '{'
print(indent + '{', file=table_def)
writeTableEntry(ops + [j])
print >> table_def, indent + '},'
print >> table_def, indent + '{'
print(indent + '},', file=table_def)
print(indent + '{', file=table_def)
writeTableEntry(ops + [numOps - 1])
print >> table_def, indent + '}'
print(indent + '}', file=table_def)
arraySizeList = []
for opList in FullOptions:
arraySizeList.append('[%s]' % (len(opList)))
arraySize = ''.join(arraySizeList)
print >> table_def, 'const ZB_fillTriangleFunc fill_tri_funcs%s = {' % (arraySize)
print >> table_decl, 'extern const ZB_fillTriangleFunc fill_tri_funcs%s;' % (arraySize)
print('const ZB_fillTriangleFunc fill_tri_funcs%s = {' % (arraySize), file=table_def)
print('extern const ZB_fillTriangleFunc fill_tri_funcs%s;' % (arraySize), file=table_decl)
writeTableEntry([])
print >> table_def, '};'
print('};', file=table_def)

View File

@ -71,7 +71,7 @@ def color_region(request, graphics_pipe):
'host',
0,
host_fbprops,
core.WindowProperties.size(32, 32),
core.WindowProperties.size(8, 8),
core.GraphicsPipe.BF_refuse_window,
)
engine.open_windows()
@ -89,7 +89,7 @@ def color_region(request, graphics_pipe):
'buffer',
0,
fbprops,
core.WindowProperties.size(32, 32),
core.WindowProperties.size(8, 8),
core.GraphicsPipe.BF_refuse_window,
host.gsg,
host
@ -111,7 +111,7 @@ def color_region(request, graphics_pipe):
engine.remove_window(buffer)
def render_color_pixel(region, state, vertex_color=None):
def render_color_pixel(region, state, vertex_color=None, clear_color=(0, 0, 0, 1)):
"""Renders a fragment using the specified render settings, and returns the
resulting color value."""
@ -121,7 +121,7 @@ def render_color_pixel(region, state, vertex_color=None):
if sattr and sattr.auto_shader():
pytest.skip("Cannot test auto-shader without Cg shader support")
# Set up the scene with a blank card rendering at specified distance.
# Set up the scene with a blank triangle rendering at specified distance.
scene = core.NodePath("root")
scene.set_attrib(core.DepthTestAttrib.make(core.RenderAttrib.M_always))
@ -134,46 +134,46 @@ def render_color_pixel(region, state, vertex_color=None):
else:
format = core.GeomVertexFormat.get_v3()
vdata = core.GeomVertexData("card", format, core.Geom.UH_static)
vdata.unclean_set_num_rows(4)
vdata = core.GeomVertexData("triangle", format, core.Geom.UH_static)
vdata.unclean_set_num_rows(3)
vertex = core.GeomVertexWriter(vdata, "vertex")
vertex.set_data3(core.Vec3.rfu(-1, 0, 1))
vertex.set_data3(core.Vec3.rfu(-1, 0, -1))
vertex.set_data3(core.Vec3.rfu(1, 0, 1))
vertex.set_data3(core.Vec3.rfu(1, 0, -1))
vertex.set_data3(core.Vec3.rfu(-1, 0, -3))
vertex.set_data3(core.Vec3.rfu(3, 0, 1))
if vertex_color is not None:
color = core.GeomVertexWriter(vdata, "color")
color.set_data4(vertex_color)
color.set_data4(vertex_color)
color.set_data4(vertex_color)
color.set_data4(vertex_color)
strip = core.GeomTristrips(core.Geom.UH_static)
strip = core.GeomTriangles(core.Geom.UH_static)
strip.set_shade_model(core.Geom.SM_uniform)
strip.add_next_vertices(4)
strip.close_primitive()
strip.add_next_vertices(3)
geom = core.Geom(vdata)
geom.add_primitive(strip)
gnode = core.GeomNode("card")
gnode = core.GeomNode("triangle")
gnode.add_geom(geom, state)
card = scene.attach_new_node(gnode)
card.set_pos(0, 2, 0)
card.set_scale(60)
triangle = scene.attach_new_node(gnode)
triangle.set_pos(0, 2, 0)
region.active = True
region.camera = camera
color_texture = core.Texture("color")
region.window.add_render_texture(color_texture,
core.GraphicsOutput.RTM_copy_ram,
core.GraphicsOutput.RTP_color)
region.window.set_clear_color(clear_color)
try:
color_texture = core.Texture("color")
region.window.add_render_texture(color_texture,
core.GraphicsOutput.RTM_copy_ram,
core.GraphicsOutput.RTP_color)
region.window.engine.render_frame()
region.window.clear_render_textures()
region.window.engine.render_frame()
finally:
region.window.clear_render_textures()
region.window.set_clear_color((0, 0, 0, 1))
col = core.LColor()
color_texture.peek().lookup(col, 0.5, 0.5)
@ -188,6 +188,104 @@ def test_color_write_mask(color_region):
assert result == (0, 1, 0, 1)
OP_NAMES = ['zero', 'one',
'incoming_color', 'one_minus_incoming_color',
'fbuffer_color', 'one_minus_fbuffer_color',
'incoming_alpha', 'one_minus_incoming_alpha',
'fbuffer_alpha', 'one_minus_fbuffer_alpha',
'constant_color', 'one_minus_constant_color',
'constant_alpha', 'one_minus_constant_alpha'
]
@pytest.mark.parametrize('op_name_a', OP_NAMES)
@pytest.mark.parametrize('op_name_b', OP_NAMES)
def test_color_blend_add(color_region, op_name_a, op_name_b):
fbuffer = core.LColor(0.2, 0.4, 0.6, 0.8)
incoming = core.LColor(0.3, 0.5, 0.7, 0.1)
const = core.LColor(0.0, 1.0, 0.5, 0.25)
op_a = getattr(core.ColorBlendAttrib, 'O_' + op_name_a)
op_b = getattr(core.ColorBlendAttrib, 'O_' + op_name_b)
state = core.RenderState.make(
core.ColorAttrib.make_flat(incoming),
core.ColorBlendAttrib.make(core.ColorBlendAttrib.M_add, op_a, op_b, const),
)
# Calculate what it should be.
def calc_op(op):
if op == core.ColorBlendAttrib.O_zero:
return core.LColor(0.0)
if op == core.ColorBlendAttrib.O_one:
return core.LColor(1.0)
if op == core.ColorBlendAttrib.O_incoming_color:
return incoming
if op == core.ColorBlendAttrib.O_one_minus_incoming_color:
return core.LColor(1.0) - incoming
if op == core.ColorBlendAttrib.O_fbuffer_color:
return fbuffer
if op == core.ColorBlendAttrib.O_one_minus_fbuffer_color:
return core.LColor(1.0) - fbuffer
if op == core.ColorBlendAttrib.O_incoming_alpha:
return core.LColor(incoming.w)
if op == core.ColorBlendAttrib.O_one_minus_incoming_alpha:
return core.LColor(1.0 - incoming.w)
if op == core.ColorBlendAttrib.O_fbuffer_alpha:
return core.LColor(fbuffer.w)
if op == core.ColorBlendAttrib.O_one_minus_fbuffer_alpha:
return core.LColor(1.0 - fbuffer.w)
if op == core.ColorBlendAttrib.O_constant_color:
return const
if op == core.ColorBlendAttrib.O_one_minus_constant_color:
return core.LColor(1.0) - const
if op == core.ColorBlendAttrib.O_constant_alpha:
return core.LColor(const.w)
if op == core.ColorBlendAttrib.O_one_minus_constant_alpha:
return core.LColor(1.0 - const.w)
term_a = core.LColor(incoming)
term_a.componentwise_mult(calc_op(op_a))
term_b = core.LColor(fbuffer)
term_b.componentwise_mult(calc_op(op_b))
expected = term_a + term_b
expected = expected.fmax(core.LColor(0)).fmin(core.LColor(1))
result = render_color_pixel(color_region, state, clear_color=fbuffer)
assert result.almost_equal(expected, FUZZ)
@pytest.mark.parametrize('rgb_mode', ['min', 'max'])
@pytest.mark.parametrize('alpha_mode', ['min', 'max'])
def test_color_blend_min_max(color_region, rgb_mode, alpha_mode):
fbuffer = core.LColor(0.2, 0.5, 0.6, 0.8)
incoming = core.LColor(0.3, 0.4, 0.7, 0.1)
# Note that operands are ignored for M_min and M_max
state = core.RenderState.make(
core.ColorAttrib.make_flat(incoming),
core.ColorBlendAttrib.make(
getattr(core.ColorBlendAttrib, 'M_' + rgb_mode),
core.ColorBlendAttrib.O_one,
core.ColorBlendAttrib.O_one,
getattr(core.ColorBlendAttrib, 'M_' + alpha_mode),
core.ColorBlendAttrib.O_one,
core.ColorBlendAttrib.O_one,
),
)
if rgb_mode == 'min':
expected = fbuffer.fmin(incoming)
elif rgb_mode == 'max':
expected = fbuffer.fmax(incoming)
if rgb_mode != alpha_mode:
if alpha_mode == 'min':
expected.w = min(fbuffer.w, incoming.w)
elif alpha_mode == 'max':
expected.w = max(fbuffer.w, incoming.w)
result = render_color_pixel(color_region, state, clear_color=fbuffer)
assert result.almost_equal(expected, FUZZ)
def test_color_empty(color_region, shader_attrib, material_attrib):
state = core.RenderState.make(
shader_attrib,
@ -321,6 +419,7 @@ def test_color_transparency(color_region, shader_attrib, light_attrib):
)
result = render_color_pixel(color_region, state)
assert result.x == pytest.approx(0.75, 0.1)
assert result.w == pytest.approx(1.0, 0.1)
def test_color_transparency_flat(color_region, shader_attrib, light_attrib):
@ -337,6 +436,7 @@ def test_color_transparency_flat(color_region, shader_attrib, light_attrib):
)
result = render_color_pixel(color_region, state)
assert result.x == pytest.approx(0.75, 0.1)
assert result.w == pytest.approx(1.0, 0.1)
def test_color_transparency_vertex(color_region, shader_attrib, light_attrib):
@ -353,6 +453,7 @@ def test_color_transparency_vertex(color_region, shader_attrib, light_attrib):
)
result = render_color_pixel(color_region, state, vertex_color=(1, 1, 1, 0.5))
assert result.x == pytest.approx(0.75, 0.1)
assert result.w == pytest.approx(1.0, 0.1)
def test_color_transparency_no_light(color_region, shader_attrib):
@ -367,6 +468,7 @@ def test_color_transparency_no_light(color_region, shader_attrib):
)
result = render_color_pixel(color_region, state)
assert result.x == pytest.approx(1.0, 0.1)
assert result.w == pytest.approx(1.0, 0.1)
def test_texture_occlusion(color_region):

View File

@ -47,8 +47,12 @@ def depth_region(request, graphics_pipe):
if buffer is None:
pytest.skip("Cannot make depth buffer")
if buffer.get_fb_properties().depth_bits != request.param:
pytest.skip("Could not make buffer with desired bit count")
got_depth_bits = buffer.get_fb_properties().depth_bits
if got_depth_bits < 24 and request.param == 16:
# We'll accept this - tinydisplay exclusively supports 20-bit depth.
pass
elif got_depth_bits != request.param:
pytest.skip("Could not make buffer with desired depth bit count")
yield buffer.make_display_region()

View File

@ -117,7 +117,7 @@ def run_glsl_compile_check(gsg, vert_path, frag_path, expect_fail=False):
assert shader is not None
if not gsg.supports_glsl:
expect_fail = True
pytest.skip("GLSL shaders not supported")
shader.prepare_now(gsg.prepared_objects, gsg)
assert shader.is_prepared(gsg.prepared_objects)
@ -633,16 +633,17 @@ def test_glsl_state_light_source(gsg):
assert(p3d_LightSource[0].shadowViewMatrix[0][1] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[0][2] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[0][3] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[1][0] == 0.5);
assert(p3d_LightSource[0].shadowViewMatrix[1][1] == 0.5);
assert(p3d_LightSource[0].shadowViewMatrix[1][2] > 1.0);
assert(p3d_LightSource[0].shadowViewMatrix[1][2] < 1.00002);
assert(p3d_LightSource[0].shadowViewMatrix[1][3] == 1);
assert(p3d_LightSource[0].shadowViewMatrix[2][0] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[2][1] > 0.2886);
assert(p3d_LightSource[0].shadowViewMatrix[2][1] < 0.2887);
assert(p3d_LightSource[0].shadowViewMatrix[2][2] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[2][3] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[1][0] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[1][1] > 0.2886);
assert(p3d_LightSource[0].shadowViewMatrix[1][1] < 0.2887);
assert(p3d_LightSource[0].shadowViewMatrix[1][2] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[1][3] == 0);
assert(p3d_LightSource[0].shadowViewMatrix[2][0] < -0.4999);
assert(p3d_LightSource[0].shadowViewMatrix[2][0] > -0.5001);
assert(p3d_LightSource[0].shadowViewMatrix[2][1] < -0.4999);
assert(p3d_LightSource[0].shadowViewMatrix[2][1] > -0.5001);
assert(p3d_LightSource[0].shadowViewMatrix[2][2] < -0.9999);
assert(p3d_LightSource[0].shadowViewMatrix[2][3] < -0.9999);
assert(p3d_LightSource[0].shadowViewMatrix[3][0] > -16.2736);
assert(p3d_LightSource[0].shadowViewMatrix[3][0] < -16.2734);
assert(p3d_LightSource[0].shadowViewMatrix[3][1] > -16.8510);

View File

@ -113,7 +113,7 @@ int main(int argc, char **argv) {
#ifdef ANDROID
// No caching on Android
PyRun_SimpleString("import sys; sys.argv.insert(1, '-o cache_dir=/dev/null')");
PyRun_SimpleString("import sys; sys.argv.insert(1, '-pno:cacheprovider')");
#endif
return Py_RunMain();