Пример #1
0
void WriteFile(const CImage& img, const char* filename)
{
    // Determine the file extension
    const char *dot = strrchr(filename, '.');
    if (strcasecmp(dot, ".tga") == 0 || strcasecmp(dot, ".tga") == 0) {
        if (img.PixType() == typeid(uchar))
            WriteFileTGA(*(CByteImage *) &img, filename);
        else if(img.PixType() == typeid(float)) {
            CByteImage tmp(img.Shape());
            TypeConvert(*(CFloatImage *) &img, tmp);
            WriteFileTGA(tmp, filename);
        } else {
            throw CError("Filetype not supported");
        }
    } else if (strcasecmp(dot, ".jpg") == 0 || strcasecmp(dot, ".jpeg") == 0) {
        if (img.PixType() == typeid(uchar))
            WriteFileJPEG(*(CByteImage *) &img, filename, 90);
        else if(img.PixType() == typeid(float)) {
            CByteImage tmp(img.Shape());
            TypeConvert(*(CFloatImage *) &img, tmp);
            WriteFileJPEG(tmp, filename, 90);
        } else {
            throw CError("Filetype not supported");
        }
    } 
    else
        throw CError("WriteFile(%s): file type not supported", filename);
}
Пример #2
0
void ReadFile(CImage& img, const char* filename)
{
    // Determine the file extension
    const char *dot = strrchr(filename, '.');
    if (strcasecmp(dot, ".tga") == 0 || strcasecmp(dot, ".tga") == 0) {
        if ((&img.PixType()) == 0)
            img.ReAllocate(CShape(), typeid(uchar), sizeof(uchar), true);
        if (img.PixType() == typeid(uchar))
            ReadFileTGA(*(CByteImage *) &img, filename);
        else {
            CByteImage imgAux;
            ReadFileTGA(imgAux, filename);

            if(img.PixType() == typeid(float)) TypeConvert(imgAux, *(CFloatImage*) &img);
            else
                throw CError("Cannot load image into img with this type of buffer");
        }
    } else if (strcasecmp(dot, ".jpg") == 0 || strcasecmp(dot, ".jpeg") == 0) {
        if ((&img.PixType()) == 0)
            img.ReAllocate(CShape(), typeid(uchar), sizeof(uchar), true);
        if (img.PixType() == typeid(uchar))
            ReadFileJPEG(*(CByteImage *) &img, filename);
        else {
            CByteImage imgAux;
            ReadFileJPEG(imgAux, filename);

            if(img.PixType() == typeid(float)) TypeConvert(imgAux, *(CFloatImage*) &img);
            else
                throw CError("Cannot load image into img with this type of buffer");
        }

    } else
        throw CError("ReadFile(%s): file type not supported", filename);
}
Пример #3
0
CByteImage 
TinyImageFeatureExtractor::render(const Feature& f) const
{
	CByteImage viz;
	TypeConvert(f, viz);
	return viz;
}
Пример #4
0
Feature 
TinyImageFeatureExtractor::operator()(const CByteImage& img_) const
{
	CFloatImage tinyImg(_targetW, _targetH, 1);

	/******** BEGIN TODO ********/
	// Compute tiny image feature, output should be _targetW by _targetH a grayscale image
	// Steps are:
	// 1) Convert image to grayscale (see convertRGB2GrayImage in Utils.h)
	// 2) Resize image to be _targetW by _targetH
	// 
	// Useful functions:
	// convertRGB2GrayImage, TypeConvert, WarpGlobal

	
	CByteImage gray;
	CFloatImage grayF;
	convertRGB2GrayImage(img_, gray);
	TypeConvert(gray, grayF);
	CTransform3x3 scale = CTransform3x3::Scale(1.* img_.Shape().width / _targetW,
											   1.* img_.Shape().height/ _targetH);
	
	WarpGlobal(grayF, tinyImg, scale, eWarpInterpLinear);

	 

	/******** END TODO ********/

	return tinyImg;
}
Пример #5
0
CByteImage 
HOGFeatureExtractor::render(const Feature& f) const
{
	CShape cellShape = _oriMarkers[0].Shape();
	CFloatImage hogImgF(CShape(cellShape.width * f.Shape().width, cellShape.height * f.Shape().height, 1));
	hogImgF.ClearPixels();

	float minBinValue, maxBinValue;
	f.getRangeOfValues(minBinValue, maxBinValue);

	// For every cell in the HOG
	for(int hi = 0; hi < f.Shape().height; hi++) {
		for(int hj = 0; hj < f.Shape().width; hj++) {

			// Now _oriMarkers, multiplying contribution by bin level
			for(int hc = 0; hc < _nAngularBins; hc++) {
				float v = f.Pixel(hj, hi, hc) / maxBinValue;
				for(int ci = 0; ci < cellShape.height; ci++) {
					float* cellIt = (float*) _oriMarkers[hc].PixelAddress(0, ci, 0);
					float* hogIt = (float*) hogImgF.PixelAddress(hj * cellShape.height, hi * cellShape.height + ci, 0);

					for(int cj = 0; cj < cellShape.width; cj++, hogIt++, cellIt++) {
						(*hogIt) += v * (*cellIt);
					}
				}
			}
		
		}
	}

	CByteImage hogImg;
	TypeConvert(hogImgF, hogImg);
	return hogImg;
}
Пример #6
0
// --------------------------------------------------------------------------------------------------------------------
// ObjectBinaryOp():  Registered to perform all operations involving objectc only values
// --------------------------------------------------------------------------------------------------------------------
bool8 ObjectBinaryOp(CScriptContext* script_context, eOpCode op, eVarType& result_type, void* result_addr,
                     eVarType val0_type, void* val0, eVarType val1_type, void* val1)
{
    // -- sanity check
    if (!result_addr || !val0 || !val1)
        return (false);

    // -- ensure the types are converted to Type_object
    void* val0addr = TypeConvert(script_context, val0_type, val0, TYPE_object);
    void* val1addr = TypeConvert(script_context, val1_type, val1, TYPE_object);
    if (!val0addr || !val1addr)
        return (false);

    uint32 v0 = *(uint32*)val0addr;
    uint32 v1 = *(uint32*)val1addr;
    int32* result = (int32*)result_addr;
    result_type = TYPE_int;

    // -- perform the operation - note, both object handle values
    // -- can differ, but if neither object actually exists, they are equal
    switch (op)
    {
    case OP_CompareEqual:
    {
        CObjectEntry* oe0 = script_context->FindObjectEntry(v0);
        CObjectEntry* oe1 = script_context->FindObjectEntry(v1);
        *result = (oe0 == oe1) ? 0 : 1;
        return (true);
    }

    case OP_CompareNotEqual:
    {
        CObjectEntry* oe0 = script_context->FindObjectEntry(v0);
        CObjectEntry* oe1 = script_context->FindObjectEntry(v1);
        *result = (oe0 != oe1) ? 0 : 1;
        return (true);
    }
    }

    // -- fail
    return (false);
}
Пример #7
0
// --------------------------------------------------------------------------------------------------------------------
// StringBinaryOp():  Registered to perform all numerical operations using a string that represents a float or an int
// --------------------------------------------------------------------------------------------------------------------
bool8 StringBinaryOp(CScriptContext* script_context, eOpCode op, eVarType& result_type, void* result_addr,
                     eVarType val0_type, void* val0, eVarType val1_type, void* val1)
{
    // -- sanity check
    if (!script_context || !result_addr || !val0 || !val1)
        return (false);

    // -- if we cannot convert the string to a float non-zero value, convert it as an integer
    bool val0_float = true;
    void* val0addr = TypeConvert(script_context, val0_type, val0, TYPE_float);
    if (!val0addr || *(float32*)(val0addr) == 0.0f)
    {
        val0addr = TypeConvert(script_context, val0_type, val0, TYPE_int);
        val0_float = false;
    }

    bool val1_float = true;
    void* val1addr = TypeConvert(script_context, val1_type, val1, TYPE_float);
    if (!val1addr || *(float32*)(val1addr) == 0.0f)
    {
        val1addr = TypeConvert(script_context, val1_type, val1, TYPE_int);
        val1_float = false;
    }

    // -- ensure we at least got two numerical types
    if (!val0addr || !val1addr)
        return (false);

    // -- if either is a float, perform a float operation
    if (val0_float || val1_float)
    {
        return (FloatBinaryOp(script_context, op, result_type, result_addr,
                              val0_float ? TYPE_float : TYPE_int, val0addr,
                              val1_float ? TYPE_float : TYPE_int, val1addr));
    }

    // -- else perform an integer op
    else
    {
        return (IntegerBinaryOp(script_context, op, result_type, result_addr, TYPE_int, val0addr, TYPE_int, val1addr));
    }
}
Пример #8
0
// --------------------------------------------------------------------------------------------------------------------
// BooleanBinaryOp():  Registered to perform all boolean operations using type bool
// --------------------------------------------------------------------------------------------------------------------
bool8 BooleanBinaryOp(CScriptContext* script_context, eOpCode op, eVarType& result_type, void* result_addr,
                      eVarType val0_type, void* val0, eVarType val1_type, void* val1)
{
    // -- sanity check
    if (!script_context || !result_addr || !val0 || !val1)
        return (false);

    // -- ensure the types are converted to vector3f
    void* val0addr = TypeConvert(script_context, val0_type, val0, TYPE_bool);
    void* val1addr = TypeConvert(script_context, val1_type, val1, TYPE_bool);
    if (!val0addr || !val1addr)
        return (false);

    bool8* v0 = (bool8*)val0addr;
    bool8* v1 = (bool8*)val1addr;
    int32* result = (int32*)result_addr;
    result_type = TYPE_int;

    // -- the result for boolean operators is numerical... 1 == true, 0 == false
    // -- the result for comparison operators is numerical... (-1, 0, 1) for lt, eq, gt
    switch (op)
    {
    case OP_BooleanAnd:
        *result = *v0 && *v1 ? 1 : 0;
        return (true);

    case OP_BooleanOr:
        *result = *v0 || *v1 ? 1 : 0;
        return (true);

    case OP_CompareEqual:
        *result = *v0 == *v1 ? 0 : 1;
        return (true);

    case OP_CompareNotEqual:
        *result = *v0 != *v1 ? 0 : 1;
        return (true);
    }

    // -- fail
    return (false);
}
NS_METHOD CNSAdapter_SecureJNIEnv::NewArray( /*[in]*/ jni_type element_type,
					     /*[in]*/  jsize len,
					     /*[out]*/ jarray* result)
{
    if (m_pSecureEnv == NULL)
	return NS_ERROR_NULL_POINTER;
	
    jd_jni_type jd_element_type = TypeConvert(element_type);
	
    return m_pSecureEnv->NewArray(jd_element_type, len, result);
}
NS_METHOD CNSAdapter_SecureJNIEnv::ReleaseArrayElements( /*[in]*/ jni_type element_type,
							  /*[in]*/ jarray array,
							  /*[in]*/ void *elems,
							  /*[in]*/ jint mode)
{
    if (m_pSecureEnv == NULL)
	return NS_ERROR_NULL_POINTER;

    jd_jni_type jd_element_type = TypeConvert(element_type);
    return m_pSecureEnv->ReleaseArrayElements(jd_element_type, array, elems, mode);
}
NS_METHOD CNSAdapter_SecureJNIEnv::GetArrayElements( /*[in]*/  jni_type element_type,
						      /*[in]*/  jarray array,
						      /*[in]*/  jboolean *isCopy,
						      /*[out]*/ void* result)
{
    if (m_pSecureEnv == NULL)
	return NS_ERROR_NULL_POINTER;

    jd_jni_type jd_element_type = TypeConvert(element_type);
    return m_pSecureEnv->GetArrayElements(jd_element_type, array, isCopy, result);
}
NS_METHOD CNSAdapter_SecureJNIEnv::SetArrayRegion( /*[in]*/  jni_type element_type,
						    /*[in]*/  jarray array,
						    /*[in]*/  jsize start,
						    /*[in]*/  jsize len,
						    /*[in]*/  void* buf)
{
    if (m_pSecureEnv == NULL)
	return NS_ERROR_NULL_POINTER;
	 
    jd_jni_type jd_element_type = TypeConvert(element_type);
    return m_pSecureEnv->SetArrayRegion(jd_element_type, array, start, len, buf);
}
Пример #13
0
void WriteFileTGA(CImage img, const char* filename)
{
    // Only 1, 3, or 4 bands supported
    CShape sh = img.Shape();
    int nBands = sh.nBands;
    if (nBands != 1 && nBands != 3 && nBands != 4)
        throw CError("WriteFileTGA(%s): can only write 1, 3, or 4 bands", filename);

    // Only unsigned_8 supported directly
#if 0   // broken for now
    if (img.PixType() != unsigned_8)
    {
        CImage u8img(sh, unsigned_8);
        TypeConvert(img, u8img);
        img = u8img;
    }
#endif

    // Fill in the header structure
    CTargaHead h;
    memset(&h, 0, sizeof(h));
    h.imageType = (nBands == 1) ? TargaRawBW : TargaRawRGB;
        // TODO:  is TargaRawBW the right thing, or only binary?
    h.width     = sh.width;
    h.height    = sh.height;
    h.pixelSize = 8 * nBands;
    bool reverseRows = false;   // TODO: when is this true?

    // Open the file and write the header
    FILE *stream = fopen(filename, "wb");
    if (stream == 0)
        throw CError("WriteFileTGA: could not open %s", filename);
    if (fwrite(&h, sizeof(CTargaHead), 1, stream) != 1)
	    throw CError("WriteFileTGA(%s): file is too short", filename);

    // Write out the rows
    for (int y = 0; y < sh.height; y++)
    {
        int yr = reverseRows ? sh.height-1-y : y;
        char* ptr = (char *) img.PixelAddress(0, yr, 0);
        int n = sh.width*sh.nBands;
    	if (fwrite(ptr, sizeof(uchar), n, stream) != n)
    	    throw CError("WriteFileTGA(%s): file is too short", filename);
    }

    if (fclose(stream))
        throw CError("WriteFileTGA(%s): error closing file", filename);
}
/**
 * Set a static field on Java object in LiveConnect.
 *
 * @param type       -- Return type
 * @param clazz      -- Class object.
 * @param fieldID    -- field id
 * @param val        -- field value to set
 * @param ctx        -- security context
 */
NS_METHOD CNSAdapter_SecureJNIEnv::SetStaticField( /*[in]*/ jni_type field_type,
						    /*[in]*/ jclass clazz,
						    /*[in]*/ jfieldID fieldID,
						    /*[in]*/ jvalue val,
						    /*[in]*/ nsISecurityContext* ctx )
{
    if (m_pSecureEnv == NULL)
	return NS_ERROR_NULL_POINTER;
    
    JDSmartPtr<ISecurityContext> spSecurityContext = new CNSAdapter_SecurityContextPeer(ctx);

    if (spSecurityContext == NULL)
	return NS_ERROR_OUT_OF_MEMORY;

    jd_jni_type jd_field_type = TypeConvert(field_type);
    return m_pSecureEnv->SetStaticField(jd_field_type, clazz, fieldID, val, spSecurityContext);
}
/**
 * Get a field on Java object in LiveConnect.
 *
 * @param type       -- Return type
 * @param obj        -- Java object.
 * @param fieldID    -- field id
 * @param result     -- return field value
 * @param ctx        -- security context
 */
NS_METHOD CNSAdapter_SecureJNIEnv::GetField( /*[in]*/  jni_type field_type,
					      /*[in]*/  jobject obj,
					      /*[in]*/  jfieldID fieldID,
					      /*[out]*/ jvalue* result,
					      /*[in]*/  nsISecurityContext* ctx)
{
    if (m_pSecureEnv == NULL)
	return NS_ERROR_NULL_POINTER;

    JDSmartPtr<ISecurityContext> spSecurityContext = new CNSAdapter_SecurityContextPeer(ctx);

    if (spSecurityContext == NULL)
	return NS_ERROR_OUT_OF_MEMORY;

    jd_jni_type jd_field_type = TypeConvert(field_type);

    return m_pSecureEnv->GetField(jd_field_type, obj, fieldID, result, spSecurityContext);
}
/**
 * Invoke static method on Java object in LiveConnect.
 *
 * @param type       -- Return type
 * @param clazz      -- Class object.
 * @param methodID   -- method id
 * @param args       -- arguments for invoking the constructor.
 * @param result     -- return result of invocation.
 * @param ctx        -- security context
 */
NS_METHOD CNSAdapter_SecureJNIEnv::CallStaticMethod( /*[in]*/  jni_type ret_type,
						      /*[in]*/  jclass clazz,
						      /*[in]*/  jmethodID methodID,
						      /*[in]*/  jvalue *args,
						      /*[out]*/ jvalue* result,
						      /*[in]*/  nsISecurityContext* ctx )
{
    if (m_pSecureEnv == NULL)
	return NS_ERROR_NULL_POINTER;

    JDSmartPtr<ISecurityContext> spSecurityContext = new CNSAdapter_SecurityContextPeer(ctx);

    if (spSecurityContext == NULL)
	return NS_ERROR_OUT_OF_MEMORY;

    jd_jni_type jd_ret_type = TypeConvert(ret_type);
    return m_pSecureEnv->CallStaticMethod(jd_ret_type, clazz, methodID, args, result, spSecurityContext);
}
Пример #17
0
Feature 
HOGFeatureExtractor::operator()(const CByteImage& img_) const
{
	/******** BEGIN TODO ********/
	// Compute the Histogram of Oriented Gradients feature
	// Steps are:
	// 1) Compute gradients in x and y directions. We provide the 
	//    derivative kernel proposed in the paper in _kernelDx and
	//    _kernelDy.
	// 2) Compute gradient magnitude and orientation
	// 3) Add contribution each pixel to HOG cells whose
	//    support overlaps with pixel. Each cell has a support of size
	//    _cellSize and each histogram has _nAngularBins.
	// 4) Normalize HOG for each cell. One simple strategy that is
	//    is also used in the SIFT descriptor is to first threshold
	//    the bin values so that no bin value is larger than some
	//    threshold (we leave it up to you do find this value) and
	//    then re-normalize the histogram so that it has norm 1. A more 
	//    elaborate normalization scheme is proposed in Dalal & Triggs
	//    paper but we leave that as extra credit.
	// 
	// Useful functions:
	// convertRGB2GrayImage, TypeConvert, WarpGlobal, Convolve

	
	int xCells = ceil(1.*img_.Shape().width  / _cellSize);
	int yCells = ceil(1.*img_.Shape().height / _cellSize);

	CFloatImage HOGHist(xCells, yCells, _nAngularBins);
	HOGHist.ClearPixels();

	CByteImage gray(img_.Shape());
	CFloatImage grayF(img_.Shape().width, img_.Shape().height, 1);

	convertRGB2GrayImage(img_, gray);
	TypeConvert(gray, grayF);

	CFloatImage diffX( img_.Shape()), diffY( img_.Shape());

	Convolve(grayF, diffX, _kernelDx);
	Convolve(grayF, diffY, _kernelDy);
	
	CFloatImage grad(grayF.Shape()), grad2(grayF.Shape());
	CFloatImage angl(grayF.Shape()), angl2(grayF.Shape());
	
	for (int y = 0; y <grayF.Shape().height; y++){
		for (int x = 0; x<grayF.Shape().width; x++) {
			grad2.Pixel(x,y,0) = (diffX.Pixel(x,y,0) * diffX.Pixel(x,y,0) +
							     diffY.Pixel(x,y,0) * diffY.Pixel(x,y,0));
			angl2.Pixel(x,y,0) = atan(diffY.Pixel(x,y,0) / abs(diffY.Pixel(x,y,0)));
		}
	}

	// Bilinear Filter
	ConvolveSeparable(grad2, grad, ConvolveKernel_121,ConvolveKernel_121,1);
	ConvolveSeparable(angl2, angl, ConvolveKernel_121,ConvolveKernel_121,1);
	//WriteFile(diffX, "angle.tga");
	//WriteFile(diffY, "angleG.tga");

	for (int y = 0; y <grayF.Shape().height; y++){
		for (int x = 0; x<grayF.Shape().width; x++) {
			// Fit in the bins
			int a = angl.Pixel(x,y,0) / 3.14 * (_nAngularBins) + _nAngularBins/2;		
			// Histogram
			HOGHist.Pixel(floor(1.*x / _cellSize),
						  floor(1.*y / _cellSize),
						  a) += grad.Pixel(x,y,0);
		}
	}
	
	// Normalization 
	float threshold = 0.7;
	for (int y = 0; y < yCells; y++){
		for (int x = 0; x < xCells; x++){
			float total = 0;
			for (int a = 0; a < _nAngularBins; a++) {
				if (HOGHist.Pixel(x,y,a) > threshold)
					HOGHist.Pixel(x,y,a) = threshold;
				// Sum for normalization
				total += HOGHist.Pixel(x,y,a);
			}
			for (int a = 0;a< _nAngularBins; a++) {
				HOGHist.Pixel(x,y,a) /= total;
				
			}
		}
	}
	
	return HOGHist;
	/******** END TODO ********/

}
Пример #18
0
// --------------------------------------------------------------------------------------------------------------------
// IntegerBinaryOp():  Registered to perform all numerical operations involving integer only values
// --------------------------------------------------------------------------------------------------------------------
bool8 IntegerBinaryOp(CScriptContext* script_context, eOpCode op, eVarType& result_type, void* result_addr,
                      eVarType val0_type, void* val0, eVarType val1_type, void* val1)
{
    // -- sanity check
    if (!result_addr || !val0 || !val1)
        return (false);

    // -- ensure the types are converted to vector3f
    void* val0addr = TypeConvert(script_context, val0_type, val0, TYPE_int);
    void* val1addr = TypeConvert(script_context, val1_type, val1, TYPE_int);
    if (!val0addr || !val1addr)
        return (false);

    int32* v0 = (int32*)val0addr;
    int32* v1 = (int32*)val1addr;
    int32* result = (int32*)result_addr;
    result_type = TYPE_int;

    // -- perform the operation
    switch (op)
    {
    case OP_Add:
        *result = *v0 + *v1;
        return (true);

    case OP_Sub:
        *result = *v0 - *v1;
        return (true);

    case OP_Mult:
        *result = *v0 * *v1;
        return (true);

    case OP_Div:
        if (*v1 == 0)
        {
            ScriptAssert_(script_context, false, "<internal>", -1, "Error - OP_Mod division by 0\n");
            *result = 0;
            return (false);
        }
        *result = *v0 / *v1;
        return (true);

    case OP_Mod:
        if (*v1 == 0)
        {
            ScriptAssert_(script_context, false, "<internal>", -1, "Error - OP_Mod division by 0\n");
            *result = 0;
            return (false);
        }

        *result = *v0 - ((*v0 / *v1) * *v1);
        return (true);

    // -- comparison operations (push a -1, 0, 1) for less than, equal, greater than
    case OP_CompareEqual:
    case OP_CompareNotEqual:
    case OP_CompareLess:
    case OP_CompareLessEqual:
    case OP_CompareGreater:
    case OP_CompareGreaterEqual:
        *result = *v0 - *v1;
        return (true);

    // -- Bit operations
    case OP_BitLeftShift:
        *result = *v0 << *v1;
        return (true);

    case OP_BitRightShift:
        *result = *v0 >> *v1;
        return (true);

    case OP_BitAnd:
        *result = *v0 & *v1;
        return (true);

    case OP_BitOr:
        *result = *v0 | *v1;
        return (true);

    case OP_BitXor:
        *result = *v0 ^ *v1;
        return (true);

    default:
        return false;
    }

    // -- fail
    return (false);
}
Пример #19
0
// --------------------------------------------------------------------------------------------------------------------
// FloatBinaryOp():  Registered to perform all numerical operations involving a float, except vector3f scaling
// --------------------------------------------------------------------------------------------------------------------
bool8 FloatBinaryOp(CScriptContext* script_context, eOpCode op, eVarType& result_type, void* result_addr,
                    eVarType val0_type, void* val0, eVarType val1_type, void* val1)
{
    // -- sanity check
    if (!script_context || !result_addr || !val0 || !val1)
        return (false);

    // -- ensure the types are converted to vector3f
    void* val0addr = TypeConvert(script_context, val0_type, val0, TYPE_float);
    void* val1addr = TypeConvert(script_context, val1_type, val1, TYPE_float);
    if (!val0addr || !val1addr)
        return (false);

    float32* v0 = (float32*)val0addr;
    float32* v1 = (float32*)val1addr;
    float32* result = (float32*)result_addr;
    result_type = TYPE_float;

    // -- perform the operation
    switch (op)
    {
    case OP_Add:
        *result = *v0 + *v1;
        return (true);

    case OP_Sub:
        *result = *v0 - *v1;
        return (true);

    case OP_Mult:
        *result = *v0 * *v1;
        return (true);

    case OP_Div:
        if (*v1 == 0.0f)
        {
            ScriptAssert_(script_context, false, "<internal>", -1, "Error - OP_Mod division by 0.0f\n");
            *result = 0.0f;
            return (false);
        }
        *result = *v0 / *v1;
        return (true);

    case OP_Mod:
        if (*v1 == 0.0f)
        {
            ScriptAssert_(script_context, false, "<internal>", -1, "Error - OP_Mod division by 0.0f\n");
            *result = 0.0f;
            return (false);
        }

        *result = *v0 - (float32)((int32)(*v0 / *v1) * *v1);
        return (true);

    // -- comparison operations (push a -1, 0, 1) for less than, equal, greater than
    case OP_CompareEqual:
    case OP_CompareNotEqual:
    case OP_CompareLess:
    case OP_CompareLessEqual:
    case OP_CompareGreater:
    case OP_CompareGreaterEqual:
        *result = (*v0 - *v1) < 0.0f ? -1.0f : (*v0 - *v1) == 0.0f ? 0.0f : 1.0f;
        return (true);

    default:
        return false;
    }

    // -- fail
    return (false);
}