core/logic/smn_float.cpp
author David Anderson <dvander@alliedmods.net>
Mon Oct 26 23:59:59 2009 -0700 (2009-10-26)
changeset 2833 e7e7e77e679d
parent 2726 c96f3fab8211
child 4327 60e4042f2589
permissions -rw-r--r--
Added better random number generator (bug 3831, r=fyren).
dvander@2726
     1
/**
dvander@2833
     2
 * vim: set ts=4 sw=4 tw=99 :
dvander@2726
     3
 * =============================================================================
dvander@2726
     4
 * SourceMod
dvander@2726
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2726
     6
 * =============================================================================
dvander@2726
     7
 *
dvander@2726
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2726
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2726
    10
 * Free Software Foundation.
dvander@2726
    11
 * 
dvander@2726
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2726
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2726
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2726
    15
 * details.
dvander@2726
    16
 *
dvander@2726
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2726
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2726
    19
 *
dvander@2726
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2726
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2726
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2726
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2726
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2726
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2726
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2726
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2726
    28
 *
dvander@2726
    29
 * Version: $Id$
dvander@2726
    30
 */
dvander@2726
    31
dvander@2726
    32
#include <math.h>
dvander@2726
    33
#include <string.h>
dvander@2726
    34
#include <stdlib.h>
dvander@2726
    35
#include "common_logic.h"
dvander@2833
    36
#include "MersenneTwister.h"
dvander@2833
    37
#include <IPluginSys.h>
dvander@2726
    38
dvander@2726
    39
/****************************************
dvander@2726
    40
*                                       *
dvander@2726
    41
* FLOATING POINT NATIVE IMPLEMENTATIONS *
dvander@2726
    42
*                                       *
dvander@2726
    43
****************************************/
dvander@2726
    44
dvander@2726
    45
dvander@2726
    46
static cell_t sm_float(IPluginContext *pCtx, const cell_t *params)
dvander@2726
    47
{
dvander@2726
    48
	float val = static_cast<float>(params[1]);
dvander@2726
    49
dvander@2726
    50
	return sp_ftoc(val);
dvander@2726
    51
}
dvander@2726
    52
dvander@2726
    53
static cell_t sm_FloatAbs(IPluginContext *pCtx, const cell_t *params)
dvander@2726
    54
{
dvander@2726
    55
	float val = sp_ctof(params[1]);
dvander@2726
    56
	val = (val >= 0.0f) ? val : -val;
dvander@2726
    57
dvander@2726
    58
	return sp_ftoc(val);
dvander@2726
    59
}
dvander@2726
    60
dvander@2726
    61
static cell_t sm_FloatAdd(IPluginContext *pCtx, const cell_t *params)
dvander@2726
    62
{
dvander@2726
    63
	float val = sp_ctof(params[1]) + sp_ctof(params[2]);
dvander@2726
    64
dvander@2726
    65
	return sp_ftoc(val);
dvander@2726
    66
}
dvander@2726
    67
dvander@2726
    68
static cell_t sm_FloatSub(IPluginContext *pCtx, const cell_t *params)
dvander@2726
    69
{
dvander@2726
    70
	float val = sp_ctof(params[1]) - sp_ctof(params[2]);
dvander@2726
    71
dvander@2726
    72
	return sp_ftoc(val);
dvander@2726
    73
}
dvander@2726
    74
dvander@2726
    75
static cell_t sm_FloatMul(IPluginContext *pCtx, const cell_t *params)
dvander@2726
    76
{
dvander@2726
    77
	float val = sp_ctof(params[1]) * sp_ctof(params[2]);
dvander@2726
    78
dvander@2726
    79
	return sp_ftoc(val);
dvander@2726
    80
}
dvander@2726
    81
dvander@2726
    82
static cell_t sm_FloatDiv(IPluginContext *pCtx, const cell_t *params)
dvander@2726
    83
{
dvander@2726
    84
	float val = sp_ctof(params[1]) / sp_ctof(params[2]);
dvander@2726
    85
dvander@2726
    86
	return sp_ftoc(val);
dvander@2726
    87
}
dvander@2726
    88
dvander@2726
    89
static cell_t sm_FloatCompare(IPluginContext *pCtx, const cell_t *params)
dvander@2726
    90
{
dvander@2726
    91
	float val1 = sp_ctof(params[1]);
dvander@2726
    92
	float val2 = sp_ctof(params[2]);
dvander@2726
    93
dvander@2726
    94
	if (val1 > val2)
dvander@2726
    95
	{
dvander@2726
    96
		return 1;
dvander@2726
    97
	} else if (val1 < val2) {
dvander@2726
    98
		return -1;
dvander@2726
    99
	}
dvander@2726
   100
dvander@2726
   101
	return 0;
dvander@2726
   102
}
dvander@2726
   103
dvander@2726
   104
static cell_t sm_Logarithm(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   105
{
dvander@2726
   106
	float val = sp_ctof(params[1]);
dvander@2726
   107
	float base = sp_ctof(params[2]);
dvander@2726
   108
dvander@2726
   109
	if ((val <= 0.0f) || (base <= 0.0f))
dvander@2726
   110
	{
dvander@2726
   111
		return pCtx->ThrowNativeError("Cannot evaluate the logarithm of zero or a negative number (val:%f base:%f)", val, base);
dvander@2726
   112
	}
dvander@2726
   113
	if (base == 10.0f)
dvander@2726
   114
	{
dvander@2726
   115
		val = log10(val);
dvander@2726
   116
	} else {
dvander@2726
   117
		val = log(val) / log(base);
dvander@2726
   118
	}
dvander@2726
   119
dvander@2726
   120
	return sp_ftoc(val);
dvander@2726
   121
}
dvander@2726
   122
dvander@2726
   123
static cell_t sm_Exponential(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   124
{
dvander@2726
   125
	float val = sp_ctof(params[1]);
dvander@2726
   126
dvander@2726
   127
	return sp_ftoc(exp(val));
dvander@2726
   128
}
dvander@2726
   129
dvander@2726
   130
static cell_t sm_Pow(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   131
{
dvander@2726
   132
	float base = sp_ctof(params[1]);
dvander@2726
   133
	float exponent = sp_ctof(params[2]);
dvander@2726
   134
dvander@2726
   135
	return sp_ftoc(pow(base, exponent));
dvander@2726
   136
}
dvander@2726
   137
dvander@2726
   138
static cell_t sm_SquareRoot(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   139
{
dvander@2726
   140
	float val = sp_ctof(params[1]);
dvander@2726
   141
dvander@2726
   142
	if (val < 0.0f)
dvander@2726
   143
	{
dvander@2726
   144
		return pCtx->ThrowNativeError("Cannot evaluate the square root of a negative number (val:%f)", val);
dvander@2726
   145
	}
dvander@2726
   146
dvander@2726
   147
	return sp_ftoc(sqrt(val));
dvander@2726
   148
}
dvander@2726
   149
dvander@2726
   150
static cell_t sm_RoundToNearest(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   151
{
dvander@2726
   152
	float val = sp_ctof(params[1]);
dvander@2726
   153
	val = (float)floor(val + 0.5f);
dvander@2726
   154
dvander@2726
   155
	return static_cast<int>(val);
dvander@2726
   156
}
dvander@2726
   157
dvander@2726
   158
static cell_t sm_RoundToFloor(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   159
{
dvander@2726
   160
	float val = sp_ctof(params[1]);
dvander@2726
   161
	val = floor(val);
dvander@2726
   162
dvander@2726
   163
	return static_cast<int>(val);
dvander@2726
   164
}
dvander@2726
   165
dvander@2726
   166
static cell_t sm_RoundToCeil(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   167
{
dvander@2726
   168
	float val = sp_ctof(params[1]);
dvander@2726
   169
	val = ceil(val);
dvander@2726
   170
dvander@2726
   171
	return static_cast<int>(val);
dvander@2726
   172
}
dvander@2726
   173
dvander@2726
   174
static cell_t sm_RoundToZero(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   175
{
dvander@2726
   176
	float val = sp_ctof(params[1]);
dvander@2726
   177
	if (val >= 0.0f)
dvander@2726
   178
	{
dvander@2726
   179
		val = floor(val);
dvander@2726
   180
	} else {
dvander@2726
   181
		val = ceil(val);
dvander@2726
   182
	}
dvander@2726
   183
dvander@2726
   184
	return static_cast<int>(val);
dvander@2726
   185
}
dvander@2726
   186
dvander@2726
   187
static cell_t sm_FloatFraction(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   188
{
dvander@2726
   189
	float val = sp_ctof(params[1]);
dvander@2726
   190
	val = val - floor(val);
dvander@2726
   191
dvander@2726
   192
	return sp_ftoc(val);
dvander@2726
   193
}
dvander@2726
   194
dvander@2726
   195
static cell_t sm_Sine(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   196
{
dvander@2726
   197
	float val = sp_ctof(params[1]);
dvander@2726
   198
	val = sin(val);
dvander@2726
   199
dvander@2726
   200
	return sp_ftoc(val);
dvander@2726
   201
}
dvander@2726
   202
dvander@2726
   203
static cell_t sm_Cosine(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   204
{
dvander@2726
   205
	float val = sp_ctof(params[1]);
dvander@2726
   206
	val = cos(val);
dvander@2726
   207
dvander@2726
   208
	return sp_ftoc(val);
dvander@2726
   209
}
dvander@2726
   210
dvander@2726
   211
static cell_t sm_Tangent(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   212
{
dvander@2726
   213
	float val = sp_ctof(params[1]);
dvander@2726
   214
	val = tan(val);
dvander@2726
   215
dvander@2726
   216
	return sp_ftoc(val);
dvander@2726
   217
}
dvander@2726
   218
dvander@2726
   219
static cell_t sm_ArcSine(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   220
{
dvander@2726
   221
	float val = sp_ctof(params[1]);
dvander@2726
   222
	val = asin(val);
dvander@2726
   223
dvander@2726
   224
	return sp_ftoc(val);
dvander@2726
   225
}
dvander@2726
   226
dvander@2726
   227
static cell_t sm_ArcCosine(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   228
{
dvander@2726
   229
	float val = sp_ctof(params[1]);
dvander@2726
   230
	val = acos(val);
dvander@2726
   231
dvander@2726
   232
	return sp_ftoc(val);
dvander@2726
   233
}
dvander@2726
   234
dvander@2726
   235
static cell_t sm_ArcTangent(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   236
{
dvander@2726
   237
	float val = sp_ctof(params[1]);
dvander@2726
   238
	val = atan(val);
dvander@2726
   239
dvander@2726
   240
	return sp_ftoc(val);
dvander@2726
   241
}
dvander@2726
   242
dvander@2726
   243
static cell_t sm_ArcTangent2(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   244
{
dvander@2726
   245
	float val1 = sp_ctof(params[1]);
dvander@2726
   246
	float val2 = sp_ctof(params[2]);
dvander@2726
   247
	val1 = atan2(val1, val2);
dvander@2726
   248
dvander@2726
   249
	return sp_ftoc(val1);
dvander@2726
   250
}
dvander@2726
   251
dvander@2726
   252
#if 0
dvander@2726
   253
static cell_t sm_FloatRound(IPluginContext *pCtx, const cell_t *params)
dvander@2726
   254
{
dvander@2726
   255
	float val = sp_ctof(params[1]);
dvander@2726
   256
dvander@2726
   257
	switch (params[2])
dvander@2726
   258
	{
dvander@2726
   259
	case 1:
dvander@2726
   260
		{
dvander@2726
   261
			val = floor(val);
dvander@2726
   262
			break;
dvander@2726
   263
		}
dvander@2726
   264
	case 2:
dvander@2726
   265
		{
dvander@2726
   266
			val = ceil(val);
dvander@2726
   267
			break;
dvander@2726
   268
		}
dvander@2726
   269
	case 3:
dvander@2726
   270
		{
dvander@2726
   271
			if (val >= 0.0f)
dvander@2726
   272
			{
dvander@2726
   273
				val = floor(val);
dvander@2726
   274
			} else {
dvander@2726
   275
				val = ceil(val);
dvander@2726
   276
			}
dvander@2726
   277
			break;
dvander@2726
   278
		}
dvander@2726
   279
	default:
dvander@2726
   280
		{
dvander@2726
   281
			val = (float)floor(val + 0.5f);
dvander@2726
   282
			break;
dvander@2726
   283
		}
dvander@2726
   284
	}
dvander@2726
   285
dvander@2726
   286
	return static_cast<int>(val);
dvander@2726
   287
}
dvander@2726
   288
#endif
dvander@2726
   289
dvander@2833
   290
class RandomHelpers :
dvander@2833
   291
	public SMGlobalClass,
dvander@2833
   292
	public IPluginsListener
dvander@2833
   293
{
dvander@2833
   294
public:
dvander@2833
   295
	void OnSourceModAllInitialized()
dvander@2833
   296
	{
dvander@2833
   297
		pluginsys->AddPluginsListener(this);
dvander@2833
   298
	}
dvander@2833
   299
dvander@2833
   300
	void OnSourceModShutdown()
dvander@2833
   301
	{
dvander@2833
   302
		pluginsys->RemovePluginsListener(this);
dvander@2833
   303
	}
dvander@2833
   304
dvander@2833
   305
	void OnPluginDestroyed(IPlugin *plugin)
dvander@2833
   306
	{
dvander@2833
   307
		MTRand *mtrand;
dvander@2833
   308
		if (plugin->GetProperty("core.logic.mtrand", (void**)&mtrand, true))
dvander@2833
   309
		{
dvander@2833
   310
			delete mtrand;
dvander@2833
   311
		}
dvander@2833
   312
	}
dvander@2833
   313
	
dvander@2833
   314
	MTRand *RandObjForPlugin(IPluginContext *ctx)
dvander@2833
   315
	{
dvander@2833
   316
		IPlugin *plugin = pluginsys->FindPluginByContext(ctx->GetContext());
dvander@2833
   317
		MTRand *mtrand;	
dvander@2833
   318
		if (!plugin->GetProperty("core.logic.mtrand", (void**)&mtrand))
dvander@2833
   319
		{
dvander@2833
   320
			mtrand = new MTRand();
dvander@2833
   321
			plugin->SetProperty("core.logic.mtrand", mtrand);
dvander@2833
   322
		}
dvander@2833
   323
		return mtrand;
dvander@2833
   324
	}
dvander@2833
   325
} s_RandHelpers;
dvander@2833
   326
dvander@2833
   327
static cell_t GetURandomInt(IPluginContext *ctx, const cell_t *params)
dvander@2833
   328
{
dvander@2833
   329
	MTRand *randobj = s_RandHelpers.RandObjForPlugin(ctx);
dvander@2833
   330
	/* Note the sign bit must be stripped off because cell_t is signed,
dvander@2833
   331
	 * and this guarantees a range of [0,max_int]
dvander@2833
   332
	 */
dvander@2833
   333
	return randobj->randInt() & 0x7FFFFFFF;
dvander@2833
   334
}
dvander@2833
   335
dvander@2833
   336
static cell_t GetURandomFloat(IPluginContext *ctx, const cell_t *params)
dvander@2833
   337
{
dvander@2833
   338
	MTRand *randobj = s_RandHelpers.RandObjForPlugin(ctx);
dvander@2833
   339
	return sp_ftoc((float)randobj->rand());
dvander@2833
   340
}
dvander@2833
   341
dvander@2833
   342
static cell_t SetURandomSeed(IPluginContext *ctx, const cell_t *params)
dvander@2833
   343
{
dvander@2833
   344
	MTRand *randobj = s_RandHelpers.RandObjForPlugin(ctx);
dvander@2833
   345
	cell_t *addr;
dvander@2833
   346
	ctx->LocalToPhysAddr(params[1], &addr);
dvander@2833
   347
	/* We're 32-bit only. */
dvander@2833
   348
	randobj->seed((MTRand::uint32*)addr, params[2]);
dvander@2833
   349
	return 1;
dvander@2833
   350
}
dvander@2833
   351
dvander@2726
   352
REGISTER_NATIVES(floatnatives)
dvander@2726
   353
{
dvander@2726
   354
	{"float",			sm_float},
dvander@2726
   355
	{"FloatMul",		sm_FloatMul},
dvander@2726
   356
	{"FloatDiv",		sm_FloatDiv},
dvander@2726
   357
	{"FloatAdd",		sm_FloatAdd},
dvander@2726
   358
	{"FloatSub",		sm_FloatSub},
dvander@2726
   359
	{"FloatFraction",	sm_FloatFraction},
dvander@2726
   360
	{"RoundToZero",		sm_RoundToZero},
dvander@2726
   361
	{"RoundToCeil",		sm_RoundToCeil},
dvander@2726
   362
	{"RoundToFloor",	sm_RoundToFloor},
dvander@2726
   363
	{"RoundToNearest",	sm_RoundToNearest},
dvander@2726
   364
	{"FloatCompare",	sm_FloatCompare},
dvander@2726
   365
	{"SquareRoot",		sm_SquareRoot},
dvander@2726
   366
	{"Pow",				sm_Pow},
dvander@2726
   367
	{"Exponential",		sm_Exponential},
dvander@2726
   368
	{"Logarithm",		sm_Logarithm},
dvander@2726
   369
	{"Sine",			sm_Sine},
dvander@2726
   370
	{"Cosine",			sm_Cosine},
dvander@2726
   371
	{"Tangent",			sm_Tangent},
dvander@2726
   372
	{"FloatAbs",		sm_FloatAbs},
dvander@2726
   373
	{"ArcTangent",		sm_ArcTangent},
dvander@2726
   374
	{"ArcCosine",		sm_ArcCosine},
dvander@2726
   375
	{"ArcSine",			sm_ArcSine},
dvander@2726
   376
	{"ArcTangent2",		sm_ArcTangent2},
dvander@2833
   377
	{"GetURandomInt",	GetURandomInt},
dvander@2833
   378
	{"GetURandomFloat",	GetURandomFloat},
dvander@2833
   379
	{"SetURandomSeed",	SetURandomSeed},
dvander@2726
   380
	{NULL,				NULL}
dvander@2726
   381
};
dvander@2833
   382